From 7ba0088d6898d7fd2873f736f1f556673a8be855 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 27 Jun 2002 20:21:38 +0000 Subject: [PATCH] network_cmds-115.tar.gz --- Makefile | 36 +- PB.project | 21 +- alias/Makefile | 2 +- alias/PB.project | 2 + alias/alias.c | 616 ++- alias/alias.h | 104 +- alias/alias_cuseeme.c | 30 +- alias/alias_db.c | 1019 +++-- alias/alias_ftp.c | 560 ++- alias/alias_irc.c | 66 +- alias/alias_local.h | 203 +- alias/alias_nbt.c | 80 +- alias/alias_pptp.c | 390 ++ alias/alias_proxy.c | 61 +- alias/alias_smedia.c | 454 ++ alias/alias_util.c | 60 +- bootparams/bpwhoami.tproj/Makefile | 2 +- bootparams/bpwhoami.tproj/Makefile.postamble | 3 + bootparams/bpwhoami.tproj/bpwhoami.1 | 31 + bootparams/bpwhoami.tproj/bpwhoami.c | 93 +- eaytest.tproj/Makefile | 51 + eaytest.tproj/Makefile.postamble | 100 + eaytest.tproj/Makefile.preamble | 146 + eaytest.tproj/PB.project | 44 + eaytest.tproj/crypto_openssl.c | 2295 ++++++++++ eaytest.tproj/crypto_openssl.h | 189 + eaytest.tproj/eaytest.c | 940 ++++ eaytest.tproj/misc.c | 167 + eaytest.tproj/misc.h | 46 + eaytest.tproj/rijndael-alg-fst.c | 492 +++ eaytest.tproj/rijndael-alg-fst.h | 33 + eaytest.tproj/rijndael-api-fst.c | 495 +++ eaytest.tproj/rijndael-api-fst.h | 103 + eaytest.tproj/sha2.c | 1102 +++++ eaytest.tproj/sha2.h | 144 + eaytest.tproj/str2val.c | 122 + eaytest.tproj/str2val.h | 33 + eaytest.tproj/vmbuf.c | 115 + eaytest.tproj/vmbuf.h | 63 + ftp.tproj/Makefile.postamble | 123 - ftp.tproj/Makefile.preamble | 130 - ftp.tproj/cmds.c | 2236 ---------- ftp.tproj/cmdtab.c | 207 - ftp.tproj/domacro.c | 168 - ftp.tproj/extern.h | 176 - ftp.tproj/ftp.1 | 1157 ----- ftp.tproj/ftp.c | 1542 ------- ftp.tproj/ftp_var.c | 135 - ftp.tproj/ftp_var.h | 149 - ftp.tproj/h.template | 11 - ftp.tproj/m.template | 18 - ftp.tproj/main.c | 528 --- ftp.tproj/pathnames.h | 62 - ftp.tproj/ruserpass.c | 300 -- ftpd.tproj/Makefile.postamble | 111 - ftpd.tproj/Makefile.preamble | 119 - ftpd.tproj/PB.project | 40 - ftpd.tproj/cmp.c | 109 - ftpd.tproj/extern.h | 89 - ftpd.tproj/ftpcmd.y | 1689 ------- ftpd.tproj/ftpd.8 | 481 -- ftpd.tproj/ftpd.c | 2923 ------------ ftpd.tproj/logwtmp.c | 115 - ftpd.tproj/ls.c | 791 ---- ftpd.tproj/ls.h | 81 - ftpd.tproj/popen.c | 206 - ftpd.tproj/print.c | 517 --- ftpd.tproj/util.c | 171 - identd.tproj/Makefile | 2 +- identd.tproj/Makefile.postamble | 3 + identd.tproj/identd.8 | 6 +- ifconfig.tproj/Makefile.preamble | 2 +- ifconfig.tproj/ifconfig.8 | 519 ++- ifconfig.tproj/ifconfig.c | 903 +++- ip6conf.tproj/6to4.conf | 20 + {rbootd.tproj => ip6conf.tproj}/Makefile | 20 +- ip6conf.tproj/Makefile.postamble | 13 + ip6conf.tproj/Makefile.preamble | 3 + {trsp.tproj => ip6conf.tproj}/PB.project | 39 +- ip6conf.tproj/ip6.8 | 45 + ip6conf.tproj/ip6config | 207 + ip6conf.tproj/ip6config.8 | 160 + ip6conf.tproj/ip6tool.c | 228 + ipfw.tproj/ipfw.8 | 1594 ++++--- ipfw.tproj/ipfw.c | 1557 +++++-- ipsec/Makefile | 61 + ipsec/Makefile.postamble | 104 + ipsec/Makefile.preamble | 141 + ipsec/PB.project | 43 + ipsec/ipsec_dump_policy.c | 307 ++ ipsec/ipsec_get_policylen.c | 47 + ipsec/ipsec_set_policy.3 | 274 ++ ipsec/ipsec_strerror.3 | 82 + ipsec/ipsec_strerror.c | 88 + ipsec/ipsec_strerror.h | 63 + ipsec/key_debug.h | 95 + ipsec/libpfkey.h | 90 + ipsec/policy_parse.y | 432 ++ ipsec/policy_token.l | 148 + makedbm.tproj/db.c | 1 - natd.tproj/icmp.c | 24 +- natd.tproj/natd.8 | 740 ++-- natd.tproj/natd.c | 531 ++- natd.tproj/natd.h | 24 +- {sliplogin.tproj => ndp.tproj}/Makefile | 14 +- ndp.tproj/Makefile.postamble | 4 + ndp.tproj/Makefile.preamble | 4 + {newclient.tproj => ndp.tproj}/PB.project | 25 +- ndp.tproj/gnuc.h | 2 + ndp.tproj/ndp.8 | 182 + ndp.tproj/ndp.c | 1528 +++++++ netstat.tproj/Makefile | 4 +- netstat.tproj/Makefile.postamble | 6 +- netstat.tproj/Makefile.preamble | 2 + netstat.tproj/PB.project | 13 +- netstat.tproj/if.c | 351 +- netstat.tproj/inet.c | 272 +- netstat.tproj/inet6.c | 1111 +++++ netstat.tproj/ipsec.c | 328 ++ netstat.tproj/iso.c | 866 ---- netstat.tproj/main.c | 406 +- netstat.tproj/mroute.c | 8 +- netstat.tproj/mroute6.c | 248 ++ netstat.tproj/netstat.1 | 398 +- netstat.tproj/netstat.h | 199 +- netstat.tproj/route.c | 401 +- newclient.tproj/Makefile | 36 - newclient.tproj/Makefile.preamble | 1 - newclient.tproj/newclient.csh | 233 - nfsstat.tproj/nfsstat.c | 1 - {startslip.tproj => ping6.tproj}/Makefile | 12 +- .../Makefile.dist | 6 +- ping6.tproj/Makefile.postamble | 5 + ping6.tproj/Makefile.preamble | 4 + {startslip.tproj => ping6.tproj}/PB.project | 19 +- ping6.tproj/md5.c | 308 ++ ping6.tproj/md5.h | 75 + ping6.tproj/ping6.8 | 484 ++ ping6.tproj/ping6.c | 2718 ++++++++++++ racoon.tproj/Makefile | 71 + racoon.tproj/Makefile.postamble | 110 + racoon.tproj/Makefile.preamble | 150 + racoon.tproj/PB.project | 130 + racoon.tproj/admin.c | 486 ++ racoon.tproj/admin.h | 77 + racoon.tproj/admin_var.h | 36 + racoon.tproj/algorithm.c | 846 ++++ racoon.tproj/algorithm.h | 191 + racoon.tproj/backupsa.c | 485 ++ racoon.tproj/backupsa.h | 37 + racoon.tproj/boxes-fst.dat | 957 ++++ racoon.tproj/cfparse.y | 1374 ++++++ racoon.tproj/cftoken.h | 41 + racoon.tproj/cftoken.l | 533 +++ racoon.tproj/crypto_openssl.c | 2295 ++++++++++ racoon.tproj/crypto_openssl.h | 189 + racoon.tproj/debug.h | 34 + racoon.tproj/dhgroup.h | 198 + racoon.tproj/dnssec.c | 147 + racoon.tproj/dnssec.h | 32 + racoon.tproj/gcmalloc.h | 114 + racoon.tproj/getcertsbyname.c | 410 ++ racoon.tproj/grabmyaddr.c | 624 +++ racoon.tproj/grabmyaddr.h | 47 + racoon.tproj/gssapi.c | 709 +++ racoon.tproj/gssapi.h | 88 + racoon.tproj/handler.c | 869 ++++ racoon.tproj/handler.h | 422 ++ racoon.tproj/ipsec_doi.c | 3910 +++++++++++++++++ racoon.tproj/ipsec_doi.h | 212 + racoon.tproj/isakmp.c | 2418 ++++++++++ racoon.tproj/isakmp.h | 348 ++ racoon.tproj/isakmp_agg.c | 1215 +++++ racoon.tproj/isakmp_agg.h | 39 + racoon.tproj/isakmp_base.c | 1068 +++++ racoon.tproj/isakmp_base.h | 41 + racoon.tproj/isakmp_ident.c | 1699 +++++++ racoon.tproj/isakmp_ident.h | 45 + racoon.tproj/isakmp_inf.c | 1291 ++++++ racoon.tproj/isakmp_inf.h | 46 + racoon.tproj/isakmp_newg.c | 228 + racoon.tproj/isakmp_newg.h | 32 + racoon.tproj/isakmp_quick.c | 2110 +++++++++ racoon.tproj/isakmp_quick.h | 43 + racoon.tproj/isakmp_var.h | 107 + racoon.tproj/key_debug.c | 751 ++++ racoon.tproj/libpfkey.h | 90 + racoon.tproj/localconf.c | 324 ++ racoon.tproj/localconf.h | 111 + racoon.tproj/logger.c | 258 ++ racoon.tproj/logger.h | 46 + racoon.tproj/main.c | 395 ++ racoon.tproj/misc.c | 167 + racoon.tproj/misc.h | 46 + racoon.tproj/netdb_dnssec.h | 67 + racoon.tproj/oakley.c | 2852 ++++++++++++ racoon.tproj/oakley.h | 191 + racoon.tproj/pfkey.c | 2546 +++++++++++ racoon.tproj/pfkey.h | 70 + racoon.tproj/pfkey2.c | 2108 +++++++++ racoon.tproj/pfkey_dump.c | 596 +++ racoon.tproj/plog.c | 219 + racoon.tproj/plog.h | 68 + racoon.tproj/policy.c | 416 ++ racoon.tproj/policy.h | 115 + racoon.tproj/proposal.c | 1113 +++++ racoon.tproj/proposal.h | 203 + racoon.tproj/psk.txt | 10 + racoon.tproj/racoon.8 | 140 + racoon.tproj/racoon.conf | 125 + racoon.tproj/racoon.conf.5 | 725 +++ racoon.tproj/remoteconf.c | 317 ++ racoon.tproj/remoteconf.h | 122 + racoon.tproj/rijndael-alg-fst.c | 492 +++ racoon.tproj/rijndael-alg-fst.h | 33 + racoon.tproj/rijndael-api-fst.c | 495 +++ racoon.tproj/rijndael-api-fst.h | 103 + racoon.tproj/rijndael.h | 3 + racoon.tproj/rijndael_local.h | 10 + racoon.tproj/safefile.c | 89 + racoon.tproj/safefile.h | 34 + racoon.tproj/sainfo.c | 224 + racoon.tproj/sainfo.h | 71 + racoon.tproj/schedule.c | 358 ++ racoon.tproj/schedule.h | 75 + racoon.tproj/session.c | 400 ++ racoon.tproj/session.h | 33 + racoon.tproj/sha2.c | 1102 +++++ racoon.tproj/sha2.h | 144 + racoon.tproj/sockmisc.c | 785 ++++ racoon.tproj/sockmisc.h | 53 + racoon.tproj/str2val.c | 122 + racoon.tproj/str2val.h | 33 + racoon.tproj/strnames.c | 832 ++++ racoon.tproj/strnames.h | 63 + racoon.tproj/var.h | 93 + racoon.tproj/vendorid.c | 139 + racoon.tproj/vendorid.h | 62 + racoon.tproj/vmbuf.c | 115 + racoon.tproj/vmbuf.h | 63 + {uucpd.tproj => racoonctl.tproj}/Makefile | 19 +- racoonctl.tproj/Makefile.postamble | 100 + racoonctl.tproj/Makefile.preamble | 146 + racoonctl.tproj/PB.project | 35 + racoonctl.tproj/key_debug.c | 751 ++++ racoonctl.tproj/kmpstat.c | 1101 +++++ racoonctl.tproj/misc.c | 167 + racoonctl.tproj/misc.h | 46 + racoonctl.tproj/pfkey.c | 2108 +++++++++ racoonctl.tproj/pfkey_dump.c | 596 +++ racoonctl.tproj/str2val.c | 122 + racoonctl.tproj/str2val.h | 33 + racoonctl.tproj/vmbuf.c | 115 + racoonctl.tproj/vmbuf.h | 63 + rbootd.tproj/Makefile.postamble | 111 - rbootd.tproj/Makefile.preamble | 119 - rbootd.tproj/PB.project | 39 - rbootd.tproj/bpf.c | 445 -- rbootd.tproj/conf.c | 113 - rbootd.tproj/defs.h | 208 - rbootd.tproj/parseconf.c | 382 -- rbootd.tproj/pathnames.h | 74 - rbootd.tproj/rbootd.8 | 156 - rbootd.tproj/rbootd.c | 531 --- rbootd.tproj/rmp.h | 118 - rbootd.tproj/rmp_var.h | 267 -- rbootd.tproj/rmpproto.c | 616 --- rbootd.tproj/utils.c | 580 --- rlogin.tproj/krcmd.c | 2 +- route.tproj/Makefile | 4 +- route.tproj/Makefile.dist | 2 +- route.tproj/Makefile.postamble | 3 + route.tproj/Makefile.preamble | 2 + route.tproj/PB.project | 2 +- route.tproj/ccitt_addr.c | 199 - route.tproj/keywords.h | 56 +- route.tproj/route.8 | 175 +- route.tproj/route.c | 369 +- routed.tproj/Makefile | 2 +- routed.tproj/Makefile.postamble | 3 + routed.tproj/Makefile.preamble | 3 + routed.tproj/PB.project | 2 +- routed.tproj/routed.8 | 670 ++- rsh.tproj/rsh.c | 4 +- {ftpd.tproj => rtadvd.tproj}/Makefile | 22 +- rtadvd.tproj/Makefile.postamble | 11 + rtadvd.tproj/Makefile.preamble | 4 + rtadvd.tproj/PB.project | 31 + rtadvd.tproj/advcap.c | 455 ++ rtadvd.tproj/advcap.h | 47 + rtadvd.tproj/config.c | 987 +++++ rtadvd.tproj/config.h | 37 + rtadvd.tproj/dump.c | 243 + rtadvd.tproj/dump.h | 34 + rtadvd.tproj/if.c | 590 +++ rtadvd.tproj/if.h | 59 + rtadvd.tproj/pathnames.h | 4 + rtadvd.tproj/rrenum.c | 489 +++ rtadvd.tproj/rrenum.h | 35 + rtadvd.tproj/rtadvd.8 | 179 + rtadvd.tproj/rtadvd.c | 1630 +++++++ rtadvd.tproj/rtadvd.conf | 21 + rtadvd.tproj/rtadvd.conf.5 | 386 ++ rtadvd.tproj/rtadvd.h | 172 + rtadvd.tproj/timer.c | 217 + rtadvd.tproj/timer.h | 66 + {ftp.tproj => rtsol.tproj}/Makefile | 18 +- rtsol.tproj/Makefile.dist | 8 + rtsol.tproj/Makefile.postamble | 10 + rtsol.tproj/Makefile.preamble | 4 + rtsol.tproj/PB.project | 31 + rtsol.tproj/dump.c | 142 + rtsol.tproj/if.c | 468 ++ rtsol.tproj/probe.c | 191 + rtsol.tproj/rtsock.c | 179 + rtsol.tproj/rtsol.8 | 224 + rtsol.tproj/rtsol.c | 343 ++ rtsol.tproj/rtsold.c | 792 ++++ rtsol.tproj/rtsold.h | 95 + setkey.tproj/Makefile | 51 + setkey.tproj/Makefile.postamble | 103 + setkey.tproj/Makefile.preamble | 140 + {ftp.tproj => setkey.tproj}/PB.project | 25 +- setkey.tproj/ipsec_strerror.h | 63 + setkey.tproj/key_debug.c | 751 ++++ setkey.tproj/key_debug.h | 95 + setkey.tproj/libpfkey.h | 90 + setkey.tproj/parse.y | 933 ++++ setkey.tproj/pfkey.c | 2108 +++++++++ setkey.tproj/pfkey_dump.c | 596 +++ setkey.tproj/setkey.8 | 629 +++ setkey.tproj/setkey.c | 648 +++ setkey.tproj/token.l | 323 ++ setkey.tproj/vchar.h | 36 + sliplogin.tproj/Makefile.preamble | 113 - sliplogin.tproj/pathnames.h | 69 - sliplogin.tproj/slip.hosts | 11 - sliplogin.tproj/slip.login | 12 - sliplogin.tproj/sliplogin.8 | 220 - sliplogin.tproj/sliplogin.c | 404 -- startslip.tproj/Makefile.preamble | 2 - startslip.tproj/startslip.1 | 105 - startslip.tproj/startslip.c | 466 -- syslogd.tproj/syslogd.c | 33 +- talk.tproj/Makefile | 2 +- talk.tproj/io.c | 3 - telnet.tproj/Makefile | 10 +- telnet.tproj/authenc.c | 73 +- telnet.tproj/commands.c | 1789 ++++---- telnet.tproj/defines.h | 30 +- telnet.tproj/externs.h | 250 +- telnet.tproj/fdset.h | 23 - telnet.tproj/general.h | 23 - telnet.tproj/main.c | 230 +- .../ls_extern.h => telnet.tproj/misc-proto.h | 66 +- ftpd.tproj/pathnames.h => telnet.tproj/misc.h | 20 +- telnet.tproj/network.c | 55 +- telnet.tproj/ring.c | 131 +- telnet.tproj/ring.h | 51 +- telnet.tproj/sys_bsd.c | 400 +- telnet.tproj/telnet.1 | 428 +- telnet.tproj/telnet.c | 753 +--- telnet.tproj/terminal.c | 69 +- telnet.tproj/types.h | 23 - telnet.tproj/utilities.c | 149 +- telnetd.tproj/Makefile | 2 +- timed.tproj/timed.tproj/Makefile.postamble | 3 + timed.tproj/timed.tproj/Makefile.preamble | 1 + traceroute.tproj/Makefile.postamble | 3 + traceroute.tproj/Makefile.preamble | 1 + {trsp.tproj => traceroute6.tproj}/Makefile | 8 +- .../Makefile.postamble | 3 + .../Makefile.preamble | 2 + .../PB.project | 10 +- traceroute6.tproj/traceroute6.8 | 123 + traceroute6.tproj/traceroute6.c | 1357 ++++++ trpt.tproj/Makefile | 2 +- trpt.tproj/trpt.c | 4 +- trsp.tproj/Makefile.postamble | 110 - trsp.tproj/trsp.8 | 141 - trsp.tproj/trsp.c | 458 -- uucpd.tproj/Makefile.postamble | 111 - uucpd.tproj/Makefile.preamble | 119 - uucpd.tproj/PB.project | 42 - uucpd.tproj/pathnames.h | 61 - uucpd.tproj/uucpd.c | 323 -- ypbind.tproj/Makefile | 2 +- ypbind.tproj/Makefile.postamble | 3 + ypbind.tproj/Makefile.preamble | 1 + ypbind.tproj/PB.project | 2 +- ypbind.tproj/ypbind.8 | 134 + ypcat.tproj/Makefile | 2 +- ypcat.tproj/Makefile.postamble | 103 + ypcat.tproj/Makefile.preamble | 1 + ypcat.tproj/PB.project | 2 +- ypinit.tproj/Makefile | 6 +- ypinit.tproj/ypinit.8 | 69 + ypinit.tproj/ypinit.sh | 4 +- yppoll.tproj/Makefile | 2 +- yppoll.tproj/Makefile.postamble | 103 + yppoll.tproj/Makefile.preamble | 1 + yppoll.tproj/PB.project | 2 +- yppush.tproj/Makefile.postamble | 3 + yppush.tproj/Makefile.preamble | 1 + yppush.tproj/ypdb.h | 2 +- ypserv.tproj/Makefile | 2 +- ypserv.tproj/Makefile.postamble | 6 + ypserv.tproj/Makefile.preamble | 1 + ypserv.tproj/ypserv.8 | 134 + ypset.tproj/Makefile | 2 +- ypset.tproj/Makefile.postamble | 103 + ypset.tproj/Makefile.preamble | 1 + ypset.tproj/PB.project | 2 +- ypset.tproj/ypset.8 | 91 + ypxfr.tproj/Makefile.postamble | 3 + ypxfr.tproj/Makefile.preamble | 1 + ypxfr.tproj/ypdb.h | 2 +- 417 files changed, 97363 insertions(+), 28357 deletions(-) create mode 100644 alias/alias_pptp.c create mode 100644 alias/alias_smedia.c create mode 100644 bootparams/bpwhoami.tproj/bpwhoami.1 create mode 100644 eaytest.tproj/Makefile create mode 100644 eaytest.tproj/Makefile.postamble create mode 100644 eaytest.tproj/Makefile.preamble create mode 100644 eaytest.tproj/PB.project create mode 100644 eaytest.tproj/crypto_openssl.c create mode 100644 eaytest.tproj/crypto_openssl.h create mode 100644 eaytest.tproj/eaytest.c create mode 100644 eaytest.tproj/misc.c create mode 100644 eaytest.tproj/misc.h create mode 100644 eaytest.tproj/rijndael-alg-fst.c create mode 100644 eaytest.tproj/rijndael-alg-fst.h create mode 100644 eaytest.tproj/rijndael-api-fst.c create mode 100644 eaytest.tproj/rijndael-api-fst.h create mode 100644 eaytest.tproj/sha2.c create mode 100644 eaytest.tproj/sha2.h create mode 100644 eaytest.tproj/str2val.c create mode 100644 eaytest.tproj/str2val.h create mode 100644 eaytest.tproj/vmbuf.c create mode 100644 eaytest.tproj/vmbuf.h delete mode 100644 ftp.tproj/Makefile.postamble delete mode 100644 ftp.tproj/Makefile.preamble delete mode 100644 ftp.tproj/cmds.c delete mode 100644 ftp.tproj/cmdtab.c delete mode 100644 ftp.tproj/domacro.c delete mode 100644 ftp.tproj/extern.h delete mode 100644 ftp.tproj/ftp.1 delete mode 100644 ftp.tproj/ftp.c delete mode 100644 ftp.tproj/ftp_var.c delete mode 100644 ftp.tproj/ftp_var.h delete mode 100644 ftp.tproj/h.template delete mode 100644 ftp.tproj/m.template delete mode 100644 ftp.tproj/main.c delete mode 100644 ftp.tproj/pathnames.h delete mode 100644 ftp.tproj/ruserpass.c delete mode 100644 ftpd.tproj/Makefile.postamble delete mode 100644 ftpd.tproj/Makefile.preamble delete mode 100644 ftpd.tproj/PB.project delete mode 100644 ftpd.tproj/cmp.c delete mode 100644 ftpd.tproj/extern.h delete mode 100644 ftpd.tproj/ftpcmd.y delete mode 100644 ftpd.tproj/ftpd.8 delete mode 100644 ftpd.tproj/ftpd.c delete mode 100644 ftpd.tproj/logwtmp.c delete mode 100644 ftpd.tproj/ls.c delete mode 100644 ftpd.tproj/ls.h delete mode 100644 ftpd.tproj/popen.c delete mode 100644 ftpd.tproj/print.c delete mode 100644 ftpd.tproj/util.c create mode 100644 identd.tproj/Makefile.postamble create mode 100644 ip6conf.tproj/6to4.conf rename {rbootd.tproj => ip6conf.tproj}/Makefile (68%) create mode 100644 ip6conf.tproj/Makefile.postamble create mode 100644 ip6conf.tproj/Makefile.preamble rename {trsp.tproj => ip6conf.tproj}/PB.project (53%) create mode 100644 ip6conf.tproj/ip6.8 create mode 100644 ip6conf.tproj/ip6config create mode 100644 ip6conf.tproj/ip6config.8 create mode 100644 ip6conf.tproj/ip6tool.c create mode 100644 ipsec/Makefile create mode 100644 ipsec/Makefile.postamble create mode 100644 ipsec/Makefile.preamble create mode 100644 ipsec/PB.project create mode 100644 ipsec/ipsec_dump_policy.c create mode 100644 ipsec/ipsec_get_policylen.c create mode 100644 ipsec/ipsec_set_policy.3 create mode 100644 ipsec/ipsec_strerror.3 create mode 100644 ipsec/ipsec_strerror.c create mode 100644 ipsec/ipsec_strerror.h create mode 100644 ipsec/key_debug.h create mode 100644 ipsec/libpfkey.h create mode 100644 ipsec/policy_parse.y create mode 100644 ipsec/policy_token.l rename {sliplogin.tproj => ndp.tproj}/Makefile (84%) create mode 100644 ndp.tproj/Makefile.postamble create mode 100644 ndp.tproj/Makefile.preamble rename {newclient.tproj => ndp.tproj}/PB.project (58%) create mode 100644 ndp.tproj/gnuc.h create mode 100644 ndp.tproj/ndp.8 create mode 100644 ndp.tproj/ndp.c create mode 100644 netstat.tproj/inet6.c create mode 100644 netstat.tproj/ipsec.c delete mode 100644 netstat.tproj/iso.c create mode 100644 netstat.tproj/mroute6.c delete mode 100644 newclient.tproj/Makefile delete mode 100644 newclient.tproj/Makefile.preamble delete mode 100644 newclient.tproj/newclient.csh rename {startslip.tproj => ping6.tproj}/Makefile (82%) rename {startslip.tproj => ping6.tproj}/Makefile.dist (54%) create mode 100644 ping6.tproj/Makefile.postamble create mode 100644 ping6.tproj/Makefile.preamble rename {startslip.tproj => ping6.tproj}/PB.project (64%) create mode 100644 ping6.tproj/md5.c create mode 100644 ping6.tproj/md5.h create mode 100644 ping6.tproj/ping6.8 create mode 100644 ping6.tproj/ping6.c create mode 100644 racoon.tproj/Makefile create mode 100644 racoon.tproj/Makefile.postamble create mode 100644 racoon.tproj/Makefile.preamble create mode 100644 racoon.tproj/PB.project create mode 100644 racoon.tproj/admin.c create mode 100644 racoon.tproj/admin.h create mode 100644 racoon.tproj/admin_var.h create mode 100644 racoon.tproj/algorithm.c create mode 100644 racoon.tproj/algorithm.h create mode 100644 racoon.tproj/backupsa.c create mode 100644 racoon.tproj/backupsa.h create mode 100644 racoon.tproj/boxes-fst.dat create mode 100644 racoon.tproj/cfparse.y create mode 100644 racoon.tproj/cftoken.h create mode 100644 racoon.tproj/cftoken.l create mode 100644 racoon.tproj/crypto_openssl.c create mode 100644 racoon.tproj/crypto_openssl.h create mode 100644 racoon.tproj/debug.h create mode 100644 racoon.tproj/dhgroup.h create mode 100644 racoon.tproj/dnssec.c create mode 100644 racoon.tproj/dnssec.h create mode 100644 racoon.tproj/gcmalloc.h create mode 100644 racoon.tproj/getcertsbyname.c create mode 100644 racoon.tproj/grabmyaddr.c create mode 100644 racoon.tproj/grabmyaddr.h create mode 100644 racoon.tproj/gssapi.c create mode 100644 racoon.tproj/gssapi.h create mode 100644 racoon.tproj/handler.c create mode 100644 racoon.tproj/handler.h create mode 100644 racoon.tproj/ipsec_doi.c create mode 100644 racoon.tproj/ipsec_doi.h create mode 100644 racoon.tproj/isakmp.c create mode 100644 racoon.tproj/isakmp.h create mode 100644 racoon.tproj/isakmp_agg.c create mode 100644 racoon.tproj/isakmp_agg.h create mode 100644 racoon.tproj/isakmp_base.c create mode 100644 racoon.tproj/isakmp_base.h create mode 100644 racoon.tproj/isakmp_ident.c create mode 100644 racoon.tproj/isakmp_ident.h create mode 100644 racoon.tproj/isakmp_inf.c create mode 100644 racoon.tproj/isakmp_inf.h create mode 100644 racoon.tproj/isakmp_newg.c create mode 100644 racoon.tproj/isakmp_newg.h create mode 100644 racoon.tproj/isakmp_quick.c create mode 100644 racoon.tproj/isakmp_quick.h create mode 100644 racoon.tproj/isakmp_var.h create mode 100644 racoon.tproj/key_debug.c create mode 100644 racoon.tproj/libpfkey.h create mode 100644 racoon.tproj/localconf.c create mode 100644 racoon.tproj/localconf.h create mode 100644 racoon.tproj/logger.c create mode 100644 racoon.tproj/logger.h create mode 100644 racoon.tproj/main.c create mode 100644 racoon.tproj/misc.c create mode 100644 racoon.tproj/misc.h create mode 100644 racoon.tproj/netdb_dnssec.h create mode 100644 racoon.tproj/oakley.c create mode 100644 racoon.tproj/oakley.h create mode 100644 racoon.tproj/pfkey.c create mode 100644 racoon.tproj/pfkey.h create mode 100644 racoon.tproj/pfkey2.c create mode 100644 racoon.tproj/pfkey_dump.c create mode 100644 racoon.tproj/plog.c create mode 100644 racoon.tproj/plog.h create mode 100644 racoon.tproj/policy.c create mode 100644 racoon.tproj/policy.h create mode 100644 racoon.tproj/proposal.c create mode 100644 racoon.tproj/proposal.h create mode 100644 racoon.tproj/psk.txt create mode 100644 racoon.tproj/racoon.8 create mode 100644 racoon.tproj/racoon.conf create mode 100644 racoon.tproj/racoon.conf.5 create mode 100644 racoon.tproj/remoteconf.c create mode 100644 racoon.tproj/remoteconf.h create mode 100644 racoon.tproj/rijndael-alg-fst.c create mode 100644 racoon.tproj/rijndael-alg-fst.h create mode 100644 racoon.tproj/rijndael-api-fst.c create mode 100644 racoon.tproj/rijndael-api-fst.h create mode 100644 racoon.tproj/rijndael.h create mode 100644 racoon.tproj/rijndael_local.h create mode 100644 racoon.tproj/safefile.c create mode 100644 racoon.tproj/safefile.h create mode 100644 racoon.tproj/sainfo.c create mode 100644 racoon.tproj/sainfo.h create mode 100644 racoon.tproj/schedule.c create mode 100644 racoon.tproj/schedule.h create mode 100644 racoon.tproj/session.c create mode 100644 racoon.tproj/session.h create mode 100644 racoon.tproj/sha2.c create mode 100644 racoon.tproj/sha2.h create mode 100644 racoon.tproj/sockmisc.c create mode 100644 racoon.tproj/sockmisc.h create mode 100644 racoon.tproj/str2val.c create mode 100644 racoon.tproj/str2val.h create mode 100644 racoon.tproj/strnames.c create mode 100644 racoon.tproj/strnames.h create mode 100644 racoon.tproj/var.h create mode 100644 racoon.tproj/vendorid.c create mode 100644 racoon.tproj/vendorid.h create mode 100644 racoon.tproj/vmbuf.c create mode 100644 racoon.tproj/vmbuf.h rename {uucpd.tproj => racoonctl.tproj}/Makefile (71%) create mode 100644 racoonctl.tproj/Makefile.postamble create mode 100644 racoonctl.tproj/Makefile.preamble create mode 100644 racoonctl.tproj/PB.project create mode 100644 racoonctl.tproj/key_debug.c create mode 100644 racoonctl.tproj/kmpstat.c create mode 100644 racoonctl.tproj/misc.c create mode 100644 racoonctl.tproj/misc.h create mode 100644 racoonctl.tproj/pfkey.c create mode 100644 racoonctl.tproj/pfkey_dump.c create mode 100644 racoonctl.tproj/str2val.c create mode 100644 racoonctl.tproj/str2val.h create mode 100644 racoonctl.tproj/vmbuf.c create mode 100644 racoonctl.tproj/vmbuf.h delete mode 100644 rbootd.tproj/Makefile.postamble delete mode 100644 rbootd.tproj/Makefile.preamble delete mode 100644 rbootd.tproj/PB.project delete mode 100644 rbootd.tproj/bpf.c delete mode 100644 rbootd.tproj/conf.c delete mode 100644 rbootd.tproj/defs.h delete mode 100644 rbootd.tproj/parseconf.c delete mode 100644 rbootd.tproj/pathnames.h delete mode 100644 rbootd.tproj/rbootd.8 delete mode 100644 rbootd.tproj/rbootd.c delete mode 100644 rbootd.tproj/rmp.h delete mode 100644 rbootd.tproj/rmp_var.h delete mode 100644 rbootd.tproj/rmpproto.c delete mode 100644 rbootd.tproj/utils.c delete mode 100644 route.tproj/ccitt_addr.c create mode 100644 routed.tproj/Makefile.postamble rename {ftpd.tproj => rtadvd.tproj}/Makefile (68%) create mode 100644 rtadvd.tproj/Makefile.postamble create mode 100644 rtadvd.tproj/Makefile.preamble create mode 100644 rtadvd.tproj/PB.project create mode 100644 rtadvd.tproj/advcap.c create mode 100644 rtadvd.tproj/advcap.h create mode 100644 rtadvd.tproj/config.c create mode 100644 rtadvd.tproj/config.h create mode 100644 rtadvd.tproj/dump.c create mode 100644 rtadvd.tproj/dump.h create mode 100644 rtadvd.tproj/if.c create mode 100644 rtadvd.tproj/if.h create mode 100644 rtadvd.tproj/pathnames.h create mode 100644 rtadvd.tproj/rrenum.c create mode 100644 rtadvd.tproj/rrenum.h create mode 100644 rtadvd.tproj/rtadvd.8 create mode 100644 rtadvd.tproj/rtadvd.c create mode 100644 rtadvd.tproj/rtadvd.conf create mode 100644 rtadvd.tproj/rtadvd.conf.5 create mode 100644 rtadvd.tproj/rtadvd.h create mode 100644 rtadvd.tproj/timer.c create mode 100644 rtadvd.tproj/timer.h rename {ftp.tproj => rtsol.tproj}/Makefile (76%) create mode 100644 rtsol.tproj/Makefile.dist create mode 100644 rtsol.tproj/Makefile.postamble create mode 100644 rtsol.tproj/Makefile.preamble create mode 100644 rtsol.tproj/PB.project create mode 100644 rtsol.tproj/dump.c create mode 100644 rtsol.tproj/if.c create mode 100644 rtsol.tproj/probe.c create mode 100644 rtsol.tproj/rtsock.c create mode 100644 rtsol.tproj/rtsol.8 create mode 100644 rtsol.tproj/rtsol.c create mode 100644 rtsol.tproj/rtsold.c create mode 100644 rtsol.tproj/rtsold.h create mode 100644 setkey.tproj/Makefile create mode 100644 setkey.tproj/Makefile.postamble create mode 100644 setkey.tproj/Makefile.preamble rename {ftp.tproj => setkey.tproj}/PB.project (53%) create mode 100644 setkey.tproj/ipsec_strerror.h create mode 100644 setkey.tproj/key_debug.c create mode 100644 setkey.tproj/key_debug.h create mode 100644 setkey.tproj/libpfkey.h create mode 100644 setkey.tproj/parse.y create mode 100644 setkey.tproj/pfkey.c create mode 100644 setkey.tproj/pfkey_dump.c create mode 100644 setkey.tproj/setkey.8 create mode 100644 setkey.tproj/setkey.c create mode 100644 setkey.tproj/token.l create mode 100644 setkey.tproj/vchar.h delete mode 100644 sliplogin.tproj/Makefile.preamble delete mode 100644 sliplogin.tproj/pathnames.h delete mode 100644 sliplogin.tproj/slip.hosts delete mode 100644 sliplogin.tproj/slip.login delete mode 100644 sliplogin.tproj/sliplogin.8 delete mode 100644 sliplogin.tproj/sliplogin.c delete mode 100644 startslip.tproj/Makefile.preamble delete mode 100644 startslip.tproj/startslip.1 delete mode 100644 startslip.tproj/startslip.c rename ftpd.tproj/ls_extern.h => telnet.tproj/misc-proto.h (51%) rename ftpd.tproj/pathnames.h => telnet.tproj/misc.h (81%) rename {trsp.tproj => traceroute6.tproj}/Makefile (88%) rename {sliplogin.tproj => traceroute6.tproj}/Makefile.postamble (97%) rename {trsp.tproj => traceroute6.tproj}/Makefile.preamble (98%) rename {sliplogin.tproj => traceroute6.tproj}/PB.project (88%) create mode 100644 traceroute6.tproj/traceroute6.8 create mode 100644 traceroute6.tproj/traceroute6.c delete mode 100644 trsp.tproj/Makefile.postamble delete mode 100644 trsp.tproj/trsp.8 delete mode 100644 trsp.tproj/trsp.c delete mode 100644 uucpd.tproj/Makefile.postamble delete mode 100644 uucpd.tproj/Makefile.preamble delete mode 100644 uucpd.tproj/PB.project delete mode 100644 uucpd.tproj/pathnames.h delete mode 100644 uucpd.tproj/uucpd.c create mode 100644 ypbind.tproj/ypbind.8 create mode 100644 ypcat.tproj/Makefile.postamble create mode 100644 ypinit.tproj/ypinit.8 create mode 100644 yppoll.tproj/Makefile.postamble create mode 100644 ypserv.tproj/ypserv.8 create mode 100644 ypset.tproj/Makefile.postamble create mode 100644 ypset.tproj/ypset.8 diff --git a/Makefile b/Makefile index 9577f9a..8badaa5 100644 --- a/Makefile +++ b/Makefile @@ -14,24 +14,26 @@ PROJECT_TYPE = Aggregate SUBPROJECTS = timed.tproj bootparams -TOOLS = arp.tproj domainname.tproj ftp.tproj ftpd.tproj identd.tproj\ +TOOLS = arp.tproj domainname.tproj identd.tproj\ ifconfig.tproj inetd.tproj logger.tproj netstat.tproj\ - nfsd.tproj nfsiod.tproj nfsstat.tproj ping.tproj \ - rarpd.tproj rbootd.tproj rcp.tproj rexecd.tproj rlogin.tproj\ - rlogind.tproj route.tproj routed.tproj rpcinfo.tproj rsh.tproj\ - rshd.tproj ruptime.tproj rwho.tproj rwhod.tproj slattach.tproj\ - sliplogin.tproj spray.tproj startslip.tproj syslogd.tproj\ - talk.tproj talkd.tproj telnet.tproj\ - telnetd.tproj tftp.tproj tftpd.tproj traceroute.tproj\ - trpt.tproj trsp.tproj uucpd.tproj wall.tproj ypbind.tproj\ - ypcat.tproj ypmatch.tproj yppoll.tproj yppush.tproj\ - ypserv.tproj ypset.tproj ypwhich.tproj ypxfr.tproj\ - makedbm.tproj revnetgroup.tproj rpc_yppasswdd.tproj\ - stdethers.tproj stdhosts.tproj natd.tproj ipfw.tproj - -LIBRARIES = alias - -LEGACIES = newclient.tproj ypinit.tproj + nfsd.tproj nfsiod.tproj nfsstat.tproj ping.tproj rarpd.tproj\ + rcp.tproj rexecd.tproj rlogin.tproj rlogind.tproj\ + route.tproj routed.tproj rpcinfo.tproj rsh.tproj rshd.tproj\ + ruptime.tproj rwho.tproj rwhod.tproj slattach.tproj\ + spray.tproj syslogd.tproj\ + talk.tproj talkd.tproj telnet.tproj telnetd.tproj tftp.tproj\ + tftpd.tproj traceroute.tproj trpt.tproj wall.tproj\ + ypbind.tproj ypcat.tproj ypmatch.tproj yppoll.tproj\ + yppush.tproj ypserv.tproj ypset.tproj ypwhich.tproj\ + ypxfr.tproj makedbm.tproj revnetgroup.tproj rpc_yppasswdd.tproj\ + stdethers.tproj stdhosts.tproj natd.tproj ipfw.tproj\ + setkey.tproj racoon.tproj racoonctl.tproj eaytest.tproj\ + ping6.tproj traceroute6.tproj rtsol.tproj ndp.tproj rtadvd.tproj\ + ip6conf.tproj + +LIBRARIES = alias ipsec + +LEGACIES = ypinit.tproj OTHERSRCS = Makefile Makefile.include Makefile.preamble diff --git a/PB.project b/PB.project index 53c29a2..e1340e0 100644 --- a/PB.project +++ b/PB.project @@ -7,20 +7,16 @@ arp.tproj, bootparams, domainname.tproj, - ftp.tproj, - ftpd.tproj, identd.tproj, ifconfig.tproj, inetd.tproj, logger.tproj, netstat.tproj, - newclient.tproj, nfsd.tproj, nfsiod.tproj, nfsstat.tproj, ping.tproj, rarpd.tproj, - rbootd.tproj, rcp.tproj, rexecd.tproj, rlogin.tproj, @@ -34,9 +30,7 @@ rwho.tproj, rwhod.tproj, slattach.tproj, - sliplogin.tproj, spray.tproj, - startslip.tproj, syslogd.tproj, talk.tproj, talkd.tproj, @@ -46,8 +40,6 @@ tftpd.tproj, traceroute.tproj, trpt.tproj, - trsp.tproj, - uucpd.tproj, wall.tproj, ypbind.tproj, ypcat.tproj, @@ -65,7 +57,18 @@ stdethers.tproj, stdhosts.tproj, natd.tproj, - ipfw.tproj + ipfw.tproj, + ipsec, + setkey.tproj, + racoon.tproj, + racoonctl.tproj, + eaytest.tproj, + ping6.tproj, + traceroute6.tproj, + rtsol.tproj, + rtadvd.tproj, + ndp.tproj, + ip6conf.tproj ); }; LANGUAGE = English; diff --git a/alias/Makefile b/alias/Makefile index f844cc3..018cf84 100644 --- a/alias/Makefile +++ b/alias/Makefile @@ -15,7 +15,7 @@ PROJECT_TYPE = Library HFILES = alias.h alias_local.h CFILES = alias.c alias_cuseeme.c alias_db.c alias_ftp.c alias_irc.c\ - alias_nbt.c alias_proxy.c alias_util.c + alias_nbt.c alias_pptp.c alias_proxy.c alias_smedia.c alias_util.c OTHERSRCS = Makefile.preamble Makefile Makefile.postamble diff --git a/alias/PB.project b/alias/PB.project index e87cc27..d3a8879 100644 --- a/alias/PB.project +++ b/alias/PB.project @@ -11,7 +11,9 @@ alias_ftp.c, alias_irc.c, alias_nbt.c, + alias_pptp.c, alias_proxy.c, + alias_smedia.c, alias_util.c ); OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble); diff --git a/alias/alias.c b/alias/alias.c index 10e0ccc..fffcae2 100644 --- a/alias/alias.c +++ b/alias/alias.c @@ -1,4 +1,53 @@ -/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias.c,v 1.16.2.7 2001/08/21 03:50:25 brian Exp $ + */ + /* Alias.c provides supervisory control for the functions of the packet aliasing software. It consists of routines to monitor @@ -13,12 +62,9 @@ function calls, so other segments of the program need not know about the underlying data structures. Alias_ftp.c contains special code for modifying the ftp PORT command used to establish - data connections, while alias_irc.c do the same for IRC + data connections, while alias_irc.c does the same for IRC DCC. Alias_util.c contains a few utility routines. - This software is placed into the public domain with no restrictions - on its distribution. - Version 1.0 August, 1996 (cjm) Version 1.1 August 20, 1996 (cjm) @@ -76,14 +122,16 @@ Version 2.3 Dec 1998 (dillon) - Major bounds checking additions, see FreeBSD/CVS - See HISTORY file for additional revisions. + Version 3.1 May, 2000 (salander) + - Added hooks to handle PPTP. -*/ + Version 3.2 July, 2000 (salander and satoh) + - Added PacketUnaliasOut routine. + - Added hooks to handle RTSP/RTP. -#include -#include + See HISTORY file for additional revisions. +*/ -#include #include #include @@ -93,9 +141,7 @@ #include #include -#ifndef IPPROTO_GRE -#define IPPROTO_GRE 47 -#endif +#include #include "alias_local.h" #include "alias.h" @@ -106,6 +152,9 @@ #define IRC_CONTROL_PORT_NUMBER_1 6667 #define IRC_CONTROL_PORT_NUMBER_2 6668 #define CUSEEME_PORT_NUMBER 7648 +#define RTSP_CONTROL_PORT_NUMBER_1 554 +#define RTSP_CONTROL_PORT_NUMBER_2 7070 +#define PPTP_CONTROL_PORT_NUMBER 1723 @@ -115,7 +164,7 @@ TcpMonitorIn() -- These routines monitor TCP connections, and TcpMonitorOut() delete a link when a connection is closed. -These routines look for SYN, ACK and RST flags to determine when TCP +These routines look for SYN, FIN and RST flags to determine when TCP connections open and close. When a TCP connection closes, the data structure containing packet aliasing information is deleted after a timeout period. @@ -137,12 +186,13 @@ TcpMonitorIn(struct ip *pip, struct alias_link *link) switch (GetStateIn(link)) { case ALIAS_TCP_STATE_NOT_CONNECTED: - if (tc->th_flags & TH_SYN) + if (tc->th_flags & TH_RST) + SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED); + else if (tc->th_flags & TH_SYN) SetStateIn(link, ALIAS_TCP_STATE_CONNECTED); break; case ALIAS_TCP_STATE_CONNECTED: - if (tc->th_flags & TH_FIN - || tc->th_flags & TH_RST) + if (tc->th_flags & (TH_FIN | TH_RST)) SetStateIn(link, ALIAS_TCP_STATE_DISCONNECTED); break; } @@ -158,12 +208,13 @@ TcpMonitorOut(struct ip *pip, struct alias_link *link) switch (GetStateOut(link)) { case ALIAS_TCP_STATE_NOT_CONNECTED: - if (tc->th_flags & TH_SYN) + if (tc->th_flags & TH_RST) + SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED); + else if (tc->th_flags & TH_SYN) SetStateOut(link, ALIAS_TCP_STATE_CONNECTED); break; case ALIAS_TCP_STATE_CONNECTED: - if (tc->th_flags & TH_FIN - || tc->th_flags & TH_RST) + if (tc->th_flags & (TH_FIN | TH_RST)) SetStateOut(link, ALIAS_TCP_STATE_DISCONNECTED); break; } @@ -175,8 +226,9 @@ TcpMonitorOut(struct ip *pip, struct alias_link *link) /* Protocol Specific Packet Aliasing Routines - IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2(), IcmpAliasIn3() - IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2(), IcmpAliasOut3() + IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2() + IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2() + ProtoAliasIn(), ProtoAliasOut() UdpAliasIn(), UdpAliasOut() TcpAliasIn(), TcpAliasOut() @@ -191,7 +243,7 @@ address of the outgoing packet and then correctly put it back for any incoming packets. For TCP and UDP, ports are also re-mapped. For ICMP echo/timestamp requests and replies, the following scheme -is used: the id number is replaced by an alias for the outgoing +is used: the ID number is replaced by an alias for the outgoing packet. ICMP error messages are handled by looking at the IP fragment @@ -200,7 +252,7 @@ in the data section of the message. For TCP and UDP protocols, a port number is chosen for an outgoing packet, and then incoming packets are identified by IP address and port numbers. For TCP packets, there is additional logic in the event -that sequence and ack numbers have been altered (as is the case for +that sequence and ACK numbers have been altered (as in the case for FTP data port commands). The port numbers used by the packet aliasing module are not true @@ -215,14 +267,15 @@ the gateway machine or other machines on a local area network. /* Local prototypes */ static int IcmpAliasIn1(struct ip *); static int IcmpAliasIn2(struct ip *); -static int IcmpAliasIn3(struct ip *); static int IcmpAliasIn (struct ip *); static int IcmpAliasOut1(struct ip *); static int IcmpAliasOut2(struct ip *); -static int IcmpAliasOut3(struct ip *); static int IcmpAliasOut (struct ip *); +static int ProtoAliasIn(struct ip *); +static int ProtoAliasOut(struct ip *); + static int UdpAliasOut(struct ip *); static int UdpAliasIn (struct ip *); @@ -234,7 +287,8 @@ static int IcmpAliasIn1(struct ip *pip) { /* - De-alias incoming echo and timestamp replies + De-alias incoming echo and timestamp replies. + Alias incoming echo and timestamp requests. */ struct alias_link *link; struct icmp *ic; @@ -242,7 +296,7 @@ IcmpAliasIn1(struct ip *pip) ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); /* Get source address from ICMP data field and restore original data */ - link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id); + link = FindIcmpIn(pip->ip_src, pip->ip_dst, ic->icmp_id, 1); if (link != NULL) { u_short original_id; @@ -253,7 +307,7 @@ IcmpAliasIn1(struct ip *pip) /* Adjust ICMP checksum */ accumulate = ic->icmp_id; accumulate -= original_id; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); /* Put original sequence number back in */ ic->icmp_id = original_id; @@ -289,7 +343,7 @@ IcmpAliasIn2(struct ip *pip) struct alias_link *link; ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - ip = (struct ip *) ic->icmp_data; + ip = &ic->icmp_ip; ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2)); tc = (struct tcphdr *) ud; @@ -298,15 +352,15 @@ IcmpAliasIn2(struct ip *pip) if (ip->ip_p == IPPROTO_UDP) link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, ud->uh_dport, ud->uh_sport, - IPPROTO_UDP); + IPPROTO_UDP, 0); else if (ip->ip_p == IPPROTO_TCP) link = FindUdpTcpIn(ip->ip_dst, ip->ip_src, tc->th_dport, tc->th_sport, - IPPROTO_TCP); + IPPROTO_TCP, 0); else if (ip->ip_p == IPPROTO_ICMP) { if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) - link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id); - else + link = FindIcmpIn(ip->ip_dst, ip->ip_src, ic2->icmp_id, 0); + else link = NULL; } else link = NULL; @@ -332,7 +386,7 @@ IcmpAliasIn2(struct ip *pip) accumulate -= *sptr; accumulate += ud->uh_sport; accumulate -= original_port; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); /* Un-alias address in IP header */ DifferentialChecksum(&pip->ip_sum, @@ -346,7 +400,7 @@ fragment contained in ICMP data section */ ip->ip_src = original_address; ud->uh_sport = original_port; } - else if (pip->ip_p == IPPROTO_ICMP) + else if (ip->ip_p == IPPROTO_ICMP) { u_short *sptr; int accumulate; @@ -365,7 +419,7 @@ fragment contained in ICMP data section */ accumulate -= *sptr; accumulate += ic2->icmp_id; accumulate -= original_id; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); /* Un-alias address in IP header */ DifferentialChecksum(&pip->ip_sum, @@ -374,8 +428,8 @@ fragment contained in ICMP data section */ 2); pip->ip_dst = original_address; -/* Un-alias address of original IP packet and seqence number of - embedded icmp datagram */ +/* Un-alias address of original IP packet and sequence number of + embedded ICMP datagram */ ip->ip_src = original_address; ic2->icmp_id = original_id; } @@ -384,21 +438,6 @@ fragment contained in ICMP data section */ return(PKT_ALIAS_IGNORED); } -static int -IcmpAliasIn3(struct ip *pip) -{ - struct in_addr original_address; - - original_address = FindOriginalAddress(pip->ip_dst); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &original_address, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = original_address; - - return PKT_ALIAS_OK; -} - static int IcmpAliasIn(struct ip *pip) @@ -430,7 +469,7 @@ IcmpAliasIn(struct ip *pip) break; case ICMP_ECHO: case ICMP_TSTAMP: - iresult = IcmpAliasIn3(pip); + iresult = IcmpAliasIn1(pip); break; } return(iresult); @@ -441,7 +480,8 @@ static int IcmpAliasOut1(struct ip *pip) { /* - Alias ICMP echo and timestamp packets + Alias outgoing echo and timestamp requests. + De-alias outgoing echo and timestamp replies. */ struct alias_link *link; struct icmp *ic; @@ -449,7 +489,7 @@ IcmpAliasOut1(struct ip *pip) ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); /* Save overwritten data for when echo packet returns */ - link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id); + link = FindIcmpOut(pip->ip_src, pip->ip_dst, ic->icmp_id, 1); if (link != NULL) { u_short alias_id; @@ -460,7 +500,7 @@ IcmpAliasOut1(struct ip *pip) /* Since data field is being modified, adjust ICMP checksum */ accumulate = ic->icmp_id; accumulate -= alias_id; - ADJUST_CHECKSUM(accumulate, ic->icmp_cksum) + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); /* Alias sequence number */ ic->icmp_id = alias_id; @@ -490,51 +530,116 @@ IcmpAliasOut2(struct ip *pip) Alias outgoing ICMP error messages containing IP header and first 64 bits of datagram. */ - struct in_addr alias_addr; struct ip *ip; - struct icmp *ic; + struct icmp *ic, *ic2; + struct udphdr *ud; + struct tcphdr *tc; + struct alias_link *link; ic = (struct icmp *) ((char *) pip + (pip->ip_hl << 2)); - ip = (struct ip *) ic->icmp_data; - - alias_addr = FindAliasAddress(ip->ip_src); + ip = &ic->icmp_ip; -/* Alias destination address in IP fragment */ - DifferentialChecksum(&ic->icmp_cksum, - (u_short *) &alias_addr, - (u_short *) &ip->ip_dst, - 2); - ip->ip_dst = alias_addr; + ud = (struct udphdr *) ((char *) ip + (ip->ip_hl <<2)); + tc = (struct tcphdr *) ud; + ic2 = (struct icmp *) ud; -/* alias source address in IP header */ - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_addr, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_addr; + if (ip->ip_p == IPPROTO_UDP) + link = FindUdpTcpOut(ip->ip_dst, ip->ip_src, + ud->uh_dport, ud->uh_sport, + IPPROTO_UDP, 0); + else if (ip->ip_p == IPPROTO_TCP) + link = FindUdpTcpOut(ip->ip_dst, ip->ip_src, + tc->th_dport, tc->th_sport, + IPPROTO_TCP, 0); + else if (ip->ip_p == IPPROTO_ICMP) { + if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) + link = FindIcmpOut(ip->ip_dst, ip->ip_src, ic2->icmp_id, 0); + else + link = NULL; + } else + link = NULL; - return PKT_ALIAS_OK; -} + if (link != NULL) + { + if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) + { + u_short *sptr; + int accumulate; + struct in_addr alias_address; + u_short alias_port; + alias_address = GetAliasAddress(link); + alias_port = GetAliasPort(link); + +/* Adjust ICMP checksum */ + sptr = (u_short *) &(ip->ip_dst); + accumulate = *sptr++; + accumulate += *sptr; + sptr = (u_short *) &alias_address; + accumulate -= *sptr++; + accumulate -= *sptr; + accumulate += ud->uh_dport; + accumulate -= alias_port; + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); -static int -IcmpAliasOut3(struct ip *pip) -{ /* - Handle outgoing echo and timestamp replies. The - only thing which is done in this case is to alias - the source IP address of the packet. -*/ - struct in_addr alias_addr; + * Alias address in IP header if it comes from the host + * the original TCP/UDP packet was destined for. + */ + if (pip->ip_src.s_addr == ip->ip_dst.s_addr) { + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_address, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_address; + } + +/* Alias address and port number of original IP packet +fragment contained in ICMP data section */ + ip->ip_dst = alias_address; + ud->uh_dport = alias_port; + } + else if (ip->ip_p == IPPROTO_ICMP) + { + u_short *sptr; + int accumulate; + struct in_addr alias_address; + u_short alias_id; - alias_addr = FindAliasAddress(pip->ip_src); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_addr, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_addr; + alias_address = GetAliasAddress(link); + alias_id = GetAliasPort(link); - return PKT_ALIAS_OK; +/* Adjust ICMP checksum */ + sptr = (u_short *) &(ip->ip_dst); + accumulate = *sptr++; + accumulate += *sptr; + sptr = (u_short *) &alias_address; + accumulate -= *sptr++; + accumulate -= *sptr; + accumulate += ic2->icmp_id; + accumulate -= alias_id; + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); + +/* + * Alias address in IP header if it comes from the host + * the original ICMP message was destined for. + */ + if (pip->ip_src.s_addr == ip->ip_dst.s_addr) { + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_address, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_address; + } + +/* Alias address of original IP packet and sequence number of + embedded ICMP datagram */ + ip->ip_dst = alias_address; + ic2->icmp_id = alias_id; + } + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); } @@ -568,7 +673,7 @@ IcmpAliasOut(struct ip *pip) break; case ICMP_ECHOREPLY: case ICMP_TSTAMPREPLY: - iresult = IcmpAliasOut3(pip); + iresult = IcmpAliasOut1(pip); } return(iresult); } @@ -576,58 +681,72 @@ IcmpAliasOut(struct ip *pip) static int -PptpAliasIn(struct ip *pip) +ProtoAliasIn(struct ip *pip) { /* - Handle incoming PPTP packets. The + Handle incoming IP packets. The only thing which is done in this case is to alias the dest IP address of the packet to our inside machine. */ - struct in_addr alias_addr; + struct alias_link *link; - if (!GetPptpAlias (&alias_addr)) - return PKT_ALIAS_IGNORED; +/* Return if proxy-only mode is enabled */ + if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) + return PKT_ALIAS_OK; - if (pip->ip_src.s_addr != alias_addr.s_addr) { + link = FindProtoIn(pip->ip_src, pip->ip_dst, pip->ip_p); + if (link != NULL) + { + struct in_addr original_address; - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_addr, - (u_short *) &pip->ip_dst, - 2); - pip->ip_dst = alias_addr; - } + original_address = GetOriginalAddress(link); - return PKT_ALIAS_OK; +/* Restore original IP address */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_dst, + 2); + pip->ip_dst = original_address; + + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); } static int -PptpAliasOut(struct ip *pip) +ProtoAliasOut(struct ip *pip) { /* - Handle outgoing PPTP packets. The + Handle outgoing IP packets. The only thing which is done in this case is to alias the source IP address of the packet. */ - struct in_addr alias_addr; + struct alias_link *link; - if (!GetPptpAlias (&alias_addr)) - return PKT_ALIAS_IGNORED; +/* Return if proxy-only mode is enabled */ + if (packetAliasMode & PKT_ALIAS_PROXY_ONLY) + return PKT_ALIAS_OK; - if (pip->ip_src.s_addr == alias_addr.s_addr) { + link = FindProtoOut(pip->ip_src, pip->ip_dst, pip->ip_p); + if (link != NULL) + { + struct in_addr alias_address; - alias_addr = FindAliasAddress(pip->ip_src); - DifferentialChecksum(&pip->ip_sum, - (u_short *) &alias_addr, - (u_short *) &pip->ip_src, - 2); - pip->ip_src = alias_addr; - } + alias_address = GetAliasAddress(link); - return PKT_ALIAS_OK; -} +/* Change source address */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &alias_address, + (u_short *) &pip->ip_src, + 2); + pip->ip_src = alias_address; + return(PKT_ALIAS_OK); + } + return(PKT_ALIAS_IGNORED); +} static int @@ -644,7 +763,7 @@ UdpAliasIn(struct ip *pip) link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, ud->uh_sport, ud->uh_dport, - IPPROTO_UDP); + IPPROTO_UDP, 1); if (link != NULL) { struct in_addr alias_address; @@ -659,26 +778,20 @@ UdpAliasIn(struct ip *pip) alias_port = ud->uh_dport; ud->uh_dport = GetOriginalPort(link); +/* Special processing for IP encoding protocols */ + if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) + AliasHandleCUSeeMeIn(pip, original_address); /* If NETBIOS Datagram, It should be alias address in UDP Data, too */ - if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) - { - r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport); - } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) - { - r = AliasHandleUdpNbtNS(pip, link, - &alias_address, - &alias_port, - &original_address, - &ud->uh_dport ); - } - - if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) - AliasHandleCUSeeMeIn(pip, original_address); + else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER) + r = AliasHandleUdpNbt(pip, link, &original_address, ud->uh_dport); + else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER) + r = AliasHandleUdpNbtNS(pip, link, &alias_address, &alias_port, + &original_address, &ud->uh_dport); /* If UDP checksum is not zero, then adjust since destination port */ -/* is being unaliased and destination port is being altered. */ +/* is being unaliased and destination address is being altered. */ if (ud->uh_sum != 0) { accumulate = alias_port; @@ -689,7 +802,7 @@ UdpAliasIn(struct ip *pip) sptr = (u_short *) &original_address; accumulate -= *sptr++; accumulate -= *sptr; - ADJUST_CHECKSUM(accumulate, ud->uh_sum) + ADJUST_CHECKSUM(accumulate, ud->uh_sum); } /* Restore original IP address */ @@ -724,7 +837,7 @@ UdpAliasOut(struct ip *pip) link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, ud->uh_sport, ud->uh_dport, - IPPROTO_UDP); + IPPROTO_UDP, 1); if (link != NULL) { u_short alias_port; @@ -733,23 +846,17 @@ UdpAliasOut(struct ip *pip) alias_address = GetAliasAddress(link); alias_port = GetAliasPort(link); - if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) - AliasHandleCUSeeMeOut(pip, link); - +/* Special processing for IP encoding protocols */ + if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER) + AliasHandleCUSeeMeOut(pip, link); /* If NETBIOS Datagram, It should be alias address in UDP Data, too */ - if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER ) - { - AliasHandleUdpNbt(pip, link, &alias_address, alias_port); - } else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER - || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER ) - { - AliasHandleUdpNbtNS(pip, link, - &pip->ip_src, - &ud->uh_sport, - &alias_address, - &alias_port); - } + else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER) + AliasHandleUdpNbt(pip, link, &alias_address, alias_port); + else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER + || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER) + AliasHandleUdpNbtNS(pip, link, &pip->ip_src, &ud->uh_sport, + &alias_address, &alias_port); /* If UDP checksum is not zero, adjust since source port is */ /* being aliased and source address is being altered */ @@ -766,7 +873,7 @@ UdpAliasOut(struct ip *pip) sptr = (u_short *) &alias_address; accumulate -= *sptr++; accumulate -= *sptr; - ADJUST_CHECKSUM(accumulate, ud->uh_sum) + ADJUST_CHECKSUM(accumulate, ud->uh_sum); } /* Put alias port in UDP header */ @@ -796,7 +903,8 @@ TcpAliasIn(struct ip *pip) link = FindUdpTcpIn(pip->ip_src, pip->ip_dst, tc->th_sport, tc->th_dport, - IPPROTO_TCP); + IPPROTO_TCP, + !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)); if (link != NULL) { struct in_addr alias_address; @@ -807,6 +915,11 @@ TcpAliasIn(struct ip *pip) int accumulate; u_short *sptr; +/* Special processing for IP encoding protocols */ + if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER + || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER) + AliasHandlePptpIn(pip, link); + alias_address = GetAliasAddress(link); original_address = GetOriginalAddress(link); proxy_address = GetProxyAddress(link); @@ -825,7 +938,7 @@ TcpAliasIn(struct ip *pip) accumulate -= *sptr++; accumulate -= *sptr; -/* If this is a proxy, then modify the tcp source port and +/* If this is a proxy, then modify the TCP source port and checksum accumulation */ if (proxy_port != 0) { @@ -841,7 +954,7 @@ TcpAliasIn(struct ip *pip) accumulate -= *sptr; } -/* See if ack number needs to be modified */ +/* See if ACK number needs to be modified */ if (GetAckModified(link) == 1) { int delta; @@ -912,7 +1025,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) return PKT_ALIAS_OK; /* If this is a transparent proxy, save original destination, - then alter the destination and adust checksums */ + then alter the destination and adjust checksums */ dest_port = tc->th_dport; dest_address = pip->ip_dst; if (proxy_type != 0) @@ -946,7 +1059,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) link = FindUdpTcpOut(pip->ip_src, pip->ip_dst, tc->th_sport, tc->th_dport, - IPPROTO_TCP); + IPPROTO_TCP, 1); if (link !=NULL) { u_short alias_port; @@ -967,16 +1080,24 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) alias_port = GetAliasPort(link); alias_address = GetAliasAddress(link); -/* Monitor tcp connection state */ +/* Monitor TCP connection state */ TcpMonitorOut(pip, link); /* Special processing for IP encoding protocols */ if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER) AliasHandleFtpOut(pip, link, maxpacketsize); - if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1 + else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1 || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2) AliasHandleIrcOut(pip, link, maxpacketsize); + else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1 + || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1 + || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2 + || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2) + AliasHandleRtspOut(pip, link, maxpacketsize); + else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER + || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER) + AliasHandlePptpOut(pip, link); /* Adjust TCP checksum since source port is being aliased */ /* and source address is being altered */ @@ -1009,7 +1130,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) } } - ADJUST_CHECKSUM(accumulate, tc->th_sum) + ADJUST_CHECKSUM(accumulate, tc->th_sum); /* Change source address */ sptr = (u_short *) &(pip->ip_src); @@ -1020,7 +1141,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) accumulate -= *sptr++; accumulate -= *sptr; - ADJUST_CHECKSUM(accumulate, pip->ip_sum) + ADJUST_CHECKSUM(accumulate, pip->ip_sum); return(PKT_ALIAS_OK); } @@ -1037,7 +1158,7 @@ TcpAliasOut(struct ip *pip, int maxpacketsize) The packet aliasing module has a limited ability for handling IP fragments. If the ICMP, TCP or UDP header is in the first fragment -received, then the id number of the IP packet is saved, and other +received, then the ID number of the IP packet is saved, and other fragments are identified according to their ID number and IP address they were sent from. Pointers to unresolved fragments can also be saved and recalled when a header fragment is seen. @@ -1098,6 +1219,7 @@ FragmentOut(struct ip *pip) PacketAliasFragmentIn() PacketAliasIn() PacketAliasOut() + PacketUnaliasOut() (prototypes in alias.h) */ @@ -1174,8 +1296,12 @@ PacketAliasIn(char *ptr, int maxpacketsize) struct ip *pip; int iresult; - if (packetAliasMode & PKT_ALIAS_REVERSE) - return PacketAliasOut(ptr, maxpacketsize); + if (packetAliasMode & PKT_ALIAS_REVERSE) { + packetAliasMode &= ~PKT_ALIAS_REVERSE; + iresult = PacketAliasOut(ptr, maxpacketsize); + packetAliasMode |= PKT_ALIAS_REVERSE; + return iresult; + } HouseKeeping(); ClearCheckNewLink(); @@ -1202,7 +1328,14 @@ PacketAliasIn(char *ptr, int maxpacketsize) iresult = TcpAliasIn(pip); break; case IPPROTO_GRE: - iresult = PptpAliasIn(pip); + if (packetAliasMode & PKT_ALIAS_PROXY_ONLY || + AliasHandlePptpGreIn(pip) == 0) + iresult = PKT_ALIAS_OK; + else + iresult = ProtoAliasIn(pip); + break; + default: + iresult = ProtoAliasIn(pip); break; } @@ -1256,8 +1389,12 @@ PacketAliasOut(char *ptr, /* valid IP packet */ struct in_addr addr_save; struct ip *pip; - if (packetAliasMode & PKT_ALIAS_REVERSE) - return PacketAliasIn(ptr, maxpacketsize); + if (packetAliasMode & PKT_ALIAS_REVERSE) { + packetAliasMode &= ~PKT_ALIAS_REVERSE; + iresult = PacketAliasIn(ptr, maxpacketsize); + packetAliasMode |= PKT_ALIAS_REVERSE; + return iresult; + } HouseKeeping(); ClearCheckNewLink(); @@ -1271,7 +1408,7 @@ PacketAliasOut(char *ptr, /* valid IP packet */ addr_save = GetDefaultAliasAddress(); if (packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) { - unsigned int addr; + u_long addr; int iclass; iclass = 0; @@ -1303,8 +1440,14 @@ PacketAliasOut(char *ptr, /* valid IP packet */ case IPPROTO_TCP: iresult = TcpAliasOut(pip, maxpacketsize); break; - case IPPROTO_GRE: - iresult = PptpAliasOut(pip); + case IPPROTO_GRE: + if (AliasHandlePptpGreOut(pip) == 0) + iresult = PKT_ALIAS_OK; + else + iresult = ProtoAliasOut(pip); + break; + default: + iresult = ProtoAliasOut(pip); break; } } @@ -1316,3 +1459,124 @@ PacketAliasOut(char *ptr, /* valid IP packet */ SetDefaultAliasAddress(addr_save); return(iresult); } + +int +PacketUnaliasOut(char *ptr, /* valid IP packet */ + int maxpacketsize /* for error checking */ + ) +{ + struct ip *pip; + struct icmp *ic; + struct udphdr *ud; + struct tcphdr *tc; + struct alias_link *link; + int iresult = PKT_ALIAS_IGNORED; + + pip = (struct ip *) ptr; + + /* Defense against mangled packets */ + if (ntohs(pip->ip_len) > maxpacketsize + || (pip->ip_hl<<2) > maxpacketsize) + return(iresult); + + ud = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); + tc = (struct tcphdr *) ud; + ic = (struct icmp *) ud; + + /* Find a link */ + if (pip->ip_p == IPPROTO_UDP) + link = FindUdpTcpIn(pip->ip_dst, pip->ip_src, + ud->uh_dport, ud->uh_sport, + IPPROTO_UDP, 0); + else if (pip->ip_p == IPPROTO_TCP) + link = FindUdpTcpIn(pip->ip_dst, pip->ip_src, + tc->th_dport, tc->th_sport, + IPPROTO_TCP, 0); + else if (pip->ip_p == IPPROTO_ICMP) + link = FindIcmpIn(pip->ip_dst, pip->ip_src, ic->icmp_id, 0); + else + link = NULL; + + /* Change it from an aliased packet to an unaliased packet */ + if (link != NULL) + { + if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) + { + u_short *sptr; + int accumulate; + struct in_addr original_address; + u_short original_port; + + original_address = GetOriginalAddress(link); + original_port = GetOriginalPort(link); + + /* Adjust TCP/UDP checksum */ + sptr = (u_short *) &(pip->ip_src); + accumulate = *sptr++; + accumulate += *sptr; + sptr = (u_short *) &original_address; + accumulate -= *sptr++; + accumulate -= *sptr; + + if (pip->ip_p == IPPROTO_UDP) { + accumulate += ud->uh_sport; + accumulate -= original_port; + ADJUST_CHECKSUM(accumulate, ud->uh_sum); + } else { + accumulate += tc->th_sport; + accumulate -= original_port; + ADJUST_CHECKSUM(accumulate, tc->th_sum); + } + + /* Adjust IP checksum */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_src, + 2); + + /* Un-alias source address and port number */ + pip->ip_src = original_address; + if (pip->ip_p == IPPROTO_UDP) + ud->uh_sport = original_port; + else + tc->th_sport = original_port; + + iresult = PKT_ALIAS_OK; + + } else if (pip->ip_p == IPPROTO_ICMP) { + + u_short *sptr; + int accumulate; + struct in_addr original_address; + u_short original_id; + + original_address = GetOriginalAddress(link); + original_id = GetOriginalPort(link); + + /* Adjust ICMP checksum */ + sptr = (u_short *) &(pip->ip_src); + accumulate = *sptr++; + accumulate += *sptr; + sptr = (u_short *) &original_address; + accumulate -= *sptr++; + accumulate -= *sptr; + accumulate += ic->icmp_id; + accumulate -= original_id; + ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); + + /* Adjust IP checksum */ + DifferentialChecksum(&pip->ip_sum, + (u_short *) &original_address, + (u_short *) &pip->ip_src, + 2); + + /* Un-alias source address and port number */ + pip->ip_src = original_address; + ic->icmp_id = original_id; + + iresult = PKT_ALIAS_OK; + } + } + return(iresult); + +} diff --git a/alias/alias.h b/alias/alias.h index 4e0391f..02d332d 100644 --- a/alias/alias.h +++ b/alias/alias.h @@ -1,22 +1,63 @@ -/*lint -save -library Flexelint comment for external headers */ - /* - Alias.h defines the outside world interfaces for the packet - aliasing software. - - This software is placed into the public domain with no restrictions - on its distribution. - - $Id: alias.h,v 1.1.1.1 2000/01/11 01:48:42 wsanchez Exp $ -*/ - + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias.h,v 1.12.2.4 2001/08/01 09:36:40 obrien Exp $ + */ + +/*- + * Alias.h defines the outside world interfaces for the packet aliasing + * software. + * + * This software is placed into the public domain with no restrictions on its + * distribution. + */ #ifndef _ALIAS_H_ -#define _ALIAS_H_ - -#ifndef NULL -#define NULL 0 -#endif +#define _ALIAS_H_ /* Alias link representative (incomplete struct) */ struct alias_link; @@ -48,6 +89,9 @@ struct alias_link; extern int PacketAliasOut(char *, int maxpacketsize); + extern int + PacketUnaliasOut(char *, int maxpacketsize); + /* Port and Address Redirection */ extern struct alias_link * PacketAliasRedirectPort(struct in_addr, u_short, @@ -56,8 +100,15 @@ struct alias_link; u_char); extern int - PacketAliasPptp(struct in_addr); + PacketAliasAddServer(struct alias_link *link, + struct in_addr addr, + u_short port); + extern struct alias_link * + PacketAliasRedirectProto(struct in_addr, + struct in_addr, + struct in_addr, + u_char); extern struct alias_link * PacketAliasRedirectAddr(struct in_addr, @@ -92,7 +143,7 @@ struct alias_link; /********************** Mode flags ********************/ -/* Set these flags using SetPacketAliasMode() */ +/* Set these flags using PacketAliasSetMode() */ /* If PKT_ALIAS_LOG is set, a message will be printed to /var/log/alias.log every time a link is created or deleted. This @@ -105,7 +156,7 @@ struct alias_link; #define PKT_ALIAS_DENY_INCOMING 0x02 /* If PKT_ALIAS_SAME_PORTS is set, packets will be attempted sent from - the same port as they originated on. This allows eg rsh to work + the same port as they originated on. This allows e.g. rsh to work *99% of the time*, but _not_ 100%. (It will be slightly flakey instead of not working at all.) This mode bit is set by PacketAliasInit(), so it is a default mode of operation. */ @@ -117,13 +168,12 @@ struct alias_link; port it chooses. This will avoid interference with the host machine. Fully specified links do not require this. This bit is set after a call to PacketAliasInit(), so it is a default - mode of operation.*/ + mode of operation. */ #define PKT_ALIAS_USE_SOCKETS 0x08 -/* If PKT_ALIAS_UNREGISTERED_ONLY is set, then only packets with with - unregistered source addresses will be aliased (along with those - of the ppp host maching itself. Private addresses are those - in the following ranges: +/* If PKT_ALIAS_UNREGISTERED_ONLY is set, then only packets with + unregistered source addresses will be aliased. Private + addresses are those in the following ranges: 10.0.0.0 -> 10.255.255.255 172.16.0.0 -> 172.31.255.255 192.168.0.0 -> 192.168.255.255 */ @@ -132,7 +182,7 @@ struct alias_link; /* If PKT_ALIAS_RESET_ON_ADDR_CHANGE is set, then the table of dynamic aliasing links will be reset whenever PacketAliasSetAddress() changes the default aliasing address. If the default aliasing - address is left unchanged by this functions call, then the + address is left unchanged by this function call, then the table of dynamic aliasing links will be left intact. This bit is set after a call to PacketAliasInit(). */ #define PKT_ALIAS_RESET_ON_ADDR_CHANGE 0x20 @@ -144,7 +194,7 @@ struct alias_link; controlled by PacketAliasSetFWBase(base, size). The hole will be attached to that particular alias_link, so when the link goes away so do the hole. */ -#define PKT_ALIAS_PUNCH_FW 0x40 +#define PKT_ALIAS_PUNCH_FW 0x100 #endif /* If PKT_ALIAS_PROXY_ONLY is set, then NAT will be disabled and only @@ -163,4 +213,4 @@ struct alias_link; #define PKT_ALIAS_FOUND_HEADER_FRAGMENT 4 #endif -/*lint -restore */ +/* lint -restore */ diff --git a/alias/alias_cuseeme.c b/alias/alias_cuseeme.c index a78f041..a19be96 100644 --- a/alias/alias_cuseeme.c +++ b/alias/alias_cuseeme.c @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ /*- * Copyright (c) 1998 Brian Somers * with the aid of code written by @@ -25,7 +46,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: alias_cuseeme.c,v 1.1.1.1 2000/01/11 01:48:42 wsanchez Exp $ + * Based upon: + * $FreeBSD: src/lib/libalias/alias_cuseeme.c,v 1.2.2.2 2000/10/31 08:48:21 ru Exp $ */ #include @@ -70,7 +92,7 @@ AliasHandleCUSeeMeOut(struct ip *pip, struct alias_link *link) struct udphdr *ud; ud = (struct udphdr *)((char *)pip + (pip->ip_hl << 2)); - if(ud->uh_ulen >= sizeof(struct cu_header)) { + if (ntohs(ud->uh_ulen) - sizeof(struct udphdr) >= sizeof(struct cu_header)) { struct cu_header *cu; struct alias_link *cu_link; @@ -79,7 +101,7 @@ AliasHandleCUSeeMeOut(struct ip *pip, struct alias_link *link) cu->addr = (u_int32_t)GetAliasAddress(link).s_addr; cu_link = FindUdpTcpOut(pip->ip_src, GetDestAddress(link), - ud->uh_dport, 0, IPPROTO_UDP); + ud->uh_dport, 0, IPPROTO_UDP, 1); #ifndef NO_FW_PUNCH if (cu_link) @@ -104,7 +126,7 @@ AliasHandleCUSeeMeIn(struct ip *pip, struct in_addr original_addr) cu = (struct cu_header *)(ud + 1); oc = (struct oc_header *)(cu + 1); ci = (struct client_info *)(oc + 1); - end = (char *)cu + ud->uh_ulen; + end = (char *)ud + ntohs(ud->uh_ulen); if ((char *)oc <= end) { if(cu->dest_addr) diff --git a/alias/alias_db.c b/alias/alias_db.c index d01188e..e67705b 100644 --- a/alias/alias_db.c +++ b/alias/alias_db.c @@ -1,4 +1,54 @@ -/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_db.c,v 1.21.2.12 2001/08/21 03:50:25 brian Exp $ + */ + +/* Alias_db.c encapsulates all data structures used for storing packet aliasing data. Other parts of the aliasing software access data through functions provided in this file. @@ -18,9 +68,6 @@ can be deleted after a certain amount of time. - This software is placed into the public domain with no restrictions - on its distribution. - Initial version: August, 1996 (cjm) Version 1.4: September 16, 1996 (cjm) @@ -32,7 +79,7 @@ Version 1.7: January 9, 1997 (cjm) Fragment handling simplified. Saves pointers for unresolved fragments. - Permits links for unspecied remote ports + Permits links for unspecified remote ports or unspecified remote addresses. Fixed bug which did not properly zero port table entries after a link was deleted. @@ -48,8 +95,8 @@ machine will will not have their port number aliased unless it conflicts with an aliasing port already being used. (cjm) - All options earlier being #ifdef'ed now are available through - a new interface, SetPacketAliasMode(). This allow run time + All options earlier being #ifdef'ed are now available through + a new interface, SetPacketAliasMode(). This allows run time control (which is now available in PPP+pktAlias through the 'alias' keyword). (ee) @@ -78,7 +125,7 @@ (192.168.0.2, port 21) <-> alias port 3604, known dest addr unknown dest port - These permament links allow for incoming connections to + These permanent links allow for incoming connections to machines on the local network. They can be given with a user-chosen amount of specificity, with increasing specificity meaning more security. (cjm) @@ -103,16 +150,27 @@ version of PacketAliasPermanentLink(). The second function implements static network address translation. + Version 3.2: July, 2000 (salander and satoh) + Added FindNewPortGroup to get contiguous range of port values. + + Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing + link but not actually add one. + + Added FindRtspOut, which is closely derived from FindUdpTcpOut, + except that the alias port (from FindNewPortGroup) is provided + as input. + See HISTORY file for additional revisions. */ /* System include files */ +#include #include #include #include -#include +#include #include #include #include @@ -142,9 +200,10 @@ #define ALIAS_CLEANUP_INTERVAL_SECS 60 #define ALIAS_CLEANUP_MAX_SPOKES 30 -/* Timouts (in seconds) for different link types) */ +/* Timeouts (in seconds) for different link types */ #define ICMP_EXPIRE_TIME 60 #define UDP_EXPIRE_TIME 60 +#define PROTO_EXPIRE_TIME 60 #define FRAGMENT_ID_EXPIRE_TIME 10 #define FRAGMENT_PTR_EXPIRE_TIME 30 @@ -190,25 +249,25 @@ The link record is identified by the source address/port and the destination address/port. In the case of an ICMP echo request, the source port is treated as being equivalent - with the 16-bit id number of the ICMP packet. + with the 16-bit ID number of the ICMP packet. The link record also can store some auxiliary data. For TCP connections that have had sequence and acknowledgment modifications, data space is available to track these changes. - A state field is used to keep track in changes to the tcp - connection state. Id numbers of fragments can also be + A state field is used to keep track in changes to the TCP + connection state. ID numbers of fragments can also be stored in the auxiliary space. Pointers to unresolved - framgents can also be stored. + fragments can also be stored. The link records support two independent chainings. Lookup tables for input and out tables hold the initial pointers the link chains. On input, the lookup table indexes on alias port and link type. On output, the lookup table indexes on - source addreess, destination address, source port, destination + source address, destination address, source port, destination port and link type. */ -struct ack_data_record /* used to save changes to ack/seq numbers */ +struct ack_data_record /* used to save changes to ACK/sequence numbers */ { u_long ack_old; u_long ack_new; @@ -216,16 +275,16 @@ struct ack_data_record /* used to save changes to ack/seq numbers */ int active; }; -struct tcp_state /* Information about tcp connection */ +struct tcp_state /* Information about TCP connection */ { int in; /* State for outside -> inside */ int out; /* State for inside -> outside */ - int index; /* Index to ack data array */ - int ack_modified; /* Indicates whether ack and seq numbers */ + int index; /* Index to ACK data array */ + int ack_modified; /* Indicates whether ACK and sequence numbers */ /* been modified */ }; -#define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes +#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes saved for a modified TCP stream */ struct tcp_dat { @@ -234,6 +293,13 @@ struct tcp_dat int fwhole; /* Which firewall record is used for this hole? */ }; +struct server /* LSNAT server pool (circular list) */ +{ + struct in_addr addr; + u_short port; + struct server *next; +}; + struct alias_link /* Main data structure */ { struct in_addr src_addr; /* Address and port information */ @@ -244,16 +310,18 @@ struct alias_link /* Main data structure */ u_short dst_port; u_short alias_port; u_short proxy_port; + struct server *server; - int link_type; /* Type of link: tcp, udp, icmp, frag */ + int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */ /* values for link_type */ -#define LINK_ICMP 1 -#define LINK_UDP 2 -#define LINK_TCP 3 -#define LINK_FRAGMENT_ID 4 -#define LINK_FRAGMENT_PTR 5 -#define LINK_ADDR 6 +#define LINK_ICMP IPPROTO_ICMP +#define LINK_UDP IPPROTO_UDP +#define LINK_TCP IPPROTO_TCP +#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) +#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) +#define LINK_ADDR (IPPROTO_MAX + 3) +#define LINK_PPTP (IPPROTO_MAX + 4) int flags; /* indicates special characteristics */ @@ -263,18 +331,15 @@ struct alias_link /* Main data structure */ #define LINK_PERMANENT 0x04 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ #define LINK_UNFIREWALLED 0x08 +#define LINK_LAST_LINE_CRLF_TERMED 0x10 int timestamp; /* Time link was last accessed */ int expire_time; /* Expire time for link */ int sockfd; /* socket descriptor */ - u_int start_point_out; /* Index number in output lookup table */ - u_int start_point_in; - struct alias_link *next_out; /* Linked list pointers for input and */ - struct alias_link *last_out; /* output tables */ - struct alias_link *next_in; /* . */ - struct alias_link *last_in; /* . */ + LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */ + LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */ union /* Auxiliary data */ { @@ -307,16 +372,18 @@ static struct in_addr targetAddress; /* IP address incoming packets */ static struct in_addr nullAddress; /* Used as a dummy parameter for */ /* some function calls */ -static struct alias_link * +static LIST_HEAD(, alias_link) linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ /* chains of link records. Each */ -static struct alias_link * /* link record is doubly indexed */ +static LIST_HEAD(, alias_link) /* link record is doubly indexed */ linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ /* tables. */ static int icmpLinkCount; /* Link statistics */ static int udpLinkCount; static int tcpLinkCount; +static int pptpLinkCount; +static int protoLinkCount; static int fragmentIdLinkCount; static int fragmentPtrLinkCount; static int sockCount; @@ -350,11 +417,6 @@ static int fireWallFD = -1; /* File descriptor to be able to */ /* flag. */ #endif -static int pptpAliasFlag; /* Indicates if PPTP aliasing is */ - /* on or off */ -static struct in_addr pptpAliasAddr; /* Address of source of PPTP */ - /* packets. */ - @@ -365,9 +427,9 @@ static struct in_addr pptpAliasAddr; /* Address of source of PPTP */ Lookup table starting points: StartPointIn() -- link table initial search point for - outgoing packets - StartPointOut() -- port table initial search point for incoming packets + StartPointOut() -- link table initial search point for + outgoing packets Miscellaneous: SeqDiff() -- difference between two TCP sequences @@ -404,7 +466,8 @@ StartPointIn(struct in_addr alias_addr, u_int n; n = alias_addr.s_addr; - n += alias_port; + if (link_type != LINK_PPTP) + n += alias_port; n += link_type; return(n % LINK_TABLE_IN_SIZE); } @@ -418,8 +481,10 @@ StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, n = src_addr.s_addr; n += dst_addr.s_addr; - n += src_port; - n += dst_port; + if (link_type != LINK_PPTP) { + n += src_port; + n += dst_port; + } n += link_type; return(n % LINK_TABLE_OUT_SIZE); @@ -447,16 +512,20 @@ ShowAliasStats(void) if (monitorFile) { - fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d", + fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", icmpLinkCount, udpLinkCount, tcpLinkCount, + pptpLinkCount, + protoLinkCount, fragmentIdLinkCount, fragmentPtrLinkCount); fprintf(monitorFile, " / tot=%d (sock=%d)\n", icmpLinkCount + udpLinkCount + tcpLinkCount + + pptpLinkCount + + protoLinkCount + fragmentIdLinkCount + fragmentPtrLinkCount, sockCount); @@ -485,6 +554,9 @@ Link creation and deletion: Link search: FindLinkOut() - find link for outgoing packets FindLinkIn() - find link for incoming packets + +Port search: + FindNewPortGroup() - find an available group of ports */ /* Local prototypes */ @@ -508,7 +580,7 @@ ReLink(struct alias_link *, u_short, u_short, int, int); static struct alias_link * -FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); +FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int); static struct alias_link * FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); @@ -516,11 +588,14 @@ FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); #define ALIAS_PORT_BASE 0x08000 #define ALIAS_PORT_MASK 0x07fff +#define ALIAS_PORT_MASK_EVEN 0x07ffe #define GET_NEW_PORT_MAX_ATTEMPTS 20 #define GET_ALIAS_PORT -1 #define GET_ALIAS_ID GET_ALIAS_PORT +#define FIND_EVEN_ALIAS_BASE 1 + /* GetNewPort() allocates port numbers. Note that if a port number is already in use, that does not mean that it cannot be used by another link concurrently. This is because GetNewPort() looks for @@ -540,7 +615,7 @@ GetNewPort(struct alias_link *link, int alias_port_param) the port number. GetNewPort() will return this number without check that it is in use. - Whis this parameter is -1, it indicates to get a randomly + When this parameter is GET_ALIAS_PORT, it indicates to get a randomly selected port number. */ @@ -555,7 +630,7 @@ GetNewPort(struct alias_link *link, int alias_port_param) if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { /* - * When the ALIAS_SAME_PORTS option is + * When the PKT_ALIAS_SAME_PORTS option is * chosen, the first try will be the * actual source port. If this is already * in use, the remainder of the trials @@ -607,8 +682,10 @@ GetNewPort(struct alias_link *link, int alias_port_param) if (go_ahead) { - if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS) - && (link->flags & LINK_PARTIALLY_SPECIFIED)) + if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS) + && (link->flags & LINK_PARTIALLY_SPECIFIED) + && ((link->link_type == LINK_TCP) || + (link->link_type == LINK_UDP))) { if (GetSocket(port_net, &link->sockfd, link->link_type)) { @@ -687,6 +764,102 @@ GetSocket(u_short port_net, int *sockfd, int link_type) } +/* FindNewPortGroup() returns a base port number for an available + range of contiguous port numbers. Note that if a port number + is already in use, that does not mean that it cannot be used by + another link concurrently. This is because FindNewPortGroup() + looks for unused triplets: (dest addr, dest port, alias port). */ + +int +FindNewPortGroup(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short src_port, + u_short dst_port, + u_short port_count, + u_char proto, + u_char align) +{ + int i, j; + int max_trials; + u_short port_sys; + int link_type; + + /* + * Get link_type from protocol + */ + + switch (proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + return (0); + break; + } + + /* + * The aliasing port is automatically selected + * by one of two methods below: + */ + max_trials = GET_NEW_PORT_MAX_ATTEMPTS; + + if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { + /* + * When the ALIAS_SAME_PORTS option is + * chosen, the first try will be the + * actual source port. If this is already + * in use, the remainder of the trials + * will be random. + */ + port_sys = ntohs(src_port); + + } else { + + /* First trial and all subsequent are random. */ + if (align == FIND_EVEN_ALIAS_BASE) + port_sys = random() & ALIAS_PORT_MASK_EVEN; + else + port_sys = random() & ALIAS_PORT_MASK; + + port_sys += ALIAS_PORT_BASE; + } + +/* Port number search */ + for (i = 0; i < max_trials; i++) { + + struct alias_link *search_result; + + for (j = 0; j < port_count; j++) + if (0 != (search_result = FindLinkIn(dst_addr, alias_addr, + dst_port, htons(port_sys + j), + link_type, 0))) + break; + + /* Found a good range, return base */ + if (j == port_count) + return (htons(port_sys)); + + /* Find a new base to try */ + if (align == FIND_EVEN_ALIAS_BASE) + port_sys = random() & ALIAS_PORT_MASK_EVEN; + else + port_sys = random() & ALIAS_PORT_MASK; + + port_sys += ALIAS_PORT_BASE; + } + +#ifdef DEBUG + fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); + fprintf(stderr, "could not find free port(s)\n"); +#endif + + return(0); +} + static void CleanupAliasData(void) { @@ -696,11 +869,11 @@ CleanupAliasData(void) icount = 0; for (i=0; inext_out; + link_next = LIST_NEXT(link, list_out); icount++; DeleteLink(link); link = link_next; @@ -718,26 +891,16 @@ IncrementalCleanup(void) struct alias_link *link; icount = 0; - link = linkTableOut[cleanupIndex++]; + link = LIST_FIRST(&linkTableOut[cleanupIndex++]); while (link != NULL) { int idelta; struct alias_link *link_next; - link_next = link->next_out; + link_next = LIST_NEXT(link, list_out); idelta = timeStamp - link->timestamp; switch (link->link_type) { - case LINK_ICMP: - case LINK_UDP: - case LINK_FRAGMENT_ID: - case LINK_FRAGMENT_PTR: - if (idelta > link->expire_time) - { - DeleteLink(link); - icount++; - } - break; case LINK_TCP: if (idelta > link->expire_time) { @@ -752,6 +915,13 @@ IncrementalCleanup(void) } } break; + default: + if (idelta > link->expire_time) + { + DeleteLink(link); + icount++; + } + break; } link = link_next; } @@ -760,44 +930,35 @@ IncrementalCleanup(void) cleanupIndex = 0; } -void +static void DeleteLink(struct alias_link *link) { - struct alias_link *link_last; - struct alias_link *link_next; /* Don't do anything if the link is marked permanent */ if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) return; #ifndef NO_FW_PUNCH -/* Delete associatied firewall hole, if any */ +/* Delete associated firewall hole, if any */ ClearFWHole(link); #endif -/* Adjust output table pointers */ - link_last = link->last_out; - link_next = link->next_out; +/* Free memory allocated for LSNAT server pool */ + if (link->server != NULL) { + struct server *head, *curr, *next; - if (link_last != NULL) - link_last->next_out = link_next; - else - linkTableOut[link->start_point_out] = link_next; + head = curr = link->server; + do { + next = curr->next; + free(curr); + } while ((curr = next) != head); + } - if (link_next != NULL) - link_next->last_out = link_last; +/* Adjust output table pointers */ + LIST_REMOVE(link, list_out); /* Adjust input table pointers */ - link_last = link->last_in; - link_next = link->next_in; - - if (link_last != NULL) - link_last->next_in = link_next; - else - linkTableIn[link->start_point_in] = link_next; - - if (link_next != NULL) - link_next->last_in = link_last; + LIST_REMOVE(link, list_in); /* Close socket, if one has been allocated */ if (link->sockfd != -1) @@ -817,8 +978,10 @@ DeleteLink(struct alias_link *link) break; case LINK_TCP: tcpLinkCount--; - if (link->data.tcp != NULL) - free(link->data.tcp); + free(link->data.tcp); + break; + case LINK_PPTP: + pptpLinkCount--; break; case LINK_FRAGMENT_ID: fragmentIdLinkCount--; @@ -828,6 +991,11 @@ DeleteLink(struct alias_link *link) if (link->data.frag_ptr != NULL) free(link->data.frag_ptr); break; + case LINK_ADDR: + break; + default: + protoLinkCount--; + break; } /* Free memory */ @@ -852,30 +1020,19 @@ AddLink(struct in_addr src_addr, { /* chosen. If greater than */ u_int start_point; /* zero, equal to alias port */ struct alias_link *link; - struct alias_link *first_link; link = malloc(sizeof(struct alias_link)); if (link != NULL) { - /* If either the aliasing address or source address are - equal to the default device address (equal to the - global variable aliasAddress), then set the alias - address field of the link record to zero */ - - if (src_addr.s_addr == aliasAddress.s_addr) - src_addr.s_addr = 0; - - if (alias_addr.s_addr == aliasAddress.s_addr) - alias_addr.s_addr = 0; - /* Basic initialization */ link->src_addr = src_addr; link->dst_addr = dst_addr; link->alias_addr = alias_addr; - link->proxy_addr.s_addr = 0; + link->proxy_addr.s_addr = INADDR_ANY; link->src_port = src_port; link->dst_port = dst_port; link->proxy_port = 0; + link->server = NULL; link->link_type = link_type; link->sockfd = -1; link->flags = 0; @@ -893,16 +1050,24 @@ AddLink(struct in_addr src_addr, case LINK_TCP: link->expire_time = TCP_EXPIRE_INITIAL; break; + case LINK_PPTP: + link->flags |= LINK_PERMANENT; /* no timeout. */ + break; case LINK_FRAGMENT_ID: link->expire_time = FRAGMENT_ID_EXPIRE_TIME; break; case LINK_FRAGMENT_PTR: link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; break; + case LINK_ADDR: + break; + default: + link->expire_time = PROTO_EXPIRE_TIME; + break; } /* Determine alias flags */ - if (dst_addr.s_addr == 0) + if (dst_addr.s_addr == INADDR_ANY) link->flags |= LINK_UNKNOWN_DEST_ADDR; if (dst_port == 0) link->flags |= LINK_UNKNOWN_DEST_PORT; @@ -914,33 +1079,6 @@ AddLink(struct in_addr src_addr, return(NULL); } - /* Set up pointers for output lookup table */ - start_point = StartPointOut(src_addr, dst_addr, - src_port, dst_port, link_type); - first_link = linkTableOut[start_point]; - - link->last_out = NULL; - link->next_out = first_link; - link->start_point_out = start_point; - - if (first_link != NULL) - first_link->last_out = link; - - linkTableOut[start_point] = link; - - /* Set up pointers for input lookup table */ - start_point = StartPointIn(alias_addr, link->alias_port, link_type); - first_link = linkTableIn[start_point]; - - link->last_in = NULL; - link->next_in = first_link; - link->start_point_in = start_point; - - if (first_link != NULL) - first_link->last_in = link; - - linkTableIn[start_point] = link; - /* Link-type dependent initialization */ switch(link_type) { @@ -954,7 +1092,6 @@ AddLink(struct in_addr src_addr, break; case LINK_TCP: aux_tcp = malloc(sizeof(struct tcp_dat)); - link->data.tcp = aux_tcp; if (aux_tcp != NULL) { int i; @@ -967,6 +1104,7 @@ AddLink(struct in_addr src_addr, for (i=0; iack[i].active = 0; aux_tcp->fwhole = -1; + link->data.tcp = aux_tcp; } else { @@ -974,15 +1112,34 @@ AddLink(struct in_addr src_addr, fprintf(stderr, "PacketAlias/AddLink: "); fprintf(stderr, " cannot allocate auxiliary TCP data\n"); #endif + free(link); + return (NULL); } break; + case LINK_PPTP: + pptpLinkCount++; + break; case LINK_FRAGMENT_ID: fragmentIdLinkCount++; break; case LINK_FRAGMENT_PTR: fragmentPtrLinkCount++; break; + case LINK_ADDR: + break; + default: + protoLinkCount++; + break; } + + /* Set up pointers for output lookup table */ + start_point = StartPointOut(src_addr, dst_addr, + src_port, dst_port, link_type); + LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out); + + /* Set up pointers for input lookup table */ + start_point = StartPointIn(alias_addr, link->alias_port, link_type); + LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in); } else { @@ -1018,7 +1175,6 @@ ReLink(struct alias_link *old_link, #ifndef NO_FW_PUNCH if (new_link != NULL && old_link->link_type == LINK_TCP && - old_link->data.tcp && old_link->data.tcp->fwhole > 0) { PunchFWHole(new_link); } @@ -1028,23 +1184,21 @@ ReLink(struct alias_link *old_link, } static struct alias_link * -FindLinkOut(struct in_addr src_addr, +_FindLinkOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short dst_port, - int link_type) + int link_type, + int replace_partial_links) { u_int i; struct alias_link *link; - if (src_addr.s_addr == aliasAddress.s_addr) - src_addr.s_addr = 0; - i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); - link = linkTableOut[i]; - while (link != NULL) + LIST_FOREACH(link, &linkTableOut[i], list_out) { if (link->src_addr.s_addr == src_addr.s_addr + && link->server == NULL && link->dst_addr.s_addr == dst_addr.s_addr && link->dst_port == dst_port && link->src_port == src_port @@ -1053,15 +1207,70 @@ FindLinkOut(struct in_addr src_addr, link->timestamp = timeStamp; break; } - link = link->next_out; + } + +/* Search for partially specified links. */ + if (link == NULL && replace_partial_links) + { + if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) + { + link = _FindLinkOut(src_addr, dst_addr, src_port, 0, + link_type, 0); + if (link == NULL) + link = _FindLinkOut(src_addr, nullAddress, src_port, + dst_port, link_type, 0); + } + if (link == NULL && + (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) + { + link = _FindLinkOut(src_addr, nullAddress, src_port, 0, + link_type, 0); + } + if (link != NULL) + { + link = ReLink(link, + src_addr, dst_addr, link->alias_addr, + src_port, dst_port, link->alias_port, + link_type); + } } return(link); } +static struct alias_link * +FindLinkOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_short src_port, + u_short dst_port, + int link_type, + int replace_partial_links) +{ + struct alias_link *link; -struct alias_link * -FindLinkIn(struct in_addr dst_addr, + link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, + link_type, replace_partial_links); + + if (link == NULL) + { + /* The following allows permanent links to be + specified as using the default source address + (i.e. device interface address) without knowing + in advance what that address is. */ + if (aliasAddress.s_addr != 0 && + src_addr.s_addr == aliasAddress.s_addr) + { + link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, + link_type, replace_partial_links); + } + } + + return(link); +} + + +static struct alias_link * +_FindLinkIn(struct in_addr dst_addr, struct in_addr alias_addr, u_short dst_port, u_short alias_port, @@ -1086,23 +1295,14 @@ FindLinkIn(struct in_addr dst_addr, loop will have to know about this. */ flags_in = 0; - if (dst_addr.s_addr == 0) + if (dst_addr.s_addr == INADDR_ANY) flags_in |= LINK_UNKNOWN_DEST_ADDR; if (dst_port == 0) flags_in |= LINK_UNKNOWN_DEST_PORT; -/* The following allows permanent links to be - be specified as using the default aliasing address - (i.e. device interface address) without knowing - in advance what that address is. */ - - if (alias_addr.s_addr == aliasAddress.s_addr) - alias_addr.s_addr = 0; - /* Search loop */ start_point = StartPointIn(alias_addr, alias_port, link_type); - link = linkTableIn[start_point]; - while (link != NULL) + LIST_FOREACH(link, &linkTableIn[start_point], list_in) { int flags; @@ -1152,46 +1352,76 @@ FindLinkIn(struct in_addr dst_addr, link_unknown_dst_port = link; } } - link = link->next_in; } if (link_fully_specified != NULL) { - return link_fully_specified; + link_fully_specified->timestamp = timeStamp; + link = link_fully_specified; } else if (link_unknown_dst_port != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_port, - link_unknown_dst_port->src_addr, dst_addr, alias_addr, - link_unknown_dst_port->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_port; - } + link = link_unknown_dst_port; else if (link_unknown_dst_addr != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_addr, - link_unknown_dst_addr->src_addr, dst_addr, alias_addr, - link_unknown_dst_addr->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_addr; - } + link = link_unknown_dst_addr; else if (link_unknown_all != NULL) + link = link_unknown_all; + else + return (NULL); + + if (replace_partial_links && + (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) { - return replace_partial_links - ? ReLink(link_unknown_all, - link_unknown_all->src_addr, dst_addr, alias_addr, - link_unknown_all->src_port, dst_port, alias_port, - link_type) - : link_unknown_all; + struct in_addr src_addr; + u_short src_port; + + if (link->server != NULL) { /* LSNAT link */ + src_addr = link->server->addr; + src_port = link->server->port; + link->server = link->server->next; + } else { + src_addr = link->src_addr; + src_port = link->src_port; + } + + link = ReLink(link, + src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port, + link_type); } - else + + return (link); +} + +static struct alias_link * +FindLinkIn(struct in_addr dst_addr, + struct in_addr alias_addr, + u_short dst_port, + u_short alias_port, + int link_type, + int replace_partial_links) +{ + struct alias_link *link; + + link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, + link_type, replace_partial_links); + + if (link == NULL) { - return(NULL); + /* The following allows permanent links to be + specified as using the default aliasing address + (i.e. device interface address) without knowing + in advance what that address is. */ + if (aliasAddress.s_addr != 0 && + alias_addr.s_addr == aliasAddress.s_addr) + { + link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, + link_type, replace_partial_links); + } } + + return(link); } @@ -1204,7 +1434,10 @@ FindLinkIn(struct in_addr dst_addr, FindIcmpIn(), FindIcmpOut() FindFragmentIn1(), FindFragmentIn2() AddFragmentPtrLink(), FindFragmentPtr() + FindProtoIn(), FindProtoOut() FindUdpTcpIn(), FindUdpTcpOut() + AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), + FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() FindOriginalAddress(), FindAliasAddress() (prototypes in alias_local.h) @@ -1214,25 +1447,40 @@ FindLinkIn(struct in_addr dst_addr, struct alias_link * FindIcmpIn(struct in_addr dst_addr, struct in_addr alias_addr, - u_short id_alias) + u_short id_alias, + int create) { - return FindLinkIn(dst_addr, alias_addr, + struct alias_link *link; + + link = FindLinkIn(dst_addr, alias_addr, NO_DEST_PORT, id_alias, LINK_ICMP, 0); + if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) + { + struct in_addr target_addr; + + target_addr = FindOriginalAddress(alias_addr); + link = AddLink(target_addr, dst_addr, alias_addr, + id_alias, NO_DEST_PORT, id_alias, + LINK_ICMP); + } + + return (link); } struct alias_link * FindIcmpOut(struct in_addr src_addr, struct in_addr dst_addr, - u_short id) + u_short id, + int create) { struct alias_link * link; link = FindLinkOut(src_addr, dst_addr, id, NO_DEST_PORT, - LINK_ICMP); - if (link == NULL) + LINK_ICMP, 0); + if (link == NULL && create) { struct in_addr alias_addr; @@ -1299,12 +1547,63 @@ FindFragmentPtr(struct in_addr dst_addr, } +struct alias_link * +FindProtoIn(struct in_addr dst_addr, + struct in_addr alias_addr, + u_char proto) +{ + struct alias_link *link; + + link = FindLinkIn(dst_addr, alias_addr, + NO_DEST_PORT, 0, + proto, 1); + + if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) + { + struct in_addr target_addr; + + target_addr = FindOriginalAddress(alias_addr); + link = AddLink(target_addr, dst_addr, alias_addr, + NO_SRC_PORT, NO_DEST_PORT, 0, + proto); + } + + return (link); +} + + +struct alias_link * +FindProtoOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_char proto) +{ + struct alias_link *link; + + link = FindLinkOut(src_addr, dst_addr, + NO_SRC_PORT, NO_DEST_PORT, + proto, 1); + + if (link == NULL) + { + struct in_addr alias_addr; + + alias_addr = FindAliasAddress(src_addr); + link = AddLink(src_addr, dst_addr, alias_addr, + NO_SRC_PORT, NO_DEST_PORT, 0, + proto); + } + + return (link); +} + + struct alias_link * FindUdpTcpIn(struct in_addr dst_addr, struct in_addr alias_addr, u_short dst_port, u_short alias_port, - u_char proto) + u_char proto, + int create) { int link_type; struct alias_link *link; @@ -1324,11 +1623,9 @@ FindUdpTcpIn(struct in_addr dst_addr, link = FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, - link_type, 1); + link_type, create); - if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) - && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) - && link == NULL) + if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { struct in_addr target_addr; @@ -1347,7 +1644,8 @@ FindUdpTcpOut(struct in_addr src_addr, struct in_addr dst_addr, u_short src_port, u_short dst_port, - u_char proto) + u_char proto, + int create) { int link_type; struct alias_link *link; @@ -1365,9 +1663,9 @@ FindUdpTcpOut(struct in_addr src_addr, break; } - link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); + link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create); - if (link == NULL) + if (link == NULL && create) { struct in_addr alias_addr; @@ -1381,6 +1679,137 @@ FindUdpTcpOut(struct in_addr src_addr, } +struct alias_link * +AddPptp(struct in_addr src_addr, + struct in_addr dst_addr, + struct in_addr alias_addr, + u_int16_t src_call_id) +{ + struct alias_link *link; + + link = AddLink(src_addr, dst_addr, alias_addr, + src_call_id, 0, GET_ALIAS_PORT, + LINK_PPTP); + + return (link); +} + + +struct alias_link * +FindPptpOutByCallId(struct in_addr src_addr, + struct in_addr dst_addr, + u_int16_t src_call_id) +{ + u_int i; + struct alias_link *link; + + i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); + LIST_FOREACH(link, &linkTableOut[i], list_out) + if (link->link_type == LINK_PPTP && + link->src_addr.s_addr == src_addr.s_addr && + link->dst_addr.s_addr == dst_addr.s_addr && + link->src_port == src_call_id) + break; + + return (link); +} + + +struct alias_link * +FindPptpOutByPeerCallId(struct in_addr src_addr, + struct in_addr dst_addr, + u_int16_t dst_call_id) +{ + u_int i; + struct alias_link *link; + + i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); + LIST_FOREACH(link, &linkTableOut[i], list_out) + if (link->link_type == LINK_PPTP && + link->src_addr.s_addr == src_addr.s_addr && + link->dst_addr.s_addr == dst_addr.s_addr && + link->dst_port == dst_call_id) + break; + + return (link); +} + + +struct alias_link * +FindPptpInByCallId(struct in_addr dst_addr, + struct in_addr alias_addr, + u_int16_t dst_call_id) +{ + u_int i; + struct alias_link *link; + + i = StartPointIn(alias_addr, 0, LINK_PPTP); + LIST_FOREACH(link, &linkTableIn[i], list_in) + if (link->link_type == LINK_PPTP && + link->dst_addr.s_addr == dst_addr.s_addr && + link->alias_addr.s_addr == alias_addr.s_addr && + link->dst_port == dst_call_id) + break; + + return (link); +} + + +struct alias_link * +FindPptpInByPeerCallId(struct in_addr dst_addr, + struct in_addr alias_addr, + u_int16_t alias_call_id) +{ + struct alias_link *link; + + link = FindLinkIn(dst_addr, alias_addr, + 0/* any */, alias_call_id, + LINK_PPTP, 0); + + + return (link); +} + + +struct alias_link * +FindRtspOut(struct in_addr src_addr, + struct in_addr dst_addr, + u_short src_port, + u_short alias_port, + u_char proto) +{ + int link_type; + struct alias_link *link; + + switch (proto) + { + case IPPROTO_UDP: + link_type = LINK_UDP; + break; + case IPPROTO_TCP: + link_type = LINK_TCP; + break; + default: + return NULL; + break; + } + + link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1); + + if (link == NULL) + { + struct in_addr alias_addr; + + alias_addr = FindAliasAddress(src_addr); + link = AddLink(src_addr, dst_addr, alias_addr, + src_port, 0, alias_port, + link_type); + } + + return(link); +} + + struct in_addr FindOriginalAddress(struct in_addr alias_addr) { @@ -1391,14 +1820,22 @@ FindOriginalAddress(struct in_addr alias_addr) if (link == NULL) { newDefaultLink = 1; - if (targetAddress.s_addr != 0) - return targetAddress; - else + if (targetAddress.s_addr == INADDR_ANY) return alias_addr; + else if (targetAddress.s_addr == INADDR_NONE) + return aliasAddress; + else + return targetAddress; } else { - if (link->src_addr.s_addr == 0) + if (link->server != NULL) { /* LSNAT link */ + struct in_addr src_addr; + + src_addr = link->server->addr; + link->server = link->server->next; + return (src_addr); + } else if (link->src_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->src_addr; @@ -1412,14 +1849,14 @@ FindAliasAddress(struct in_addr original_addr) struct alias_link *link; link = FindLinkOut(original_addr, nullAddress, - 0, 0, LINK_ADDR); + 0, 0, LINK_ADDR, 0); if (link == NULL) { return aliasAddress; } else { - if (link->alias_addr.s_addr == 0) + if (link->alias_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->alias_addr; @@ -1437,6 +1874,8 @@ FindAliasAddress(struct in_addr original_addr) GetOriginalPort(), GetAliasPort() SetAckModified(), GetAckModified() GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() + SetLastLineCrlfTermed(), GetLastLineCrlfTermed() + SetDestCallId() */ @@ -1474,22 +1913,19 @@ SetStateIn(struct alias_link *link, int state) /* TCP input state */ switch (state) { case ALIAS_TCP_STATE_DISCONNECTED: - if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { + if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) link->expire_time = TCP_EXPIRE_DEAD; - } else { + else link->expire_time = TCP_EXPIRE_SINGLEDEAD; - } - link->data.tcp->state.in = state; break; case ALIAS_TCP_STATE_CONNECTED: - link->expire_time = TCP_EXPIRE_CONNECTED; - /*FALLTHROUGH*/ - case ALIAS_TCP_STATE_NOT_CONNECTED: - link->data.tcp->state.in = state; + if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) + link->expire_time = TCP_EXPIRE_CONNECTED; break; default: abort(); } + link->data.tcp->state.in = state; } @@ -1499,22 +1935,19 @@ SetStateOut(struct alias_link *link, int state) /* TCP output state */ switch (state) { case ALIAS_TCP_STATE_DISCONNECTED: - if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { + if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) link->expire_time = TCP_EXPIRE_DEAD; - } else { + else link->expire_time = TCP_EXPIRE_SINGLEDEAD; - } - link->data.tcp->state.out = state; break; case ALIAS_TCP_STATE_CONNECTED: - link->expire_time = TCP_EXPIRE_CONNECTED; - /*FALLTHROUGH*/ - case ALIAS_TCP_STATE_NOT_CONNECTED: - link->data.tcp->state.out = state; + if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) + link->expire_time = TCP_EXPIRE_CONNECTED; break; default: abort(); } + link->data.tcp->state.out = state; } @@ -1537,7 +1970,7 @@ GetStateOut(struct alias_link *link) struct in_addr GetOriginalAddress(struct alias_link *link) { - if (link->src_addr.s_addr == 0) + if (link->src_addr.s_addr == INADDR_ANY) return aliasAddress; else return(link->src_addr); @@ -1554,7 +1987,7 @@ GetDestAddress(struct alias_link *link) struct in_addr GetAliasAddress(struct alias_link *link) { - if (link->alias_addr.s_addr == 0) + if (link->alias_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->alias_addr; @@ -1588,16 +2021,18 @@ GetAliasPort(struct alias_link *link) return(link->alias_port); } -u_short +#ifndef NO_FW_PUNCH +static u_short GetDestPort(struct alias_link *link) { return(link->dst_port); } +#endif void SetAckModified(struct alias_link *link) { -/* Indicate that ack numbers have been modified in a TCP connection */ +/* Indicate that ACK numbers have been modified in a TCP connection */ link->data.tcp->state.ack_modified = 1; } @@ -1633,7 +2068,7 @@ SetProxyPort(struct alias_link *link, u_short port) int GetAckModified(struct alias_link *link) { -/* See if ack numbers have been modified */ +/* See if ACK numbers have been modified */ return link->data.tcp->state.ack_modified; } @@ -1642,8 +2077,8 @@ int GetDeltaAckIn(struct ip *pip, struct alias_link *link) { /* -Find out how much the ack number has been altered for an incoming -TCP packet. To do this, a circular list is ack numbers where the TCP +Find out how much the ACK number has been altered for an incoming +TCP packet. To do this, a circular list of ACK numbers where the TCP packet size was altered is searched. */ @@ -1693,8 +2128,8 @@ int GetDeltaSeqOut(struct ip *pip, struct alias_link *link) { /* -Find out how much the seq number has been altered for an outgoing -TCP packet. To do this, a circular list is ack numbers where the TCP +Find out how much the sequence number has been altered for an outgoing +TCP packet. To do this, a circular list of ACK numbers where the TCP packet size was altered is searched. */ @@ -1806,6 +2241,33 @@ ClearCheckNewLink(void) newDefaultLink = 0; } +void +SetLastLineCrlfTermed(struct alias_link *link, int yes) +{ + + if (yes) + link->flags |= LINK_LAST_LINE_CRLF_TERMED; + else + link->flags &= ~LINK_LAST_LINE_CRLF_TERMED; +} + +int +GetLastLineCrlfTermed(struct alias_link *link) +{ + + return (link->flags & LINK_LAST_LINE_CRLF_TERMED); +} + +void +SetDestCallId(struct alias_link *link, u_int16_t cid) +{ + + deleteAllLinks = 1; + link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, + link->src_port, cid, link->alias_port, link->link_type); + deleteAllLinks = 0; +} + /* Miscellaneous Functions @@ -1910,6 +2372,8 @@ UninitPacketAliasLog(void) -- "outside world" means other than alias*.c routines -- PacketAliasRedirectPort() + PacketAliasAddServer() + PacketAliasRedirectProto() PacketAliasRedirectAddr() PacketAliasRedirectDelete() PacketAliasSetAddress() @@ -1921,7 +2385,7 @@ UninitPacketAliasLog(void) */ /* Redirection from a specific public addr:port to a - a private addr:port */ + private addr:port */ struct alias_link * PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, struct in_addr dst_addr, u_short dst_port, @@ -1966,24 +2430,63 @@ PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, return link; } -/* Translate PPTP packets to a machine on the inside - */ +/* Add server to the pool of servers */ int -PacketAliasPptp(struct in_addr src_addr) +PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) { + struct server *server; + + server = malloc(sizeof(struct server)); + + if (server != NULL) { + struct server *head; + + server->addr = addr; + server->port = port; - pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */ - pptpAliasFlag = src_addr.s_addr != INADDR_NONE; + head = link->server; + if (head == NULL) + server->next = server; + else { + struct server *s; - return 1; + for (s = head; s->next != head; s = s->next); + s->next = server; + server->next = head; + } + link->server = server; + return (0); + } else + return (-1); } -int GetPptpAlias (struct in_addr* alias_addr) +/* Redirect packets of a given IP protocol from a specific + public address to a private address */ +struct alias_link * +PacketAliasRedirectProto(struct in_addr src_addr, + struct in_addr dst_addr, + struct in_addr alias_addr, + u_char proto) { - if (pptpAliasFlag) - *alias_addr = pptpAliasAddr; + struct alias_link *link; - return pptpAliasFlag; + link = AddLink(src_addr, dst_addr, alias_addr, + NO_SRC_PORT, NO_DEST_PORT, 0, + proto); + + if (link != NULL) + { + link->flags |= LINK_PERMANENT; + } +#ifdef DEBUG + else + { + fprintf(stderr, "PacketAliasRedirectProto(): " + "call to AddLink() failed\n"); + } +#endif + + return link; } /* Static address translation */ @@ -2059,9 +2562,9 @@ PacketAliasInit(void) houseKeepingResidual = 0; for (i=0; i #include #include #include @@ -2169,19 +2671,13 @@ static char *fireWallField; /* bool array for entries */ #define fw_setfield(field, num) \ do { \ - (field)[num] = 1; \ + (field)[(num) - fireWallBaseNum] = 1; \ } /*lint -save -e717 */ while(0) /*lint -restore */ #define fw_clrfield(field, num) \ do { \ - (field)[num] = 0; \ + (field)[(num) - fireWallBaseNum] = 0; \ } /*lint -save -e717 */ while(0) /*lint -restore */ -#define fw_tstfield(field, num) ((field)[num]) - -void -PacketAliasSetFWBase(unsigned int base, unsigned int num) { - fireWallBaseNum = base; - fireWallNumNums = num; -} +#define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) static void InitPunchFW(void) { @@ -2218,8 +2714,7 @@ PunchFWHole(struct alias_link *link) { /* Don't do anything unless we are asked to */ if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || fireWallFD < 0 || - link->link_type != LINK_TCP || - !link->data.tcp) + link->link_type != LINK_TCP) return; memset(&rule, 0, sizeof rule); @@ -2232,8 +2727,7 @@ PunchFWHole(struct alias_link *link) { fw_tstfield(fireWallField, fwhole); fwhole++) ; - if (fwhole >= fireWallBaseNum + fireWallNumNums || - fw_tstfield(fireWallField, fwhole)) { + if (fwhole == fireWallBaseNum + fireWallNumNums) { for (fwhole = fireWallBaseNum; fwhole < fireWallActiveNum && fw_tstfield(fireWallField, fwhole); @@ -2253,8 +2747,9 @@ PunchFWHole(struct alias_link *link) { /* Build generic part of the two rules */ rule.fw_number = fwhole; - rule.fw_nports = 1; /* Number of source ports; dest ports follow */ - rule.fw_flg = IP_FW_F_ACCEPT; + IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */ + IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */ + rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT; rule.fw_prot = IPPROTO_TCP; rule.fw_smsk.s_addr = INADDR_BROADCAST; rule.fw_dmsk.s_addr = INADDR_BROADCAST; @@ -2294,7 +2789,7 @@ PunchFWHole(struct alias_link *link) { link. Calling this too often is harmless. */ static void ClearFWHole(struct alias_link *link) { - if (link->link_type == LINK_TCP && link->data.tcp) { + if (link->link_type == LINK_TCP) { int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ struct ip_fw rule; @@ -2328,3 +2823,11 @@ ClearAllFWHoles(void) { memset(fireWallField, 0, fireWallNumNums); } #endif + +void +PacketAliasSetFWBase(unsigned int base, unsigned int num) { +#ifndef NO_FW_PUNCH + fireWallBaseNum = base; + fireWallNumNums = num; +#endif +} diff --git a/alias/alias_ftp.c b/alias/alias_ftp.c index 73769fd..7985a95 100644 --- a/alias/alias_ftp.c +++ b/alias/alias_ftp.c @@ -1,22 +1,72 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_ftp.c,v 1.5.2.4 2001/08/21 03:50:25 brian Exp $ + */ + /* Alias_ftp.c performs special processing for FTP sessions under - TCP. Specifically, when a PORT command from the client side - is sent, it is intercepted and modified. The address is changed - to the gateway machine and an aliasing port is used. + TCP. Specifically, when a PORT/EPRT command from the client + side or 227/229 reply from the server is sent, it is intercepted + and modified. The address is changed to the gateway machine + and an aliasing port is used. - For this routine to work, the PORT command must fit entirely - into a single TCP packet. This is typically the case, but exceptions + For this routine to work, the message must fit entirely into a + single TCP packet. This is typically the case, but exceptions can easily be envisioned under the actual specifications. Probably the most troubling aspect of the approach taken here is - that the new PORT command will typically be a different length, and + that the new message will typically be a different length, and this causes a certain amount of bookkeeping to keep track of the changes of sequence and acknowledgment numbers, since the client machine is totally unaware of the modification to the TCP stream. - This software is placed into the public domain with no restrictions - on its distribution. + References: RFC 959, RFC 2428. Initial version: August, 1996 (cjm) @@ -25,20 +75,23 @@ error for modified IP packets. Version 1.7: January 9, 1996 (cjm) - Differental checksum computation for change + Differential checksum computation for change in IP packet length. - + Version 2.1: May, 1997 (cjm) Very minor changes to conform with local/global/function naming conventions - withing the packet alising module. + within the packet aliasing module. + + Version 3.1: May, 2000 (eds) + Add support for passive mode, alias the 227 replies. See HISTORY file for record of revisions. */ /* Includes */ #include -#include +#include #include #include #include @@ -48,9 +101,25 @@ #include "alias_local.h" -static void NewFtpPortCommand(struct ip *, struct alias_link *, struct in_addr, u_short, int); +#define FTP_CONTROL_PORT_NUMBER 21 +#define MAX_MESSAGE_SIZE 128 + +enum ftp_message_type { + FTP_PORT_COMMAND, + FTP_EPRT_COMMAND, + FTP_227_REPLY, + FTP_229_REPLY, + FTP_UNKNOWN_MESSAGE +}; +static int ParseFtpPortCommand(char *, int); +static int ParseFtpEprtCommand(char *, int); +static int ParseFtp227Reply(char *, int); +static int ParseFtp229Reply(char *, int); +static void NewFtpMessage(struct ip *, struct alias_link *, int, int); +static struct in_addr true_addr; /* in network byte order. */ +static u_short true_port; /* in host byte order. */ void AliasHandleFtpOut( @@ -59,93 +128,367 @@ struct alias_link *link, /* The link to go through (aliased port) */ int maxpacketsize /* The maximum size this packet can grow to (including headers) */) { int hlen, tlen, dlen; - struct in_addr true_addr; - u_short true_port; char *sptr; struct tcphdr *tc; - + int ftp_message_type; + /* Calculate data length of TCP packet */ tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); hlen = (pip->ip_hl + tc->th_off) << 2; tlen = ntohs(pip->ip_len); dlen = tlen - hlen; -/* Return is data length is too long or too short */ - if (dlen<10 || dlen>80) - return; - /* Place string pointer and beginning of data */ - sptr = (char *) pip; + sptr = (char *) pip; sptr += hlen; -/* Parse through string using state diagram method */ - { - char ch, zero; - int i, state; - u_long a1, a2, a3, a4; - u_short p1, p2; - - a1=0; a2=0; a3=0; a4=0; p1=0; p2=0; - zero = '0'; - state=-4; - for (i=0; ith_dport) == FTP_CONTROL_PORT_NUMBER) { +/* + * When aliasing a client, check for the PORT/EPRT command. + */ + if (ParseFtpPortCommand(sptr, dlen)) + ftp_message_type = FTP_PORT_COMMAND; + else if (ParseFtpEprtCommand(sptr, dlen)) + ftp_message_type = FTP_EPRT_COMMAND; + } else { +/* + * When aliasing a server, check for the 227/229 reply. + */ + if (ParseFtp227Reply(sptr, dlen)) + ftp_message_type = FTP_227_REPLY; + else if (ParseFtp229Reply(sptr, dlen)) + ftp_message_type = FTP_229_REPLY; + } + + if (ftp_message_type != FTP_UNKNOWN_MESSAGE) + NewFtpMessage(pip, link, maxpacketsize, ftp_message_type); + } + +/* Track the msgs which are CRLF term'd for PORT/PASV FW breach */ + + if (dlen) { /* only if there's data */ + sptr = (char *) pip; /* start over at beginning */ + tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may have grown */ + SetLastLineCrlfTermed(link, + (sptr[tlen-2] == '\r') && (sptr[tlen-1] == '\n')); + } +} + +static int +ParseFtpPortCommand(char *sptr, int dlen) +{ + char ch; + int i, state; + u_int32_t addr; + u_short port; + u_int8_t octet; + + /* Format: "PORT A,D,D,R,PO,RT". */ + + /* Return if data length is too short. */ + if (dlen < 18) + return 0; + + addr = port = octet = 0; + state = -4; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) { + case -4: if (ch == 'P') state++; else return 0; break; + case -3: if (ch == 'O') state++; else return 0; break; + case -2: if (ch == 'R') state++; else return 0; break; + case -1: if (ch == 'T') state++; else return 0; break; + + case 0: + if (isspace(ch)) + break; + else + state++; + case 1: case 3: case 5: case 7: case 9: case 11: + if (isdigit(ch)) { + octet = ch - '0'; + state++; + } else + return 0; + break; + case 2: case 4: case 6: case 8: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',') { + addr = (addr << 8) + octet; + state++; + } else + return 0; + break; + case 10: case 12: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',' || state == 12) { + port = (port << 8) + octet; + state++; + } else + return 0; + break; + } + } + + if (state == 13) { + true_addr.s_addr = htonl(addr); + true_port = port; + return 1; + } else + return 0; +} + +static int +ParseFtpEprtCommand(char *sptr, int dlen) +{ + char ch, delim; + int i, state; + u_int32_t addr; + u_short port; + u_int8_t octet; + + /* Format: "EPRT |1|A.D.D.R|PORT|". */ + + /* Return if data length is too short. */ + if (dlen < 18) + return 0; + + addr = port = octet = 0; + delim = '|'; /* XXX gcc -Wuninitialized */ + state = -4; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) + { + case -4: if (ch == 'E') state++; else return 0; break; + case -3: if (ch == 'P') state++; else return 0; break; + case -2: if (ch == 'R') state++; else return 0; break; + case -1: if (ch == 'T') state++; else return 0; break; + + case 0: + if (!isspace(ch)) { + delim = ch; + state++; + } + break; + case 1: + if (ch == '1') /* IPv4 address */ + state++; + else + return 0; + break; + case 2: + if (ch == delim) + state++; + else + return 0; + break; + case 3: case 5: case 7: case 9: + if (isdigit(ch)) { + octet = ch - '0'; + state++; + } else + return 0; + break; + case 4: case 6: case 8: case 10: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == '.' || state == 10) { + addr = (addr << 8) + octet; + state++; + } else + return 0; + break; + case 11: + if (isdigit(ch)) { + port = ch - '0'; + state++; + } else + return 0; + break; + case 12: + if (isdigit(ch)) + port = 10 * port + ch - '0'; + else if (ch == delim) + state++; + else + return 0; + break; + } + } + + if (state == 13) { + true_addr.s_addr = htonl(addr); + true_port = port; + return 1; + } else + return 0; +} - if (state == 11) +static int +ParseFtp227Reply(char *sptr, int dlen) +{ + char ch; + int i, state; + u_int32_t addr; + u_short port; + u_int8_t octet; + + /* Format: "227 Entering Passive Mode (A,D,D,R,PO,RT)" */ + + /* Return if data length is too short. */ + if (dlen < 17) + return 0; + + addr = port = octet = 0; + + state = -3; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) { - true_port = htons((p1<<8) + p2); - true_addr.s_addr = htonl((a1<<24) + (a2<<16) +(a3<<8) + a4); - NewFtpPortCommand(pip, link, true_addr, true_port, maxpacketsize); - } + case -3: if (ch == '2') state++; else return 0; break; + case -2: if (ch == '2') state++; else return 0; break; + case -1: if (ch == '7') state++; else return 0; break; + + case 0: + if (ch == '(') + state++; + break; + case 1: case 3: case 5: case 7: case 9: case 11: + if (isdigit(ch)) { + octet = ch - '0'; + state++; + } else + return 0; + break; + case 2: case 4: case 6: case 8: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',') { + addr = (addr << 8) + octet; + state++; + } else + return 0; + break; + case 10: case 12: + if (isdigit(ch)) + octet = 10 * octet + ch - '0'; + else if (ch == ',' || (state == 12 && ch == ')')) { + port = (port << 8) + octet; + state++; + } else + return 0; + break; + } } + + if (state == 13) { + true_port = port; + true_addr.s_addr = htonl(addr); + return 1; + } else + return 0; +} + +static int +ParseFtp229Reply(char *sptr, int dlen) +{ + char ch, delim; + int i, state; + u_short port; + + /* Format: "229 Entering Extended Passive Mode (|||PORT|)" */ + + /* Return if data length is too short. */ + if (dlen < 11) + return 0; + + port = 0; + delim = '|'; /* XXX gcc -Wuninitialized */ + + state = -3; + for (i = 0; i < dlen; i++) { + ch = sptr[i]; + switch (state) + { + case -3: if (ch == '2') state++; else return 0; break; + case -2: if (ch == '2') state++; else return 0; break; + case -1: if (ch == '9') state++; else return 0; break; + + case 0: + if (ch == '(') + state++; + break; + case 1: + delim = ch; + state++; + break; + case 2: case 3: + if (ch == delim) + state++; + else + return 0; + break; + case 4: + if (isdigit(ch)) { + port = ch - '0'; + state++; + } else + return 0; + break; + case 5: + if (isdigit(ch)) + port = 10 * port + ch - '0'; + else if (ch == delim) + state++; + else + return 0; + break; + case 6: + if (ch == ')') + state++; + else + return 0; + break; + } + } + + if (state == 7) { + true_port = port; + return 1; + } else + return 0; } static void -NewFtpPortCommand(struct ip *pip, - struct alias_link *link, - struct in_addr true_addr, - u_short true_port, - int maxpacketsize) -{ +NewFtpMessage(struct ip *pip, + struct alias_link *link, + int maxpacketsize, + int ftp_message_type) +{ struct alias_link *ftp_link; -/* Establish link to address and port found in PORT command */ +/* Security checks. */ + if (ftp_message_type != FTP_229_REPLY && + pip->ip_src.s_addr != true_addr.s_addr) + return; + + if (true_port < IPPORT_RESERVED) + return; + +/* Establish link to address and port found in FTP control message. */ ftp_link = FindUdpTcpOut(true_addr, GetDestAddress(link), - true_port, 0, IPPROTO_TCP); + htons(true_port), 0, IPPROTO_TCP, 1); if (ftp_link != NULL) { @@ -153,8 +496,11 @@ NewFtpPortCommand(struct ip *pip, struct tcphdr *tc; #ifndef NO_FW_PUNCH -/* Punch hole in firewall */ - PunchFWHole(ftp_link); + if (ftp_message_type == FTP_PORT_COMMAND || + ftp_message_type == FTP_EPRT_COMMAND) { + /* Punch hole in firewall */ + PunchFWHole(ftp_link); + } #endif /* Calculate data length of TCP packet */ @@ -163,33 +509,57 @@ NewFtpPortCommand(struct ip *pip, tlen = ntohs(pip->ip_len); dlen = tlen - hlen; -/* Create new PORT command */ +/* Create new FTP message. */ { - char stemp[80]; + char stemp[MAX_MESSAGE_SIZE + 1]; char *sptr; u_short alias_port; u_char *ptr; - int a1, a2, a3, a4, p1, p2; + int a1, a2, a3, a4, p1, p2; struct in_addr alias_address; - + /* Decompose alias address into quad format */ alias_address = GetAliasAddress(link); ptr = (u_char *) &alias_address.s_addr; a1 = *ptr++; a2=*ptr++; a3=*ptr++; a4=*ptr; -/* Decompose alias port into pair format */ - alias_port = GetAliasPort(ftp_link); - ptr = (char *) &alias_port; - p1 = *ptr++; p2=*ptr; - -/* Generate command string */ - sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", - a1,a2,a3,a4,p1,p2); + alias_port = GetAliasPort(ftp_link); + + switch (ftp_message_type) + { + case FTP_PORT_COMMAND: + case FTP_227_REPLY: + /* Decompose alias port into pair format. */ + ptr = (char *) &alias_port; + p1 = *ptr++; p2=*ptr; + + if (ftp_message_type == FTP_PORT_COMMAND) { + /* Generate PORT command string. */ + sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n", + a1,a2,a3,a4,p1,p2); + } else { + /* Generate 227 reply string. */ + sprintf(stemp, + "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", + a1,a2,a3,a4,p1,p2); + } + break; + case FTP_EPRT_COMMAND: + /* Generate EPRT command string. */ + sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n", + a1,a2,a3,a4,ntohs(alias_port)); + break; + case FTP_229_REPLY: + /* Generate 229 reply string. */ + sprintf(stemp, "229 Entering Extended Passive Mode (|||%d|)\r\n", + ntohs(alias_port)); + break; + } /* Save string length for IP header modification */ slen = strlen(stemp); -/* Copy into IP packet */ +/* Copy modified buffer into IP packet. */ sptr = (char *) pip; sptr += hlen; strncpy(sptr, stemp, maxpacketsize-hlen); } diff --git a/alias/alias_irc.c b/alias/alias_irc.c index 910e934..e33ad75 100644 --- a/alias/alias_irc.c +++ b/alias/alias_irc.c @@ -1,3 +1,53 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_irc.c,v 1.5.2.4 2001/08/21 16:42:42 ru Exp $ + */ + /* Alias_irc.c intercepts packages contain IRC CTCP commands, and changes DCC commands to export a port on the aliasing host instead of an aliased host. @@ -10,9 +60,6 @@ The handling of this is copied more-or-less verbatim from ftp_alias.c - This software is placed into the public domain with no restrictions - on its distribution. - Initial version: Eivind Eklund (ee) 97-01-29 Version 2.1: May, 1997 (cjm) @@ -211,13 +258,18 @@ lFOUND_CTCP: true_addr.s_addr = htonl(org_addr); destaddr.s_addr = 0; + /* Sanity/Security checking */ + if (!org_addr || !org_port || + pip->ip_src.s_addr != true_addr.s_addr || + org_port < IPPORT_RESERVED) + goto lBAD_CTCP; + /* Steal the FTP_DATA_PORT - it doesn't really matter, and this would probably allow it through at least _some_ firewalls. */ - dcc_link = FindUdpTcpOut (true_addr, - destaddr, - true_port, - 0, IPPROTO_TCP); + dcc_link = FindUdpTcpOut(true_addr, destaddr, + true_port, 0, + IPPROTO_TCP, 1); DBprintf(("Got a DCC link\n")); if ( dcc_link ) { struct in_addr alias_address; /* Address from aliasing */ diff --git a/alias/alias_local.h b/alias/alias_local.h index 23b04a8..8aeb983 100644 --- a/alias/alias_local.h +++ b/alias/alias_local.h @@ -1,70 +1,113 @@ -/* -*- mode: c; tab-width: 3; c-basic-offset: 3; -*- - Alias_local.h contains the function prototypes for alias.c, - alias_db.c, alias_util.c and alias_ftp.c, alias_irc.c (as well - as any future add-ons). It also includes macros, globals and - struct definitions shared by more than one alias*.c file. - - This include file is intended to be used only within the aliasing - software. Outside world interfaces are defined in alias.h - - This software is placed into the public domain with no restrictions - on its distribution. - - Initial version: August, 1996 (cjm) - - -*/ -#ifndef ALIAS_LOCAL_H -#define ALIAS_LOCAL_H - - /* - Macros + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_local.h,v 1.10.2.5 2001/08/01 09:52:26 obrien Exp $ */ /* - The following macro is used to update an - internet checksum. "delta" is a 32-bit - accumulation of all the changes to the - checksum (adding in new 16-bit words and - subtracting out old words), and "cksum" - is the checksum value to be updated. -*/ -#define ADJUST_CHECKSUM(acc, cksum) { \ - acc += cksum; \ - if (acc < 0) \ - { \ - acc = -acc; \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) ~acc; \ - } \ - else \ - { \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) acc; \ - } \ -} + * Alias_local.h contains the function prototypes for alias.c, + * alias_db.c, alias_util.c and alias_ftp.c, alias_irc.c (as well + * as any future add-ons). It also includes macros, globals and + * struct definitions shared by more than one alias*.c file. + * + * This include file is intended to be used only within the aliasing + * software. Outside world interfaces are defined in alias.h + * + * This software is placed into the public domain with no restrictions + * on its distribution. + * + * Initial version: August, 1996 (cjm) + * + * + */ + +#ifndef _ALIAS_LOCAL_H_ +#define _ALIAS_LOCAL_H_ +#ifndef NULL +#define NULL 0 +#endif + +/* Macros */ /* - Globals -*/ + * The following macro is used to update an + * internet checksum. "delta" is a 32-bit + * accumulation of all the changes to the + * checksum (adding in new 16-bit words and + * subtracting out old words), and "cksum" + * is the checksum value to be updated. + */ +#define ADJUST_CHECKSUM(acc, cksum) \ + do { \ + acc += cksum; \ + if (acc < 0) { \ + acc = -acc; \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) ~acc; \ + } else { \ + acc = (acc >> 16) + (acc & 0xffff); \ + acc += acc >> 16; \ + cksum = (u_short) acc; \ + } \ + } while (0) + +/* Globals */ extern int packetAliasMode; -/* - Structs -*/ +/* Structs */ struct alias_link; /* Incomplete structure */ -/* - Prototypes -*/ +/* Prototypes */ /* General utilities */ u_short IpChecksum(struct ip *); @@ -73,10 +116,10 @@ void DifferentialChecksum(u_short *, u_short *, u_short *, int); /* Internal data access */ struct alias_link * -FindIcmpIn(struct in_addr, struct in_addr, u_short); +FindIcmpIn(struct in_addr, struct in_addr, u_short, int); struct alias_link * -FindIcmpOut(struct in_addr, struct in_addr, u_short); +FindIcmpOut(struct in_addr, struct in_addr, u_short, int); struct alias_link * FindFragmentIn1(struct in_addr, struct in_addr, u_short); @@ -91,10 +134,34 @@ struct alias_link * FindFragmentPtr(struct in_addr, u_short); struct alias_link * -FindUdpTcpIn (struct in_addr, struct in_addr, u_short, u_short, u_char); +FindProtoIn(struct in_addr, struct in_addr, u_char); + +struct alias_link * +FindProtoOut(struct in_addr, struct in_addr, u_char); + +struct alias_link * +FindUdpTcpIn (struct in_addr, struct in_addr, u_short, u_short, u_char, int); + +struct alias_link * +FindUdpTcpOut(struct in_addr, struct in_addr, u_short, u_short, u_char, int); + +struct alias_link * +AddPptp(struct in_addr, struct in_addr, struct in_addr, u_int16_t); + +struct alias_link * +FindPptpOutByCallId(struct in_addr, struct in_addr, u_int16_t); + +struct alias_link * +FindPptpInByCallId(struct in_addr, struct in_addr, u_int16_t); + +struct alias_link * +FindPptpOutByPeerCallId(struct in_addr, struct in_addr, u_int16_t); + +struct alias_link * +FindPptpInByPeerCallId(struct in_addr, struct in_addr, u_int16_t); struct alias_link * -FindUdpTcpOut(struct in_addr, struct in_addr, u_short, u_short, u_char); +FindRtspOut(struct in_addr, struct in_addr, u_short, u_short, u_char); struct in_addr FindOriginalAddress(struct in_addr); @@ -103,6 +170,8 @@ struct in_addr FindAliasAddress(struct in_addr); /* External data access/modification */ +int FindNewPortGroup(struct in_addr, struct in_addr, + u_short, u_short, u_short, u_char, u_char); void GetFragmentAddr(struct alias_link *, struct in_addr *); void SetFragmentAddr(struct alias_link *, struct in_addr); void GetFragmentPtr(struct alias_link *, char **); @@ -129,6 +198,9 @@ int GetDeltaSeqOut(struct ip *, struct alias_link *); void AddSeq(struct ip *, struct alias_link *, int); void SetExpire(struct alias_link *, int); void ClearCheckNewLink(void); +void SetLastLineCrlfTermed(struct alias_link *, int); +int GetLastLineCrlfTermed(struct alias_link *); +void SetDestCallId(struct alias_link *, u_int16_t); #ifndef NO_FW_PUNCH void PunchFWHole(struct alias_link *); #endif @@ -146,6 +218,15 @@ void AliasHandleFtpOut(struct ip *, struct alias_link *, int); /* IRC routines */ void AliasHandleIrcOut(struct ip *, struct alias_link *, int); +/* RTSP routines */ +void AliasHandleRtspOut(struct ip *, struct alias_link *, int); + +/* PPTP routines */ +void AliasHandlePptpOut(struct ip *, struct alias_link *); +void AliasHandlePptpIn(struct ip *, struct alias_link *); +int AliasHandlePptpGreOut(struct ip *); +int AliasHandlePptpGreIn(struct ip *); + /* NetBIOS routines */ int AliasHandleUdpNbt(struct ip *, struct alias_link *, struct in_addr *, u_short); int AliasHandleUdpNbtNS(struct ip *, struct alias_link *, struct in_addr *, u_short *, struct in_addr *, u_short *); @@ -160,11 +241,11 @@ void ProxyModify(struct alias_link *, struct ip *, int, int); enum alias_tcp_state { - ALIAS_TCP_STATE_NOT_CONNECTED, - ALIAS_TCP_STATE_CONNECTED, - ALIAS_TCP_STATE_DISCONNECTED + ALIAS_TCP_STATE_NOT_CONNECTED, + ALIAS_TCP_STATE_CONNECTED, + ALIAS_TCP_STATE_DISCONNECTED }; -int GetPptpAlias (struct in_addr*); /*lint -restore */ -#endif /* defined(ALIAS_LOCAL_H) */ + +#endif /* !_ALIAS_LOCAL_H_ */ diff --git a/alias/alias_nbt.c b/alias/alias_nbt.c index b629b8e..f0b8048 100644 --- a/alias/alias_nbt.c +++ b/alias/alias_nbt.c @@ -1,21 +1,52 @@ /* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- * Written by Atsushi Murai + * Copyright (c) 1998, System Planning and Engineering Co. + * All rights reserved. * - * Copyright (C) 1998, System Planning and Engineering Co. All rights reserverd. + * 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. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the System Planning and Engineering Co. The name of the - * SPEC may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. * - * $Id: alias_nbt.c,v 1.1.1.1 2000/01/11 01:48:42 wsanchez Exp $ + * Based upon: + * $FreeBSD: src/lib/libalias/alias_nbt.c,v 1.4.2.3 2001/08/01 09:52:26 obrien Exp $ * * TODO: * oClean up. @@ -44,23 +75,6 @@ #include "alias_local.h" -#define ADJUST_CHECKSUM(acc, cksum) { \ - acc += cksum; \ - if (acc < 0) \ - { \ - acc = -acc; \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) ~acc; \ - } \ - else \ - { \ - acc = (acc >> 16) + (acc & 0xffff); \ - acc += acc >> 16; \ - cksum = (u_short) acc; \ - } \ -} - typedef struct { struct in_addr oldaddr; u_short oldport; @@ -258,7 +272,7 @@ int AliasHandleUdpNbt( sptr = (u_short *) alias_address; acc -= *sptr++; acc -= *sptr; - ADJUST_CHECKSUM(acc, uh->uh_sum) + ADJUST_CHECKSUM(acc, uh->uh_sum); } ndh->source_ip = *alias_address; ndh->source_port = alias_port; @@ -375,7 +389,7 @@ AliasHandleResourceNB( sptr = (u_short *) &(nbtarg->newaddr); acc -= *sptr++; acc -= *sptr; - ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) + ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); } nb->addr = nbtarg->newaddr; @@ -443,7 +457,7 @@ AliasHandleResourceA( sptr = (u_short *) &nbtarg->newaddr; /* New */ acc -= *sptr++; acc -= *sptr; - ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) + ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); } a->addr = nbtarg->newaddr; diff --git a/alias/alias_pptp.c b/alias/alias_pptp.c new file mode 100644 index 0000000..03e1a22 --- /dev/null +++ b/alias/alias_pptp.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * alias_pptp.c + * + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Erik Salander + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_pptp.c,v 1.1.2.4 2001/08/01 09:52:27 obrien Exp $ + */ + +/* + Alias_pptp.c performs special processing for PPTP sessions under TCP. + Specifically, watch PPTP control messages and alias the Call ID or the + Peer's Call ID in the appropriate messages. Note, PPTP requires + "de-aliasing" of incoming packets, this is different than any other + TCP applications that are currently (ie. FTP, IRC and RTSP) aliased. + + For Call IDs encountered for the first time, a PPTP alias link is created. + The PPTP alias link uses the Call ID in place of the original port number. + An alias Call ID is created. + + For this routine to work, the PPTP control messages must fit entirely + into a single TCP packet. This is typically the case, but is not + required by the spec. + + Unlike some of the other TCP applications that are aliased (ie. FTP, + IRC and RTSP), the PPTP control messages that need to be aliased are + guaranteed to remain the same length. The aliased Call ID is a fixed + length field. + + Reference: RFC 2637 + + Initial version: May, 2000 (eds) + +*/ + +/* Includes */ +#include +#include +#include +#include +#include + +#include + +#include "alias_local.h" + +/* + * PPTP definitions + */ + +struct grehdr /* Enhanced GRE header. */ +{ + u_int16_t gh_flags; /* Flags. */ + u_int16_t gh_protocol; /* Protocol type. */ + u_int16_t gh_length; /* Payload length. */ + u_int16_t gh_call_id; /* Call ID. */ + u_int32_t gh_seq_no; /* Sequence number (optional). */ + u_int32_t gh_ack_no; /* Acknowledgment number (optional). */ +}; +typedef struct grehdr GreHdr; + +/* The PPTP protocol ID used in the GRE 'proto' field. */ +#define PPTP_GRE_PROTO 0x880b + +/* Bits that must be set a certain way in all PPTP/GRE packets. */ +#define PPTP_INIT_VALUE ((0x2001 << 16) | PPTP_GRE_PROTO) +#define PPTP_INIT_MASK 0xef7fffff + +#define PPTP_MAGIC 0x1a2b3c4d +#define PPTP_CTRL_MSG_TYPE 1 + +enum { + PPTP_StartCtrlConnRequest = 1, + PPTP_StartCtrlConnReply = 2, + PPTP_StopCtrlConnRequest = 3, + PPTP_StopCtrlConnReply = 4, + PPTP_EchoRequest = 5, + PPTP_EchoReply = 6, + PPTP_OutCallRequest = 7, + PPTP_OutCallReply = 8, + PPTP_InCallRequest = 9, + PPTP_InCallReply = 10, + PPTP_InCallConn = 11, + PPTP_CallClearRequest = 12, + PPTP_CallDiscNotify = 13, + PPTP_WanErrorNotify = 14, + PPTP_SetLinkInfo = 15 +}; + + /* Message structures */ + struct pptpMsgHead { + u_int16_t length; /* total length */ + u_int16_t msgType; /* PPTP message type */ + u_int32_t magic; /* magic cookie */ + u_int16_t type; /* control message type */ + u_int16_t resv0; /* reserved */ + }; + typedef struct pptpMsgHead *PptpMsgHead; + + struct pptpCodes { + u_int8_t resCode; /* Result Code */ + u_int8_t errCode; /* Error Code */ + }; + typedef struct pptpCodes *PptpCode; + + struct pptpCallIds { + u_int16_t cid1; /* Call ID field #1 */ + u_int16_t cid2; /* Call ID field #2 */ + }; + typedef struct pptpCallIds *PptpCallId; + +static PptpCallId AliasVerifyPptp(struct ip *, u_int16_t *); + + +void +AliasHandlePptpOut(struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *link) /* The PPTP control link */ +{ + struct alias_link *pptp_link; + PptpCallId cptr; + PptpCode codes; + u_int16_t ctl_type; /* control message type */ + struct tcphdr *tc; + + /* Verify valid PPTP control message */ + if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL) + return; + + /* Modify certain PPTP messages */ + switch (ctl_type) { + case PPTP_OutCallRequest: + case PPTP_OutCallReply: + case PPTP_InCallRequest: + case PPTP_InCallReply: + /* Establish PPTP link for address and Call ID found in control message. */ + pptp_link = AddPptp(GetOriginalAddress(link), GetDestAddress(link), + GetAliasAddress(link), cptr->cid1); + break; + case PPTP_CallClearRequest: + case PPTP_CallDiscNotify: + /* Find PPTP link for address and Call ID found in control message. */ + pptp_link = FindPptpOutByCallId(GetOriginalAddress(link), + GetDestAddress(link), + cptr->cid1); + break; + default: + return; + } + + if (pptp_link != NULL) { + int accumulate = cptr->cid1; + + /* alias the Call Id */ + cptr->cid1 = GetAliasPort(pptp_link); + + /* Compute TCP checksum for revised packet */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + accumulate -= cptr->cid1; + ADJUST_CHECKSUM(accumulate, tc->th_sum); + + switch (ctl_type) { + case PPTP_OutCallReply: + case PPTP_InCallReply: + codes = (PptpCode)(cptr + 1); + if (codes->resCode == 1) /* Connection established, */ + SetDestCallId(pptp_link, /* note the Peer's Call ID. */ + cptr->cid2); + else + SetExpire(pptp_link, 0); /* Connection refused. */ + break; + case PPTP_CallDiscNotify: /* Connection closed. */ + SetExpire(pptp_link, 0); + break; + } + } +} + +void +AliasHandlePptpIn(struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *link) /* The PPTP control link */ +{ + struct alias_link *pptp_link; + PptpCallId cptr; + u_int16_t *pcall_id; + u_int16_t ctl_type; /* control message type */ + struct tcphdr *tc; + + /* Verify valid PPTP control message */ + if ((cptr = AliasVerifyPptp(pip, &ctl_type)) == NULL) + return; + + /* Modify certain PPTP messages */ + switch (ctl_type) + { + case PPTP_InCallConn: + case PPTP_WanErrorNotify: + case PPTP_SetLinkInfo: + pcall_id = &cptr->cid1; + break; + case PPTP_OutCallReply: + case PPTP_InCallReply: + pcall_id = &cptr->cid2; + break; + case PPTP_CallDiscNotify: /* Connection closed. */ + pptp_link = FindPptpInByCallId(GetDestAddress(link), + GetAliasAddress(link), + cptr->cid1); + if (pptp_link != NULL) + SetExpire(pptp_link, 0); + return; + default: + return; + } + + /* Find PPTP link for address and Call ID found in PPTP Control Msg */ + pptp_link = FindPptpInByPeerCallId(GetDestAddress(link), + GetAliasAddress(link), + *pcall_id); + + if (pptp_link != NULL) { + int accumulate = *pcall_id; + + /* De-alias the Peer's Call Id. */ + *pcall_id = GetOriginalPort(pptp_link); + + /* Compute TCP checksum for modified packet */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + accumulate -= *pcall_id; + ADJUST_CHECKSUM(accumulate, tc->th_sum); + + if (ctl_type == PPTP_OutCallReply || ctl_type == PPTP_InCallReply) { + PptpCode codes = (PptpCode)(cptr + 1); + + if (codes->resCode == 1) /* Connection established, */ + SetDestCallId(pptp_link, /* note the Call ID. */ + cptr->cid1); + else + SetExpire(pptp_link, 0); /* Connection refused. */ + } + } +} + +static PptpCallId +AliasVerifyPptp(struct ip *pip, u_int16_t *ptype) /* IP packet to examine/patch */ +{ + int hlen, tlen, dlen; + PptpMsgHead hptr; + struct tcphdr *tc; + + /* Calculate some lengths */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + + /* Verify data length */ + if (dlen < (sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds))) + return(NULL); + + /* Move up to PPTP message header */ + hptr = (PptpMsgHead)(((char *) pip) + hlen); + + /* Return the control message type */ + *ptype = ntohs(hptr->type); + + /* Verify PPTP Control Message */ + if ((ntohs(hptr->msgType) != PPTP_CTRL_MSG_TYPE) || + (ntohl(hptr->magic) != PPTP_MAGIC)) + return(NULL); + + /* Verify data length. */ + if ((*ptype == PPTP_OutCallReply || *ptype == PPTP_InCallReply) && + (dlen < sizeof(struct pptpMsgHead) + sizeof(struct pptpCallIds) + + sizeof(struct pptpCodes))) + return (NULL); + else + return (PptpCallId)(hptr + 1); +} + + +int +AliasHandlePptpGreOut(struct ip *pip) +{ + GreHdr *gr; + struct alias_link *link; + + gr = (GreHdr *)((char *)pip + (pip->ip_hl << 2)); + + /* Check GRE header bits. */ + if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) + return (-1); + + link = FindPptpOutByPeerCallId(pip->ip_src, pip->ip_dst, gr->gh_call_id); + if (link != NULL) { + struct in_addr alias_addr = GetAliasAddress(link); + + /* Change source IP address. */ + DifferentialChecksum(&pip->ip_sum, + (u_short *)&alias_addr, + (u_short *)&pip->ip_src, + 2); + pip->ip_src = alias_addr; + } + + return (0); +} + + +int +AliasHandlePptpGreIn(struct ip *pip) +{ + GreHdr *gr; + struct alias_link *link; + + gr = (GreHdr *)((char *)pip + (pip->ip_hl << 2)); + + /* Check GRE header bits. */ + if ((ntohl(*((u_int32_t *)gr)) & PPTP_INIT_MASK) != PPTP_INIT_VALUE) + return (-1); + + link = FindPptpInByPeerCallId(pip->ip_src, pip->ip_dst, gr->gh_call_id); + if (link != NULL) { + struct in_addr src_addr = GetOriginalAddress(link); + + /* De-alias the Peer's Call Id. */ + gr->gh_call_id = GetOriginalPort(link); + + /* Restore original IP address. */ + DifferentialChecksum(&pip->ip_sum, + (u_short *)&src_addr, + (u_short *)&pip->ip_dst, + 2); + pip->ip_dst = src_addr; + } + + return (0); +} diff --git a/alias/alias_proxy.c b/alias/alias_proxy.c index 60437bf..67299c0 100644 --- a/alias/alias_proxy.c +++ b/alias/alias_proxy.c @@ -1,3 +1,53 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_proxy.c,v 1.4.2.4 2001/08/01 09:52:27 obrien Exp $ + */ + /* file: alias_proxy.c This file encapsulates special operations related to transparent @@ -518,6 +568,7 @@ PacketAliasProxyRule(const char *cmd) char buffer[256]; char str_port[sizeof(buffer)]; char str_server_port[sizeof(buffer)]; + char *res = buffer; int rule_index; int proto; @@ -530,6 +581,7 @@ PacketAliasProxyRule(const char *cmd) struct proxy_entry *proxy_entry; /* Copy command line into a buffer */ + cmd += strspn(cmd, " \t"); cmd_len = strlen(cmd); if (cmd_len > (sizeof(buffer) - 1)) return -1; @@ -538,7 +590,7 @@ PacketAliasProxyRule(const char *cmd) /* Convert to lower case */ len = strlen(buffer); for (i=0; i + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Authors: Erik Salander + * Junichi SATOH + * + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_smedia.c,v 1.1.2.4 2001/03/05 03:48:00 kris Exp $ + */ + +/* + Alias_smedia.c is meant to contain the aliasing code for streaming media + protocols. It performs special processing for RSTP sessions under TCP. + Specifically, when a SETUP request is sent by a client, or a 200 reply + is sent by a server, it is intercepted and modified. The address is + changed to the gateway machine and an aliasing port is used. + + More specifically, the "client_port" configuration parameter is + parsed for SETUP requests. The "server_port" configuration parameter is + parsed for 200 replies eminating from a server. This is intended to handle + the unicast case. + + RTSP also allows a redirection of a stream to another client by using the + "destination" configuration parameter. The destination config parm would + indicate a different IP address. This function is NOT supported by the + RTSP translation code below. + + The RTSP multicast functions without any address translation intervention. + + For this routine to work, the SETUP/200 must fit entirely + into a single TCP packet. This is typically the case, but exceptions + can easily be envisioned under the actual specifications. + + Probably the most troubling aspect of the approach taken here is + that the new SETUP/200 will typically be a different length, and + this causes a certain amount of bookkeeping to keep track of the + changes of sequence and acknowledgment numbers, since the client + machine is totally unaware of the modification to the TCP stream. + + Initial version: May, 2000 (eds) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alias_local.h" + +#define RTSP_CONTROL_PORT_NUMBER_1 554 +#define RTSP_CONTROL_PORT_NUMBER_2 7070 +#define RTSP_PORT_GROUP 2 + +#define ISDIGIT(a) (((a) >= '0') && ((a) <= '9')) + +static int +search_string(char *data, int dlen, const char *search_str) +{ + int i, j, k; + int search_str_len; + + search_str_len = strlen(search_str); + for (i = 0; i < dlen - search_str_len; i++) { + for (j = i, k = 0; j < dlen - search_str_len; j++, k++) { + if (data[j] != search_str[k] && + data[j] != search_str[k] - ('a' - 'A')) { + break; + } + if (k == search_str_len - 1) { + return j + 1; + } + } + } + return -1; +} + +static int +alias_rtsp_out(struct ip *pip, + struct alias_link *link, + char *data, + const char *port_str) +{ + int hlen, tlen, dlen; + struct tcphdr *tc; + int i, j, pos, state, port_dlen, new_dlen, delta; + u_short p[2], new_len; + u_short sport, eport, base_port; + u_short salias = 0, ealias = 0, base_alias = 0; + const char *transport_str = "transport:"; + char newdata[2048], *port_data, *port_newdata, stemp[80]; + int links_created = 0, pkt_updated = 0; + struct alias_link *rtsp_link = NULL; + struct in_addr null_addr; + + /* Calculate data length of TCP packet */ + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + + /* Find keyword, "Transport: " */ + pos = search_string(data, dlen, transport_str); + if (pos < 0) { + return -1; + } + port_data = data + pos; + port_dlen = dlen - pos; + + memcpy(newdata, data, pos); + port_newdata = newdata + pos; + + while (port_dlen > strlen(port_str)) { + /* Find keyword, appropriate port string */ + pos = search_string(port_data, port_dlen, port_str); + if (pos < 0) { + break; + } + + memcpy (port_newdata, port_data, pos + 1); + port_newdata += (pos + 1); + + p[0] = p[1] = 0; + sport = eport = 0; + state = 0; + for (i = pos; i < port_dlen; i++) { + switch(state) { + case 0: + if (port_data[i] == '=') { + state++; + } + break; + case 1: + if (ISDIGIT(port_data[i])) { + p[0] = p[0] * 10 + port_data[i] - '0'; + } else { + if (port_data[i] == ';') { + state = 3; + } + if (port_data[i] == '-') { + state++; + } + } + break; + case 2: + if (ISDIGIT(port_data[i])) { + p[1] = p[1] * 10 + port_data[i] - '0'; + } else { + state++; + } + break; + case 3: + base_port = p[0]; + sport = htons(p[0]); + eport = htons(p[1]); + + if (!links_created) { + + links_created = 1; + /* Find an even numbered port number base that + satisfies the contiguous number of ports we need */ + null_addr.s_addr = 0; + if (0 == (salias = FindNewPortGroup(null_addr, + FindAliasAddress(pip->ip_src), + sport, 0, + RTSP_PORT_GROUP, + IPPROTO_UDP, 1))) { +#ifdef DEBUG + fprintf(stderr, + "PacketAlias/RTSP: Cannot find contiguous RTSP data ports\n"); +#endif + } else { + + base_alias = ntohs(salias); + for (j = 0; j < RTSP_PORT_GROUP; j++) { + /* Establish link to port found in RTSP packet */ + rtsp_link = FindRtspOut(GetOriginalAddress(link), null_addr, + htons(base_port + j), htons(base_alias + j), + IPPROTO_UDP); + if (rtsp_link != NULL) { +#ifndef NO_FW_PUNCH + /* Punch hole in firewall */ + PunchFWHole(rtsp_link); +#endif + } else { +#ifdef DEBUG + fprintf(stderr, + "PacketAlias/RTSP: Cannot allocate RTSP data ports\n"); +#endif + break; + } + } + } + ealias = htons(base_alias + (RTSP_PORT_GROUP - 1)); + } + + if (salias && rtsp_link) { + + pkt_updated = 1; + + /* Copy into IP packet */ + sprintf(stemp, "%d", ntohs(salias)); + memcpy(port_newdata, stemp, strlen(stemp)); + port_newdata += strlen(stemp); + + if (eport != 0) { + *port_newdata = '-'; + port_newdata++; + + /* Copy into IP packet */ + sprintf(stemp, "%d", ntohs(ealias)); + memcpy(port_newdata, stemp, strlen(stemp)); + port_newdata += strlen(stemp); + } + + *port_newdata = ';'; + port_newdata++; + } + state++; + break; + } + if (state > 3) { + break; + } + } + port_data += i; + port_dlen -= i; + } + + if (!pkt_updated) + return -1; + + memcpy (port_newdata, port_data, port_dlen); + port_newdata += port_dlen; + *port_newdata = '\0'; + + /* Create new packet */ + new_dlen = port_newdata - newdata; + memcpy (data, newdata, new_dlen); + + SetAckModified(link); + delta = GetDeltaSeqOut(pip, link); + AddSeq(pip, link, delta + new_dlen - dlen); + + new_len = htons(hlen + new_dlen); + DifferentialChecksum(&pip->ip_sum, + &new_len, + &pip->ip_len, + 1); + pip->ip_len = new_len; + + tc->th_sum = 0; + tc->th_sum = TcpChecksum(pip); + + return 0; +} + +/* Support the protocol used by early versions of RealPlayer */ + +static int +alias_pna_out(struct ip *pip, + struct alias_link *link, + char *data, + int dlen) +{ + struct alias_link *pna_links; + u_short msg_id, msg_len; + char *work; + u_short alias_port, port; + struct tcphdr *tc; + + work = data; + work += 5; + while (work + 4 < data + dlen) { + memcpy(&msg_id, work, 2); + work += 2; + memcpy(&msg_len, work, 2); + work += 2; + if (ntohs(msg_id) == 0) { + /* end of options */ + return 0; + } + if ((ntohs(msg_id) == 1) || (ntohs(msg_id) == 7)) { + memcpy(&port, work, 2); + pna_links = FindUdpTcpOut(pip->ip_src, GetDestAddress(link), + port, 0, IPPROTO_UDP, 1); + if (pna_links != NULL) { +#ifndef NO_FW_PUNCH + /* Punch hole in firewall */ + PunchFWHole(pna_links); +#endif + tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); + alias_port = GetAliasPort(pna_links); + memcpy(work, &alias_port, 2); + + /* Compute TCP checksum for revised packet */ + tc->th_sum = 0; + tc->th_sum = TcpChecksum(pip); + } + } + work += ntohs(msg_len); + } + + return 0; +} + +void +AliasHandleRtspOut(struct ip *pip, struct alias_link *link, int maxpacketsize) +{ + int hlen, tlen, dlen; + struct tcphdr *tc; + char *data; + const char *setup = "SETUP", *pna = "PNA", *str200 = "200"; + const char *okstr = "OK", *client_port_str = "client_port"; + const char *server_port_str = "server_port"; + int i, parseOk; + + tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); + hlen = (pip->ip_hl + tc->th_off) << 2; + tlen = ntohs(pip->ip_len); + dlen = tlen - hlen; + + data = (char*)pip; + data += hlen; + + /* When aliasing a client, check for the SETUP request */ + if ((ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1) || + (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2)) { + + if (dlen >= strlen(setup)) { + if (memcmp(data, setup, strlen(setup)) == 0) { + alias_rtsp_out(pip, link, data, client_port_str); + return; + } + } + if (dlen >= strlen(pna)) { + if (memcmp(data, pna, strlen(pna)) == 0) { + alias_pna_out(pip, link, data, dlen); + } + } + + } else { + + /* When aliasing a server, check for the 200 reply + Accomodate varying number of blanks between 200 & OK */ + + if (dlen >= strlen(str200)) { + + for (parseOk = 0, i = 0; + i <= dlen - strlen(str200); + i++) { + if (memcmp(&data[i], str200, strlen(str200)) == 0) { + parseOk = 1; + break; + } + } + if (parseOk) { + + i += strlen(str200); /* skip string found */ + while(data[i] == ' ') /* skip blank(s) */ + i++; + + if ((dlen - i) >= strlen(okstr)) { + + if (memcmp(&data[i], okstr, strlen(okstr)) == 0) + alias_rtsp_out(pip, link, data, server_port_str); + + } + } + } + } +} diff --git a/alias/alias_util.c b/alias/alias_util.c index fe07653..28ea257 100644 --- a/alias/alias_util.c +++ b/alias/alias_util.c @@ -1,5 +1,55 @@ /* - Alias_util.h contains general utilities used by other functions + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/*- + * Copyright (c) 2001 Charles Mott + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 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. + * + * Based upon: + * $FreeBSD: src/lib/libalias/alias_util.c,v 1.4.2.2 2001/06/04 14:59:06 brian Exp $ + */ + +/* + Alias_util.c contains general utilities used by other functions in the packet aliasing module. At the moment, there are functions for computing IP header and TCP packet checksums. @@ -15,7 +65,7 @@ /* Note: the checksum routines assume that the actual checksum word has -been zeroed out. If the checksum workd is filled with the proper value, +been zeroed out. If the checksum word is filled with the proper value, then these routines will give a result of zero (useful for testing purposes); */ @@ -43,7 +93,8 @@ PacketAliasInternetChecksum(u_short *ptr, int nbytes) if (nbytes == 1) { oddbyte = 0; - *((u_char *) &oddbyte) = *(u_char *) ptr; + ((u_char *) &oddbyte)[0] = *(u_char *) ptr; + ((u_char *) &oddbyte)[1] = 0; sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); @@ -84,7 +135,8 @@ TcpChecksum(struct ip *pip) if (nbytes == 1) { oddbyte = 0; - *((u_char *) &oddbyte) = *(u_char *) ptr; + ((u_char *) &oddbyte)[0] = *(u_char *) ptr; + ((u_char *) &oddbyte)[1] = 0; sum += oddbyte; } diff --git a/bootparams/bpwhoami.tproj/Makefile b/bootparams/bpwhoami.tproj/Makefile index 1cf44ad..55fa9ac 100644 --- a/bootparams/bpwhoami.tproj/Makefile +++ b/bootparams/bpwhoami.tproj/Makefile @@ -14,7 +14,7 @@ PROJECT_TYPE = Tool CFILES = bpwhoami.c -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble bpwhoami.1 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/bootparams/bpwhoami.tproj/Makefile.postamble b/bootparams/bpwhoami.tproj/Makefile.postamble index 411cde6..a4a093c 100644 --- a/bootparams/bpwhoami.tproj/Makefile.postamble +++ b/bootparams/bpwhoami.tproj/Makefile.postamble @@ -98,3 +98,6 @@ # owned by the top-level Makefile API and no context has been set up for where # derived files should go. # +after_install: + install -d $(DSTROOT)/usr/share/man/man1 + install -c -m 444 bpwhoami.1 $(DSTROOT)/usr/share/man/man1 diff --git a/bootparams/bpwhoami.tproj/bpwhoami.1 b/bootparams/bpwhoami.tproj/bpwhoami.1 new file mode 100644 index 0000000..dd73e36 --- /dev/null +++ b/bootparams/bpwhoami.tproj/bpwhoami.1 @@ -0,0 +1,31 @@ +.\" Copyright (c) 1997, Apple Computer, Inc. All rights reserved. +.\" +.Dd August 7, 1997 +.Dt BPWHOAMI 1 +.Os Mac OS X +.Sh NAME +.Nm bpwhoami +.Nd print the output of a bootparams whoami call +.Sh SYNOPSIS +.Nm bpwhoami +.Sh DESCRIPTION +This command makes a bootparams whoami call and echos the results to +stdout. The output is of the form: +.Pp +HOSTNAME= +DOMAIN= +ROUTER= +SERVER= +.Sh SEE ALSO +.Xr bootparams 5 +.Xr bootparamd 8 +.Sh DIAGNOSTICS +.Nm bpwhoami +exits with one of the following values: +.Bl -tag -width Ds -compact +.It 0 +Successfully retrieved information. +.It 1 +RPC timed out while attempting to retrieve information. +.It 2 +Unrecoverable error. diff --git a/bootparams/bpwhoami.tproj/bpwhoami.c b/bootparams/bpwhoami.tproj/bpwhoami.c index c846417..68a4c6d 100644 --- a/bootparams/bpwhoami.tproj/bpwhoami.c +++ b/bootparams/bpwhoami.tproj/bpwhoami.c @@ -66,6 +66,7 @@ void usage __P((void)); #include #include #include +#include #include #include #include "bootparam_prot.h" @@ -122,77 +123,31 @@ each_whoresult(result, from) return(FALSE); } -#define MAX_IF 16 static boolean_t -getFirstInterface(struct ifreq * ret_p) +getFirstInterface(struct sockaddr_in *ret_p) { - struct ifconf ifconf; /* points to ifreq */ - struct ifreq * ifreq = NULL; - struct ifreq * ifrp; - int size = sizeof(struct ifreq) * MAX_IF; - int sockfd; - - if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - fprintf(stderr, "bpwhoami: socket call failed\n"); - return (FALSE); - } - - while (1) { - if (ifreq != NULL) - ifreq = (struct ifreq *)realloc(ifreq, size); - else - ifreq = (struct ifreq *)malloc(size); - - if (ifreq == NULL) - goto err; - - ifconf.ifc_len = size; - ifconf.ifc_req = ifreq; - if (ioctl(sockfd, SIOCGIFCONF, (caddr_t)&ifconf) < 0 - || ifconf.ifc_len <= 0) { - fprintf(stderr, "bpwhoami: ioctl SIOCGIFCONF failed\n"); - goto err; - } - if ((ifconf.ifc_len + sizeof(struct ifreq)) < size) - break; - size *= 2; + struct ifaddrs *ifap; + struct ifaddrs *ifcurrent; + getifaddrs(&ifap); + + for (ifcurrent = ifap; ifcurrent; ifcurrent = ifcurrent->ifa_next) { + if (ifcurrent->ifa_addr->sa_family == AF_INET) { + if ((ifcurrent->ifa_flags & IFF_LOOPBACK) + || !(ifcurrent->ifa_flags & IFF_UP)) + continue; + net_mask = ((struct sockaddr_in*)(ifcurrent->ifa_netmask))->sin_addr; + *ret_p = *((struct sockaddr_in*)(ifcurrent->ifa_addr)); + freeifaddrs(ifap); + return (TRUE); + } } -#define IFR_NEXT(ifr) \ - ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \ - MAX(0, (int) (ifr)->ifr_addr.sa_len \ - - (int) sizeof((ifr)->ifr_addr)))) - for (ifrp = (struct ifreq *) ifconf.ifc_buf; - (char *) ifrp < &ifconf.ifc_buf[ifconf.ifc_len]; - ifrp = IFR_NEXT(ifrp)) { - if (ifrp->ifr_addr.sa_family == AF_INET) { - struct ifreq ifr; - - strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name)); - if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) - ; - else if ((ifr.ifr_flags & IFF_LOOPBACK) - || !(ifr.ifr_flags & IFF_UP)) - ; - else if (ioctl(sockfd, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) - ; - else { - net_mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; - *ret_p = *ifrp; - close(sockfd); - if (ifreq) - free(ifreq); - return (TRUE); - } - } - } - err: - close(sockfd); - if (ifreq) - free(ifreq); + if (ifap) + freeifaddrs(ifap); return (FALSE); } + /* * Routine: bp_whoami * Function: @@ -203,19 +158,17 @@ int bp_whoami() { extern enum clnt_stat clnt_broadcast(); - struct ifreq ifr; - struct sockaddr_in *sockin; + struct sockaddr_in sockin; enum clnt_stat stat; struct bp_whoami_arg who_arg; struct bp_whoami_res who_res; - if (getFirstInterface(&ifr) == FALSE) + if (getFirstInterface(&sockin) == FALSE) return (2); - sockin = (struct sockaddr_in *) &ifr.ifr_addr; - ip_address = sockin->sin_addr; + ip_address = sockin.sin_addr; who_arg.client_address.bp_address_u.ip_addr = - *((ip_addr_t *)&sockin->sin_addr); + *((ip_addr_t *)&sockin.sin_addr); who_arg.client_address.address_type = IP_ADDR_TYPE; bzero(&who_res, sizeof (who_res)); diff --git a/eaytest.tproj/Makefile b/eaytest.tproj/Makefile new file mode 100644 index 0000000..73483e3 --- /dev/null +++ b/eaytest.tproj/Makefile @@ -0,0 +1,51 @@ +# +# Generated by the Apple Project Builder. +# +# NOTE: Do NOT change this file -- Project Builder maintains it. +# +# Put all of your customizations in files called Makefile.preamble +# and Makefile.postamble (both optional), and Makefile will include them. +# + +NAME = eaytest + +PROJECTVERSION = 2.8 +PROJECT_TYPE = Tool + +HFILES = crypto_openssl.h misc.h str2val.h vmbuf.h rijndael-alg-fst.h\ + rijndael-api-fst.h sha2.h + +CFILES = crypto_openssl.c eaytest.c misc.c rijndael-alg-fst.c\ + rijndael-api-fst.c sha2.c str2val.c vmbuf.c + +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble + + +MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles +CODE_GEN_STYLE = DYNAMIC +MAKEFILE = tool.make +NEXTSTEP_INSTALLDIR = /usr/bin +WINDOWS_INSTALLDIR = /Library/Executables +PDO_UNIX_INSTALLDIR = /bin +LIBS = -lcrypto -lipsec -lssl +DEBUG_LIBS = $(LIBS) +PROF_LIBS = $(LIBS) + + + +NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc +WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc +PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc +NEXTSTEP_JAVA_COMPILER = /usr/bin/javac +WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe +PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac + +include $(MAKEFILEDIR)/platform.make + +-include Makefile.preamble + +include $(MAKEFILEDIR)/$(MAKEFILE) + +-include Makefile.postamble + +-include Makefile.dependencies diff --git a/eaytest.tproj/Makefile.postamble b/eaytest.tproj/Makefile.postamble new file mode 100644 index 0000000..411cde6 --- /dev/null +++ b/eaytest.tproj/Makefile.postamble @@ -0,0 +1,100 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGES: langages in which the project is written (default "English") +# English_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# diff --git a/eaytest.tproj/Makefile.preamble b/eaytest.tproj/Makefile.preamble new file mode 100644 index 0000000..a96500c --- /dev/null +++ b/eaytest.tproj/Makefile.preamble @@ -0,0 +1,146 @@ +############################################################################### +# Makefile.preamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile for configuring the standard application makefiles +# associated with ProjectBuilder. It is included before the main makefile. +# In Makefile.preamble you set attributes for a project, so they are available +# to the project's makefiles. In contrast, you typically write additional rules or +# override built-in behavior in the Makefile.postamble. +# +# Each directory in a project tree (main project plus subprojects) should +# have its own Makefile.preamble and Makefile.postamble. +############################################################################### +# +# Before the main makefile is included for this project, you may set: +# +# MAKEFILEDIR: Directory in which to find $(MAKEFILE) +# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make) + +# Compiler/linker flags added to the defaults: The OTHER_* variables will be +# inherited by all nested sub-projects, but the LOCAL_ versions of the same +# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's +# Build Attributes inspector if at all possible. To override the default flags +# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The +# variables below are *inputs* to the build process and distinct from the override +# settings done (less often) in the Makefile.postamble. +# +# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler +# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m, +# .cc, .cxx, .C, and .M files. There is no need to respecify the +# flags in OTHER_MFLAGS, etc. +# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files +# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files +# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files +# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when +# precompiling header files +# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool +# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap +# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen +# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc +# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex +OTHER_CFLAGS=-DHAVE_FUNCTION_MACRO=1 -DENABLE_IPV6=1 -DADVAPI=1 -DHAVE_GETADDRINFO=1 \ +-DHAVE_GETNAMEINFO=1 -DHAVE_LIBSSL=1 -DHAVE_LIBCRYPTO=1 -DHAVE_LIBL=1 -DHAVE_LIBY=1 \ +-DSTDC_HEADERS=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_UNISTD_H=1 \ +-DHAVE_STDARG_H=1 -DHAVE_VARARGS_H=1 -DHAVE_OPENSSL_RSA_H=1 -DHAVE_OPENSSL_PEM_H=1 \ +-DHAVE_OPENSSL_EVP_H=1 -DHAVE_OPENSSL_X509_H=1 -DHAVE_SIGNING_C=1 -DHAVE_OPENSSL_OPENSSLV_H=1 \ +-DTIME_WITH_SYS_TIME=1 -DRETSIGTYPE=void -DHAVE_VPRINTF=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_SELECT=1 \ +-DHAVE_SOCKET=1 -DHAVE_STRERROR=1 -DHAVE_STRTOL=1 -DHAVE_STRTOUL=1 -DHAVE_STRDUP=1 \ +-DHAVE_GETIFADDRS=1 -DINET6 -DHAVE_PFKEYV2 -O -DYIPS_DEBUG -DIPSEC -Dss_family=__ss_family \ +-Dss_len=__ss_len -DSYSCONFDIR=\"/etc\" -DYY_NO_UNPUT -I../racoon.tproj -DNOUSE_PLOG -DEAYDEBUG + +# These variables provide hooks enabling you to add behavior at almost every +# stage of the make: +# +# BEFORE_PREBUILD: targets to build before installing headers for a subproject +# AFTER_PREBUILD: targets to build after installing headers for a subproject +# BEFORE_BUILD_RECURSION: targets to make before building subprojects +# BEFORE_BUILD: targets to make before a build, but after subprojects +# AFTER_BUILD: targets to make after a build +# +# BEFORE_INSTALL: targets to build before installing the product +# AFTER_INSTALL: targets to build after installing the product +# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject +# AFTER_POSTINSTALL: targts to build after postinstalling every subproject +# +# BEFORE_INSTALLHDRS: targets to build before installing headers for a +# subproject +# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject +# BEFORE_INSTALLSRC: targets to build before installing source for a subproject +# AFTER_INSTALLSRC: targets to build after installing source for a subproject +# +# BEFORE_DEPEND: targets to build before building dependencies for a +# subproject +# AFTER_DEPEND: targets to build after building dependencies for a +# subproject +# +# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is +# updated every time the project is built. If NO, the dependency +# file is only built when the depend target is invoked. + +# Framework-related variables: +# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the framework's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables + +# Library-related variables: +# PUBLIC_HEADER_DIR: Determines where public exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. For library projects you should +# set this to something like /Developer/Headers/$(NAME). Do not set +# this variable for framework projects unless you do not want the +# header files included in the framework. +# PRIVATE_HEADER_DIR: Determines where private exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. +# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines +# whether the libraries produced are statically linked when they +# are used or if they are dynamically loadable. This defaults to +# DYNAMIC. +# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the library's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables +# +# INSTALL_AS_USER: owner of the intalled products (default root) +# INSTALL_AS_GROUP: group of the installed products (default wheel) +# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX) +# +# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be +# passed on the command line to recursive invocations of make. Note that +# the values in OTHER_*FLAGS are inherited by subprojects automatically -- +# you do not have to (and shouldn't) add OTHER_*FLAGS to +# OTHER_RECURSIVE_VARIABLES. + +# Additional headers to export beyond those in the PB.project: +# OTHER_PUBLIC_HEADERS +# OTHER_PROJECT_HEADERS +# OTHER_PRIVATE_HEADERS + +# Additional files for the project's product: <> +# OTHER_RESOURCES: (non-localized) resources for this project +# OTHER_OFILES: relocatables to be linked into this project +# OTHER_LIBS: more libraries to link against +# OTHER_PRODUCT_DEPENDS: other dependencies of this project +# OTHER_SOURCEFILES: other source files maintained by .pre/postamble +# OTHER_GARBAGE: additional files to be removed by `make clean' + +# Set this to YES if you don't want a final libtool call for a library/framework. +# BUILD_OFILES_LIST_ONLY + +# To include a version string, project source must exist in a directory named +# $(NAME).%d[.%d][.%d] and the following line must be uncommented. +# OTHER_GENERATED_OFILES = $(VERS_OFILE) + +# This definition will suppress stripping of debug symbols when an executable +# is installed. By default it is YES. +# STRIP_ON_INSTALL = NO + +# Uncomment to suppress generation of a KeyValueCoding index when installing +# frameworks (This index is used by WOB and IB to determine keys available +# for an object). Set to YES by default. +# PREINDEX_FRAMEWORK = NO + +# Change this definition to install projects somewhere other than the +# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems +# and "" on other systems. +DSTROOT = $(HOME) diff --git a/eaytest.tproj/PB.project b/eaytest.tproj/PB.project new file mode 100644 index 0000000..3ed44a1 --- /dev/null +++ b/eaytest.tproj/PB.project @@ -0,0 +1,44 @@ +{ + DYNAMIC_CODE_GEN = YES; + FILESTABLE = { + FRAMEWORKS = (); + H_FILES = ( + crypto_openssl.h, + misc.h, + str2val.h, + vmbuf.h, + "rijndael-alg-fst.h", + "rijndael-api-fst.h", + sha2.h + ); + OTHER_LIBS = (crypto, ipsec, ssl); + OTHER_LINKED = ( + crypto_openssl.c, + eaytest.c, + misc.c, + "rijndael-alg-fst.c", + "rijndael-api-fst.c", + sha2.c, + str2val.c, + vmbuf.c + ); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble); + }; + LANGUAGE = English; + MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; + NEXTSTEP_BUILDTOOL = /bin/gnumake; + NEXTSTEP_INSTALLDIR = /bin; + NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; + PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; + PDO_UNIX_INSTALLDIR = /bin; + PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac"; + PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; + PROJECTNAME = eaytest; + PROJECTTYPE = Tool; + PROJECTVERSION = 2.8; + WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; + WINDOWS_INSTALLDIR = /Library/Executables; + WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; + WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; +} diff --git a/eaytest.tproj/crypto_openssl.c b/eaytest.tproj/crypto_openssl.c new file mode 100644 index 0000000..c042c33 --- /dev/null +++ b/eaytest.tproj/crypto_openssl.c @@ -0,0 +1,2295 @@ +/* $KAME: crypto_openssl.c,v 1.69 2001/09/11 13:25:00 sakane 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. 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. + */ + +#include +#include + +#include +#include +#include +#include + +/* get openssl/ssleay version number */ +#ifdef HAVE_OPENSSL_OPENSSLV_H +# include +#else +# error no opensslv.h found. +#endif + +#ifndef OPENSSL_VERSION_NUMBER +#error OPENSSL_VERSION_NUMBER is not defined. OpenSSL0.9.4 or later required. +#endif + +#ifdef HAVE_OPENSSL_PEM_H +#include +#endif +#ifdef HAVE_OPENSSL_EVP_H +#include +#endif +#ifdef HAVE_OPENSSL_X509_H +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_OPENSSL_IDEA_H +#include +#endif +#include +#ifdef HAVE_OPENSSL_RC5_H +#include +#endif +#include +#include +#ifdef HAVE_OPENSSL_RIJNDAEL_H +#include +#else +#include "rijndael-api-fst.h" +#endif +#ifdef HAVE_OPENSSL_SHA2_H +#include +#else +#include "sha2.h" +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "crypto_openssl.h" +#include "debug.h" +#include "gcmalloc.h" + +/* + * I hate to cast every parameter to des_xx into void *, but it is + * necessary for SSLeay/OpenSSL portability. It sucks. + */ + +#ifdef HAVE_SIGNING_C +static int cb_check_cert __P((int, X509_STORE_CTX *)); +static void eay_setgentype __P((char *, int *)); +static X509 *mem2x509 __P((vchar_t *)); +#endif + +static caddr_t eay_hmac_init __P((vchar_t *, const EVP_MD *)); + +#ifdef HAVE_SIGNING_C +/* X509 Certificate */ +/* + * convert the string of the subject name into DER + * e.g. str = "C=JP, ST=Kanagawa"; + */ +vchar_t * +eay_str2asn1dn(str, len) + char *str; + int len; +{ + X509_NAME *name; + char *buf; + char *field, *value; + int i, j; + vchar_t *ret; + caddr_t p; + + buf = racoon_malloc(len + 1); + if (!buf) { + printf("failed to allocate buffer\n"); + return NULL; + } + memcpy(buf, str, len); + + name = X509_NAME_new(); + + field = &buf[0]; + value = NULL; + for (i = 0; i < len; i++) { + if (!value && buf[i] == '=') { + buf[i] = '\0'; + value = &buf[i + 1]; + continue; + } else if (buf[i] == ',' || buf[i] == '/') { + buf[i] = '\0'; +#if 0 + printf("[%s][%s]\n", field, value); +#endif + if (!X509_NAME_add_entry_by_txt(name, field, + MBSTRING_ASC, value, -1, -1, 0)) + goto err; + for (j = i + 1; j < len; j++) { + if (buf[j] != ' ') + break; + } + field = &buf[j]; + value = NULL; + continue; + } + } + buf[len] = '\0'; +#if 0 + printf("[%s][%s]\n", field, value); +#endif + if (!X509_NAME_add_entry_by_txt(name, field, + MBSTRING_ASC, value, -1, -1, 0)) + goto err; + + i = i2d_X509_NAME(name, NULL); + if (!i) + goto err; + ret = vmalloc(i); + if (!ret) + goto err; + p = ret->v; + i = i2d_X509_NAME(name, (unsigned char **)&p); + if (!i) + goto err; + + return ret; + + err: + if (buf) + racoon_free(buf); + if (name) + X509_NAME_free(name); + return NULL; +} + +/* + * compare two subjectNames. + * OUT: 0: equal + * positive: + * -1: other error. + */ +int +eay_cmp_asn1dn(n1, n2) + vchar_t *n1, *n2; +{ + X509_NAME *a = NULL, *b = NULL; + caddr_t p; + int i = -1; + + p = n1->v; + if (!d2i_X509_NAME(&a, (unsigned char **)&p, n1->l)) + goto end; + p = n2->v; + if (!d2i_X509_NAME(&b, (unsigned char **)&p, n2->l)) + goto end; + + i = X509_NAME_cmp(a, b); + + end: + if (a) + X509_NAME_free(a); + if (b) + X509_NAME_free(b); + return i; +} + +/* + * this functions is derived from apps/verify.c in OpenSSL0.9.5 + */ +int +eay_check_x509cert(cert, CApath) + vchar_t *cert; + char *CApath; +{ + X509_STORE *cert_ctx = NULL; + X509_LOOKUP *lookup = NULL; + X509 *x509 = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + X509_STORE_CTX *csc; +#else + X509_STORE_CTX csc; +#endif + int error = -1; + + /* XXX define only functions required. */ +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + OpenSSL_add_all_algorithms(); +#else + SSLeay_add_all_algorithms(); +#endif + + cert_ctx = X509_STORE_new(); + if (cert_ctx == NULL) + goto end; + X509_STORE_set_verify_cb_func(cert_ctx, cb_check_cert); + + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); + if (lookup == NULL) + goto end; + X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); /* XXX */ + + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); + if (lookup == NULL) + goto end; + error = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM); + if(!error) { + error = -1; + goto end; + } + error = -1; /* initialized */ + + /* read the certificate to be verified */ + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + csc = X509_STORE_CTX_new(); + if (csc == NULL) + goto end; + X509_STORE_CTX_init(csc, cert_ctx, x509, NULL); + error = X509_verify_cert(csc); + X509_STORE_CTX_cleanup(csc); +#else + X509_STORE_CTX_init(&csc, cert_ctx, x509, NULL); + error = X509_verify_cert(&csc); + X509_STORE_CTX_cleanup(&csc); +#endif + + /* + * if x509_verify_cert() is successful then the value of error is + * set non-zero. + */ + error = error ? 0 : -1; + +end: + if (error) + printf("%s\n", eay_strerror()); + if (cert_ctx != NULL) + X509_STORE_free(cert_ctx); + if (x509 != NULL) + X509_free(x509); + + return(error); +} + +/* + * callback function for verifing certificate. + * this function is derived from cb() in openssl/apps/s_server.c + */ +static int +cb_check_cert(ok, ctx) + int ok; + X509_STORE_CTX *ctx; +{ + char buf[256]; + int log_tag; + + if (!ok) { + X509_NAME_oneline( + X509_get_subject_name(ctx->current_cert), + buf, + 256); + /* + * since we are just checking the certificates, it is + * ok if they are self signed. But we should still warn + * the user. + */ + switch (ctx->error) { + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + case X509_V_ERR_INVALID_CA: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_PURPOSE: +#endif + ok = 1; + log_tag = LLV_WARNING; + break; + default: + log_tag = LLV_ERROR; + } +#ifndef EAYDEBUG + plog(log_tag, LOCATION, NULL, + "%s(%d) at depth:%d SubjectName:%s\n", + X509_verify_cert_error_string(ctx->error), + ctx->error, + ctx->error_depth, + buf); +#else + printf("%d: %s(%d) at depth:%d SubjectName:%s\n", + log_tag, + X509_verify_cert_error_string(ctx->error), + ctx->error, + ctx->error_depth, + buf); +#endif + } + ERR_clear_error(); + + return ok; +} + +/* + * get a subjectAltName from X509 certificate. + */ +vchar_t * +eay_get_x509asn1subjectname(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + u_char *bp; + vchar_t *name = NULL; + int len; + int error = -1; + + bp = cert->v; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + /* get the length of the name */ + len = i2d_X509_NAME(x509->cert_info->subject, NULL); + name = vmalloc(len); + if (!name) + goto end; + /* get the name */ + bp = name->v; + len = i2d_X509_NAME(x509->cert_info->subject, &bp); + + error = 0; + + end: + if (error) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#else + printf("%s\n", eay_strerror()); +#endif + if (name) { + vfree(name); + name = NULL; + } + } + if (x509) + X509_free(x509); + + return name; +} + +/* + * get the subjectAltName from X509 certificate. + * the name is terminated by '\0'. + */ +#include +int +eay_get_x509subjectaltname(cert, altname, type, pos) + vchar_t *cert; + char **altname; + int *type; + int pos; +{ + X509 *x509 = NULL; + X509_EXTENSION *ext; + X509V3_EXT_METHOD *method = NULL; + STACK_OF(GENERAL_NAME) *name; + CONF_VALUE *cval = NULL; + STACK_OF(CONF_VALUE) *nval = NULL; + u_char *bp; + int i, len; + int error = -1; + + *altname = NULL; + *type = GENT_OTHERNAME; + + bp = cert->v; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + i = X509_get_ext_by_NID(x509, NID_subject_alt_name, -1); + if (i < 0) + goto end; + ext = X509_get_ext(x509, i); + method = X509V3_EXT_get(ext); + if(!method) + goto end; + + bp = ext->value->data; + name = method->d2i(NULL, &bp, ext->value->length); + if(!name) + goto end; + + nval = method->i2v(method, name, NULL); + method->ext_free(name); + name = NULL; + if(!nval) + goto end; + + for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { + /* skip the name */ + if (i + 1 != pos) + continue; + cval = sk_CONF_VALUE_value(nval, i); + len = strlen(cval->value) + 1; /* '\0' included */ + *altname = racoon_malloc(len); + if (!*altname) { + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); + goto end; + } + strcpy(*altname, cval->value); + + /* set type of the name */ + eay_setgentype(cval->name, type); + } + + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); + + error = 0; + + end: + if (error) { + if (*altname) { + racoon_free(*altname); + *altname = NULL; + } +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#else + printf("%s\n", eay_strerror()); +#endif + } + if (x509) + X509_free(x509); + + return error; +} + +static void +eay_setgentype(name, type) + char *name; + int *type; +{ + /* XXX It's needed effective code */ + if(!memcmp(name, "email", strlen("email"))) { + *type = GENT_EMAIL; + } else if(!memcmp(name, "URI", strlen("URI"))) { + *type = GENT_URI; + } else if(!memcmp(name, "DNS", strlen("DNS"))) { + *type = GENT_DNS; + } else if(!memcmp(name, "RID", strlen("RID"))) { + *type = GENT_RID; + } else if(!memcmp(name, "IP", strlen("IP"))) { + *type = GENT_IPADD; + } else { + *type = GENT_OTHERNAME; + } +} + +/* + * decode a X509 certificate and make a readable text terminated '\n'. + * return the buffer allocated, so must free it later. + */ +char * +eay_get_x509text(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + BIO *bio = NULL; + char *text = NULL; + u_char *bp = NULL; + int len = 0; + int error = -1; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto end; + + error = X509_print(bio, x509); + if (error != 1) { + error = -1; + goto end; + } + + len = BIO_get_mem_data(bio, &bp); + text = racoon_malloc(len + 1); + if (text == NULL) + goto end; + memcpy(text, bp, len); + text[len] = '\0'; + + error = 0; + + end: + if (error) { + if (text) { + racoon_free(text); + text = NULL; + } +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#else + printf("%s\n", eay_strerror()); +#endif + } + if (bio) + BIO_free(bio); + if (x509) + X509_free(x509); + + return text; +} + +/* get X509 structure from buffer. */ +static X509 * +mem2x509(cert) + vchar_t *cert; +{ + X509 *x509; + +#ifndef EAYDEBUG + { + u_char *bp; + + bp = cert->v; + + x509 = d2i_X509(NULL, &bp, cert->l); + } +#else + { + BIO *bio; + int len; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + return NULL; + len = BIO_write(bio, cert->v, cert->l); + if (len == -1) + return NULL; + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + } +#endif + return x509; +} + +/* + * get a X509 certificate from local file. + * a certificate must be PEM format. + * Input: + * path to a certificate. + * Output: + * NULL if error occured + * other is the cert. + */ +vchar_t * +eay_get_x509cert(path) + char *path; +{ + FILE *fp; + X509 *x509; + vchar_t *cert; + u_char *bp; + int len; + int error; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + x509 = PEM_read_X509(fp, NULL, NULL, NULL); +#else + x509 = PEM_read_X509(fp, NULL, NULL); +#endif + fclose (fp); + + if (x509 == NULL) + return NULL; + + len = i2d_X509(x509, NULL); + cert = vmalloc(len); + if (cert == NULL) { + X509_free(x509); + return NULL; + } + bp = cert->v; + error = i2d_X509(x509, &bp); + X509_free(x509); + + if (error == 0) + return NULL; + + return cert; +} + +/* + * sign a souce by X509 signature. + * XXX: to be get hash type from my cert ? + * to be handled EVP_dss(). + */ +vchar_t * +eay_get_x509sign(source, privkey, cert) + vchar_t *source; + vchar_t *privkey; + vchar_t *cert; +{ + vchar_t *sig = NULL; + + sig = eay_rsa_sign(source, privkey); + + return sig; +} + +/* + * check a X509 signature + * XXX: to be get hash type from my cert ? + * to be handled EVP_dss(). + * OUT: return -1 when error. + * 0 + */ +int +eay_check_x509sign(source, sig, cert) + vchar_t *source; + vchar_t *sig; + vchar_t *cert; +{ + X509 *x509; + u_char *bp; + vchar_t pubkey; + + bp = cert->v; + + x509 = d2i_X509(NULL, &bp, cert->l); + if (x509 == NULL) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#endif + return -1; + } + + pubkey.v = x509->cert_info->key->public_key->data; + pubkey.l = x509->cert_info->key->public_key->length; + + return eay_rsa_verify(source, sig, &pubkey); +} + +/* + * check a signature by signed with PKCS7 certificate. + * XXX: to be get hash type from my cert ? + * to be handled EVP_dss(). + * OUT: return -1 when error. + * 0 + */ +int +eay_check_pkcs7sign(source, sig, cert) + vchar_t *source; + vchar_t *sig; + vchar_t *cert; +{ + X509 *x509; + EVP_MD_CTX md_ctx; + EVP_PKEY *evp; + int error; + BIO *bio = BIO_new(BIO_s_mem()); + char *bp; + + if (bio == NULL) + return -1; + error = BIO_write(bio, cert->v, cert->l); + if (error != cert->l) + return -1; + + bp = cert->v; + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + if (x509 == NULL) + return -1; + + evp = X509_get_pubkey(x509); + X509_free(x509); + if (evp == NULL) + return -1; + + /* Verify the signature */ + /* XXX: to be handled EVP_dss() */ + EVP_VerifyInit(&md_ctx, EVP_sha1()); + EVP_VerifyUpdate(&md_ctx, source->v, source->l); + error = EVP_VerifyFinal(&md_ctx, sig->v, sig->l, evp); + + EVP_PKEY_free(evp); + + if (error != 1) + return -1; + + return 0; +} + +/* + * get PKCS#1 Private Key of PEM format from local file. + */ +vchar_t * +eay_get_pkcs1privkey(path) + char *path; +{ + FILE *fp; + EVP_PKEY *evp = NULL; + vchar_t *pkey = NULL; + u_char *bp; + int pkeylen; + int error = -1; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + evp = PEM_read_PrivateKey(fp, NULL, NULL, NULL); +#else + evp = PEM_read_PrivateKey(fp, NULL, NULL); +#endif + fclose (fp); + + if (evp == NULL) + return NULL; + + pkeylen = i2d_PrivateKey(evp, NULL); + if (pkeylen == 0) + goto end; + pkey = vmalloc(pkeylen); + if (pkey == NULL) + goto end; + bp = pkey->v; + pkeylen = i2d_PrivateKey(evp, &bp); + if (pkeylen == 0) + goto end; + + error = 0; + +end: + if (evp != NULL) + EVP_PKEY_free(evp); + if (error != 0 && pkey != NULL) { + vfree(pkey); + pkey = NULL; + } + + return pkey; +} + +/* + * get PKCS#1 Public Key of PEM format from local file. + */ +vchar_t * +eay_get_pkcs1pubkey(path) + char *path; +{ + FILE *fp; + EVP_PKEY *evp = NULL; + vchar_t *pkey = NULL; + X509 *x509 = NULL; + u_char *bp; + int pkeylen; + int error = -1; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + x509 = PEM_read_X509(fp, NULL, NULL, NULL); +#else + x509 = PEM_read_X509(fp, NULL, NULL); +#endif + fclose (fp); + + if (x509 == NULL) + return NULL; + + /* Get public key - eay */ + evp = X509_get_pubkey(x509); + if (evp == NULL) + return NULL; + + pkeylen = i2d_PublicKey(evp, NULL); + if (pkeylen == 0) + goto end; + pkey = vmalloc(pkeylen); + if (pkey == NULL) + goto end; + bp = pkey->v; + pkeylen = i2d_PublicKey(evp, &bp); + if (pkeylen == 0) + goto end; + + error = 0; +end: + if (evp != NULL) + EVP_PKEY_free(evp); + if (error != 0 && pkey != NULL) { + vfree(pkey); + pkey = NULL; + } + + return pkey; +} +#endif + +vchar_t * +eay_rsa_sign(src, privkey) + vchar_t *src, *privkey; +{ + EVP_PKEY *evp; + u_char *bp = privkey->v; + vchar_t *sig = NULL; + int len; + int pad = RSA_PKCS1_PADDING; + + /* XXX to be handled EVP_PKEY_DSA */ + evp = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &bp, privkey->l); + if (evp == NULL) + return NULL; + + /* XXX: to be handled EVP_dss() */ + /* XXX: Where can I get such parameters ? From my cert ? */ + + len = RSA_size(evp->pkey.rsa); + + sig = vmalloc(len); + if (sig == NULL) + return NULL; + + len = RSA_private_encrypt(src->l, src->v, sig->v, evp->pkey.rsa, pad); + EVP_PKEY_free(evp); + if (len == 0 || len != sig->l) { + vfree(sig); + sig = NULL; + } + + return sig; +} + +int +eay_rsa_verify(src, sig, pubkey) + vchar_t *src, *sig, *pubkey; +{ + EVP_PKEY *evp; + u_char *bp = pubkey->v; + vchar_t *xbuf = NULL; + int pad = RSA_PKCS1_PADDING; + int len = 0; + int error; + + evp = d2i_PUBKEY(NULL, &bp, pubkey->l); + if (evp == NULL) +#ifndef EAYDEBUG + return NULL; +#endif + + len = RSA_size(evp->pkey.rsa); + + xbuf = vmalloc(len); + if (xbuf == NULL) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#endif + EVP_PKEY_free(evp); + return -1; + } + + len = RSA_public_decrypt(sig->l, sig->v, xbuf->v, evp->pkey.rsa, pad); +#ifndef EAYDEBUG + if (len == 0 || len != src->l) + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#endif + EVP_PKEY_free(evp); + if (len == 0 || len != src->l) { + vfree(xbuf); + return -1; + } + + error = memcmp(src->v, xbuf->v, src->l); + vfree(xbuf); + if (error != 0) + return -1; + + return 0; +} + +/* + * get error string + * MUST load ERR_load_crypto_strings() first. + */ +char * +eay_strerror() +{ + static char ebuf[512]; + int len = 0, n; + unsigned long l; + char buf[200]; +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + const char *file, *data; +#else + char *file, *data; +#endif + int line, flags; + unsigned long es; + + es = CRYPTO_thread_id(); + + while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0){ + n = snprintf(ebuf + len, sizeof(ebuf) - len, + "%lu:%s:%s:%d:%s ", + es, ERR_error_string(l, buf), file, line, + (flags & ERR_TXT_STRING) ? data : ""); + if (n < 0 || n >= sizeof(ebuf) - len) + break; + len += n; + if (sizeof(ebuf) < len) + break; + } + + return ebuf; +} + +void +eay_init_error() +{ + ERR_load_crypto_strings(); +} + +/* + * DES-CBC + */ +vchar_t * +eay_des_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks; + + if (des_key_sched((void *)key->v, ks) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks, (void *)iv->v, DES_ENCRYPT); + + return res; +} + +vchar_t * +eay_des_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks; + + if (des_key_sched((void *)key->v, ks) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks, (void *)iv->v, DES_DECRYPT); + + return res; +} + +int +eay_des_weakkey(key) + vchar_t *key; +{ + return des_is_weak_key((void *)key->v); +} + +int +eay_des_keylen(len) + int len; +{ + if (len != 0 && len != 64) + return -1; + return 64; +} + +#ifdef HAVE_OPENSSL_IDEA_H +/* + * IDEA-CBC + */ +vchar_t * +eay_idea_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + IDEA_KEY_SCHEDULE ks; + + idea_set_encrypt_key(key->v, &ks); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + idea_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, IDEA_ENCRYPT); + + return res; +} + +vchar_t * +eay_idea_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + IDEA_KEY_SCHEDULE ks, dks; + + idea_set_encrypt_key(key->v, &ks); + idea_set_decrypt_key(&ks, &dks); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + idea_cbc_encrypt(data->v, res->v, data->l, + &dks, iv->v, IDEA_DECRYPT); + + return res; +} + +int +eay_idea_weakkey(key) + vchar_t *key; +{ + return 0; /* XXX */ +} + +int +eay_idea_keylen(len) + int len; +{ + if (len != 0 && len != 128) + return -1; + return 128; +} +#endif + +/* + * BLOWFISH-CBC + */ +vchar_t * +eay_bf_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + BF_KEY ks; + + BF_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + BF_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, BF_ENCRYPT); + + return res; +} + +vchar_t * +eay_bf_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + BF_KEY ks; + + BF_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + BF_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, BF_DECRYPT); + + return res; +} + +int +eay_bf_weakkey(key) + vchar_t *key; +{ + return 0; /* XXX to be done. refer to RFC 2451 */ +} + +int +eay_bf_keylen(len) + int len; +{ + if (len == 0) + return 448; + if (len < 40 || len > 448) + return -1; + return len + 7 / 8; +} + +#ifdef HAVE_OPENSSL_RC5_H +/* + * RC5-CBC + */ +vchar_t * +eay_rc5_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + RC5_32_KEY ks; + + /* in RFC 2451, there is information about the number of round. */ + RC5_32_set_key(&ks, key->l, key->v, 16); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + RC5_32_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, RC5_ENCRYPT); + + return res; +} + +vchar_t * +eay_rc5_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + RC5_32_KEY ks; + + /* in RFC 2451, there is information about the number of round. */ + RC5_32_set_key(&ks, key->l, key->v, 16); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + RC5_32_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, RC5_DECRYPT); + + return res; +} + +int +eay_rc5_weakkey(key) + vchar_t *key; +{ + return 0; /* No known weak keys when used with 16 rounds. */ + +} + +int +eay_rc5_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len < 40 || len > 2040) + return -1; + return len + 7 / 8; +} +#endif + +/* + * 3DES-CBC + */ +vchar_t * +eay_3des_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks1, ks2, ks3; + + if (key->l < 24) + return NULL; + + if (des_key_sched((void *)key->v, ks1) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 8), ks2) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 16), ks3) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_ede3_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks1, ks2, ks3, (void *)iv->v, DES_ENCRYPT); + + return res; +} + +vchar_t * +eay_3des_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks1, ks2, ks3; + + if (key->l < 24) + return NULL; + + if (des_key_sched((void *)key->v, ks1) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 8), ks2) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 16), ks3) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_ede3_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks1, ks2, ks3, (void *)iv->v, DES_DECRYPT); + + return res; +} + +int +eay_3des_weakkey(key) + vchar_t *key; +{ + if (key->l < 24) + return NULL; + + return (des_is_weak_key((void *)key->v) + || des_is_weak_key((void *)(key->v + 8)) + || des_is_weak_key((void *)(key->v + 16))); +} + +int +eay_3des_keylen(len) + int len; +{ + if (len != 0 && len != 192) + return -1; + return 192; +} + +/* + * CAST-CBC + */ +vchar_t * +eay_cast_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + CAST_KEY ks; + + CAST_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + CAST_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, DES_ENCRYPT); + + return res; +} + +vchar_t * +eay_cast_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + CAST_KEY ks; + + CAST_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + CAST_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, DES_DECRYPT); + + return res; +} + +int +eay_cast_weakkey(key) + vchar_t *key; +{ + return 0; /* No known weak keys. */ +} + +int +eay_cast_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len < 40 || len > 128) + return -1; + return len + 7 / 8; +} + +/* + * AES(RIJNDAEL)-CBC + */ +vchar_t * +eay_aes_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + keyInstance k; + cipherInstance c; + + memset(&k, 0, sizeof(k)); + if (rijndael_makeKey(&k, DIR_ENCRYPT, key->l << 3, key->v) < 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* encryption data */ + memset(&c, 0, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0) + return NULL; + if (rijndael_blockEncrypt(&c, &k, data->v, data->l << 3, res->v) < 0) + return NULL; + + return res; +} + +vchar_t * +eay_aes_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + keyInstance k; + cipherInstance c; + + memset(&k, 0, sizeof(k)); + if (rijndael_makeKey(&k, DIR_DECRYPT, key->l << 3, key->v) < 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + memset(&c, 0, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0) + return NULL; + if (rijndael_blockDecrypt(&c, &k, data->v, data->l << 3, res->v) < 0) + return NULL; + + return res; +} + +int +eay_aes_weakkey(key) + vchar_t *key; +{ + return 0; +} + +int +eay_aes_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len != 128 && len != 192 && len != 256) + return -1; + return len; +} + +/* for ipsec part */ +int +eay_null_hashlen() +{ + return 0; +} + +int +eay_kpdk_hashlen() +{ + return 0; +} + +int +eay_twofish_keylen(len) + int len; +{ + if (len < 0 || len > 256) + return -1; + return len; +} + +/* + * HMAC functions + */ +static caddr_t +eay_hmac_init(key, md) + vchar_t *key; + const EVP_MD *md; +{ + HMAC_CTX *c = racoon_malloc(sizeof(*c)); + + HMAC_Init(c, key->v, key->l, md); + + return (caddr_t)c; +} + +/* + * HMAC SHA2-512 + */ +vchar_t * +eay_hmacsha2_512_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_512_init(key); + eay_hmacsha2_512_update(ctx, data); + res = eay_hmacsha2_512_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_512_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha2_512()); +} + +void +eay_hmacsha2_512_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha2_512_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA512_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_512 length mismatch %d.\n", res->l); +#else + printf("hmac sha2_512 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC SHA2-384 + */ +vchar_t * +eay_hmacsha2_384_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_384_init(key); + eay_hmacsha2_384_update(ctx, data); + res = eay_hmacsha2_384_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_384_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha2_384()); +} + +void +eay_hmacsha2_384_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha2_384_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA384_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_384 length mismatch %d.\n", res->l); +#else + printf("hmac sha2_384 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC SHA2-256 + */ +vchar_t * +eay_hmacsha2_256_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_256_init(key); + eay_hmacsha2_256_update(ctx, data); + res = eay_hmacsha2_256_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_256_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha2_256()); +} + +void +eay_hmacsha2_256_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha2_256_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA256_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_256 length mismatch %d.\n", res->l); +#else + printf("hmac sha2_256 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC SHA1 + */ +vchar_t * +eay_hmacsha1_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha1_init(key); + eay_hmacsha1_update(ctx, data); + res = eay_hmacsha1_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha1_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha1()); +} + +void +eay_hmacsha1_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha1_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha1 length mismatch %d.\n", res->l); +#else + printf("hmac sha1 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC MD5 + */ +vchar_t * +eay_hmacmd5_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacmd5_init(key); + eay_hmacmd5_update(ctx, data); + res = eay_hmacmd5_final(ctx); + + return(res); +} + +caddr_t +eay_hmacmd5_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_md5()); +} + +void +eay_hmacmd5_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacmd5_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (MD5_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac md5 length mismatch %d.\n", res->l); +#else + printf("hmac md5 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * SHA2-512 functions + */ +caddr_t +eay_sha2_512_init() +{ + SHA512_CTX *c = racoon_malloc(sizeof(*c)); + + SHA512_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_512_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA512_Update((SHA512_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_512_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0) + return(0); + + SHA512_Final(res->v, (SHA512_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_512_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_512_init(); + eay_sha2_512_update(ctx, data); + res = eay_sha2_512_final(ctx); + + return(res); +} + +int +eay_sha2_512_hashlen() +{ + return SHA512_DIGEST_LENGTH << 3; +} + +/* + * SHA2-384 functions + */ +caddr_t +eay_sha2_384_init() +{ + SHA384_CTX *c = racoon_malloc(sizeof(*c)); + + SHA384_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_384_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA384_Update((SHA384_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_384_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0) + return(0); + + SHA384_Final(res->v, (SHA384_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_384_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_384_init(); + eay_sha2_384_update(ctx, data); + res = eay_sha2_384_final(ctx); + + return(res); +} + +int +eay_sha2_384_hashlen() +{ + return SHA384_DIGEST_LENGTH << 3; +} + +/* + * SHA2-256 functions + */ +caddr_t +eay_sha2_256_init() +{ + SHA256_CTX *c = racoon_malloc(sizeof(*c)); + + SHA256_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_256_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA256_Update((SHA256_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_256_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0) + return(0); + + SHA256_Final(res->v, (SHA256_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_256_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_256_init(); + eay_sha2_256_update(ctx, data); + res = eay_sha2_256_final(ctx); + + return(res); +} + +int +eay_sha2_256_hashlen() +{ + return SHA256_DIGEST_LENGTH << 3; +} + +/* + * SHA functions + */ +caddr_t +eay_sha1_init() +{ + SHA_CTX *c = racoon_malloc(sizeof(*c)); + + SHA1_Init(c); + + return((caddr_t)c); +} + +void +eay_sha1_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA1_Update((SHA_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha1_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0) + return(0); + + SHA1_Final(res->v, (SHA_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha1_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha1_init(); + eay_sha1_update(ctx, data); + res = eay_sha1_final(ctx); + + return(res); +} + +int +eay_sha1_hashlen() +{ + return SHA_DIGEST_LENGTH << 3; +} + +/* + * MD5 functions + */ +caddr_t +eay_md5_init() +{ + MD5_CTX *c = racoon_malloc(sizeof(*c)); + + MD5_Init(c); + + return((caddr_t)c); +} + +void +eay_md5_update(c, data) + caddr_t c; + vchar_t *data; +{ + MD5_Update((MD5_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_md5_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0) + return(0); + + MD5_Final(res->v, (MD5_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_md5_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_md5_init(); + eay_md5_update(ctx, data); + res = eay_md5_final(ctx); + + return(res); +} + +int +eay_md5_hashlen() +{ + return MD5_DIGEST_LENGTH << 3; +} + +/* + * eay_set_random + * size: number of bytes. + */ +vchar_t * +eay_set_random(size) + u_int32_t size; +{ + BIGNUM *r = NULL; + vchar_t *res = 0; + + if ((r = BN_new()) == NULL) + goto end; + BN_rand(r, size * 8, 0, 0); + eay_bn2v(&res, r); + +end: + if (r) + BN_free(r); + return(res); +} + +/* DH */ +int +eay_dh_generate(prime, g, publen, pub, priv) + vchar_t *prime, **pub, **priv; + u_int publen; + u_int32_t g; +{ + BIGNUM *p = NULL; + DH *dh = NULL; + int error = -1; + + /* initialize */ + /* pre-process to generate number */ + if (eay_v2bn(&p, prime) < 0) + goto end; + + if ((dh = DH_new()) == NULL) + goto end; + dh->p = p; + p = NULL; /* p is now part of dh structure */ + dh->g = NULL; + if ((dh->g = BN_new()) == NULL) + goto end; + if (!BN_set_word(dh->g, g)) + goto end; + + if (publen != 0) + dh->length = publen; + + /* generate public and private number */ + if (!DH_generate_key(dh)) + goto end; + + /* copy results to buffers */ + if (eay_bn2v(pub, dh->pub_key) < 0) + goto end; + if (eay_bn2v(priv, dh->priv_key) < 0) { + vfree(*pub); + goto end; + } + + error = 0; + +end: + if (dh != NULL) + DH_free(dh); + if (p != 0) + BN_free(p); + return(error); +} + +int +eay_dh_compute(prime, g, pub, priv, pub2, key) + vchar_t *prime, *pub, *priv, *pub2, **key; + u_int32_t g; +{ + BIGNUM *dh_pub = NULL; + DH *dh = NULL; + int l; + caddr_t v = NULL; + int error = -1; + + /* make public number to compute */ + if (eay_v2bn(&dh_pub, pub2) < 0) + goto end; + + /* make DH structure */ + if ((dh = DH_new()) == NULL) + goto end; + if (eay_v2bn(&dh->p, prime) < 0) + goto end; + if (eay_v2bn(&dh->pub_key, pub) < 0) + goto end; + if (eay_v2bn(&dh->priv_key, priv) < 0) + goto end; + dh->length = pub2->l * 8; + + dh->g = NULL; + if ((dh->g = BN_new()) == NULL) + goto end; + if (!BN_set_word(dh->g, g)) + goto end; + + if ((v = (caddr_t)racoon_calloc(prime->l, sizeof(u_char))) == NULL) + goto end; + if ((l = DH_compute_key(v, dh_pub, dh)) == -1) + goto end; + memcpy((*key)->v + (prime->l - l), v, l); + + error = 0; + +end: + if (dh_pub != NULL) + BN_free(dh_pub); + if (dh != NULL) + DH_free(dh); + if (v != NULL) + racoon_free(v); + return(error); +} + +#if 1 +int +eay_v2bn(bn, var) + BIGNUM **bn; + vchar_t *var; +{ + if ((*bn = BN_bin2bn(var->v, var->l, NULL)) == NULL) + return -1; + + return 0; +} +#else +/* + * convert vchar_t <-> BIGNUM. + * + * vchar_t: unit is u_char, network endian, most significant byte first. + * BIGNUM: unit is BN_ULONG, each of BN_ULONG is in host endian, + * least significant BN_ULONG must come first. + * + * hex value of "0x3ffe050104" is represented as follows: + * vchar_t: 3f fe 05 01 04 + * BIGNUM (BN_ULONG = u_int8_t): 04 01 05 fe 3f + * BIGNUM (BN_ULONG = u_int16_t): 0x0104 0xfe05 0x003f + * BIGNUM (BN_ULONG = u_int32_t_t): 0xfe050104 0x0000003f + */ +int +eay_v2bn(bn, var) + BIGNUM **bn; + vchar_t *var; +{ + u_char *p; + u_char *q; + BN_ULONG *r; + int l; + BN_ULONG num; + + *bn = BN_new(); + if (*bn == NULL) + goto err; + l = (var->l * 8 + BN_BITS2 - 1) / BN_BITS2; + if (bn_expand(*bn, l * BN_BITS2) == NULL) + goto err; + (*bn)->top = l; + + /* scan from least significant byte */ + p = (u_char *)var->v; + q = (u_char *)(var->v + var->l); + r = (*bn)->d; + num = 0; + l = 0; + do { + q--; + num = num | ((BN_ULONG)*q << (l++ * 8)); + if (l == BN_BYTES) { + *r++ = num; + num = 0; + l = 0; + } + } while (p < q); + if (l) + *r = num; + return 0; + +err: + if (*bn) + BN_free(*bn); + return -1; +} +#endif + +int +eay_bn2v(var, bn) + vchar_t **var; + BIGNUM *bn; +{ + *var = vmalloc(bn->top * BN_BYTES); + if (*var == NULL) + return(-1); + + (*var)->l = BN_bn2bin(bn, (*var)->v); + + return 0; +} + +const char * +eay_version() +{ + return SSLeay_version(SSLEAY_VERSION); +} diff --git a/eaytest.tproj/crypto_openssl.h b/eaytest.tproj/crypto_openssl.h new file mode 100644 index 0000000..51c920f --- /dev/null +++ b/eaytest.tproj/crypto_openssl.h @@ -0,0 +1,189 @@ +/* $KAME: crypto_openssl.h,v 1.23 2001/08/14 12:26:06 sakane 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. 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. + */ + +#ifdef HAVE_SIGNING_C +/* X509 Certificate */ +#define GENT_OTHERNAME 0 +#define GENT_EMAIL 1 +#define GENT_DNS 2 +#define GENT_X400 3 +#define GENT_DIRNAME 4 +#define GENT_EDIPARTY 5 +#define GENT_URI 6 +#define GENT_IPADD 7 +#define GENT_RID 8 + +extern vchar_t *eay_str2asn1dn __P((char *, int)); +extern int eay_cmp_asn1dn __P((vchar_t *, vchar_t *)); +extern int eay_check_x509cert __P((vchar_t *, char *)); +extern vchar_t *eay_get_x509asn1subjectname __P((vchar_t *)); +extern int eay_get_x509subjectaltname __P((vchar_t *, char **, int *, int)); +extern char *eay_get_x509text __P((vchar_t *)); +extern vchar_t *eay_get_x509cert __P((char *)); +extern vchar_t *eay_get_x509sign __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_check_x509sign __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_check_pkcs7sign __P((vchar_t *, vchar_t *, vchar_t *)); + +/* RSA */ +extern vchar_t *eay_rsa_sign __P((vchar_t *, vchar_t *)); +extern int eay_rsa_verify __P((vchar_t *, vchar_t *, vchar_t *)); + +/* ASN.1 */ +extern vchar_t *eay_get_pkcs1privkey __P((char *)); +extern vchar_t *eay_get_pkcs1pubkey __P((char *)); +#endif + +/* string error */ +extern char *eay_strerror __P((void)); +extern void eay_init_error __P((void)); + +/* DES */ +extern vchar_t *eay_des_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_des_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_des_weakkey __P((vchar_t *)); +extern int eay_des_keylen __P((int)); + +/* IDEA */ +extern vchar_t *eay_idea_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_idea_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_idea_weakkey __P((vchar_t *)); +extern int eay_idea_keylen __P((int)); + +/* blowfish */ +extern vchar_t *eay_bf_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_bf_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_bf_weakkey __P((vchar_t *)); +extern int eay_bf_keylen __P((int)); + +/* RC5 */ +extern vchar_t *eay_rc5_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_rc5_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_rc5_weakkey __P((vchar_t *)); +extern int eay_rc5_keylen __P((int)); + +/* 3DES */ +extern vchar_t *eay_3des_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_3des_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_3des_weakkey __P((vchar_t *)); +extern int eay_3des_keylen __P((int)); + +/* CAST */ +extern vchar_t *eay_cast_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_cast_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_cast_weakkey __P((vchar_t *)); +extern int eay_cast_keylen __P((int)); + +/* AES(RIJNDAEL) */ +extern vchar_t *eay_aes_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_aes_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_aes_weakkey __P((vchar_t *)); +extern int eay_aes_keylen __P((int)); + +/* misc */ +extern int eay_null_hashlen __P((void)); +extern int eay_kpdk_hashlen __P((void)); +extern int eay_twofish_keylen __P((int)); + +/* hash */ +/* HMAC SHA2 */ +extern vchar_t *eay_hmacsha2_512_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha2_512_init __P((vchar_t *)); +extern void eay_hmacsha2_512_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha2_512_final __P((caddr_t)); +extern vchar_t *eay_hmacsha2_384_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha2_384_init __P((vchar_t *)); +extern void eay_hmacsha2_384_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha2_384_final __P((caddr_t)); +extern vchar_t *eay_hmacsha2_256_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha2_256_init __P((vchar_t *)); +extern void eay_hmacsha2_256_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha2_256_final __P((caddr_t)); +/* HMAC SHA1 */ +extern vchar_t *eay_hmacsha1_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha1_init __P((vchar_t *)); +extern void eay_hmacsha1_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha1_final __P((caddr_t)); +/* HMAC MD5 */ +extern vchar_t *eay_hmacmd5_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacmd5_init __P((vchar_t *)); +extern void eay_hmacmd5_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacmd5_final __P((caddr_t)); + +/* SHA2 functions */ +extern caddr_t eay_sha2_512_init __P((void)); +extern void eay_sha2_512_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha2_512_final __P((caddr_t)); +extern vchar_t *eay_sha2_512_one __P((vchar_t *)); +extern int eay_sha2_512_hashlen __P((void)); + +extern caddr_t eay_sha2_384_init __P((void)); +extern void eay_sha2_384_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha2_384_final __P((caddr_t)); +extern vchar_t *eay_sha2_384_one __P((vchar_t *)); +extern int eay_sha2_384_hashlen __P((void)); + +extern caddr_t eay_sha2_256_init __P((void)); +extern void eay_sha2_256_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha2_256_final __P((caddr_t)); +extern vchar_t *eay_sha2_256_one __P((vchar_t *)); +extern int eay_sha2_256_hashlen __P((void)); + +/* SHA functions */ +extern caddr_t eay_sha1_init __P((void)); +extern void eay_sha1_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha1_final __P((caddr_t)); +extern vchar_t *eay_sha1_one __P((vchar_t *)); +extern int eay_sha1_hashlen __P((void)); + +/* MD5 functions */ +extern caddr_t eay_md5_init __P((void)); +extern void eay_md5_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_md5_final __P((caddr_t)); +extern vchar_t *eay_md5_one __P((vchar_t *)); +extern int eay_md5_hashlen __P((void)); + +/* eay_set_random */ +extern vchar_t *eay_set_random __P((u_int32_t)); + +/* DH */ +extern int eay_dh_generate __P((vchar_t *, u_int32_t, u_int, vchar_t **, vchar_t **)); +extern int eay_dh_compute __P((vchar_t *, u_int32_t, vchar_t *, vchar_t *, vchar_t *, vchar_t **)); + +/* misc */ +extern int eay_revbnl __P((vchar_t *)); +#include +extern int eay_v2bn __P((BIGNUM **, vchar_t *)); +extern int eay_bn2v __P((vchar_t **, BIGNUM *)); + +extern const char *eay_version __P((void)); + +#define CBC_BLOCKLEN 8 +#define IPSEC_ENCRYPTKEYLEN 8 diff --git a/eaytest.tproj/eaytest.c b/eaytest.tproj/eaytest.c new file mode 100644 index 0000000..0f046d4 --- /dev/null +++ b/eaytest.tproj/eaytest.c @@ -0,0 +1,940 @@ +/* $KAME: eaytest.c,v 1.38 2001/11/16 04:12:59 sakane 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. 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. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "var.h" +#include "vmbuf.h" +#include "misc.h" +#include "debug.h" +#include "str2val.h" + +#include "oakley.h" +#include "dhgroup.h" +#include "crypto_openssl.h" + +#define PVDUMP(var) hexdump((var)->v, (var)->l) + +u_int32_t loglevel = 4; + +/* prototype */ + +void rsatest __P((int, char **)); +static vchar_t *pem_read_buf __P((char *)); +void certtest __P((int, char **)); +static char **getcerts __P((char *)); +void ciphertest __P((int, char **)); +void hmactest __P((int, char **)); +void sha2test __P((int, char **)); +void sha1test __P((int, char **)); +void md5test __P((int, char **)); +void dhtest __P((int, char **)); +void bntest __P((int, char **)); +void Usage __P((void)); + +/* test */ + +void +rsatest(ac, av) + int ac; + char **av; +{ + char *text = "this is test."; + vchar_t src; + vchar_t *priv, *pub, *sig; + int error; + + char *pkcs1 = +"-----BEGIN RSA PRIVATE KEY-----\n" +"MIICXQIBAAKBgQChe5/Fzk9SA0vCKBOcu9jBcLb9oLv50PeuEfQojhakY+OH8A3Q\n" +"M8A0qIDG6uhTNGPvzCWb/+mKeOB48n5HJpLxlDFyP3kyd2yXHIZ/MN8g1nh4FsB0\n" +"iTkk8QUCJkkan6FCOBrIeLEsGA5AdodzuR+khnCMt8vO+NFHZYKAQeynyQIDAQAB\n" +"AoGAOfDcnCHxjhDGrwyoNNWl6Yqi7hAtQm67YAbrH14UO7nnmxAENM9MyNgpFLaW\n" +"07v5m8IZQIcradcDXAJOUwNBN8E06UflwEYCaScIwndvr5UpVlN3e2NC6Wyg2yC7\n" +"GarxQput3zj35XNR5bK42UneU0H6zDxpHWqI1SwE+ToAHu0CQQDNl9gUJTpg0L09\n" +"HkbE5jeb8bA5I20nKqBOBP0v5tnzpwu41umQwk9I7Ru0ucD7j+DW4k8otadW+FnI\n" +"G1M1MpSjAkEAyRMt4bN8otfpOpsOQWzw4jQtouohOxRFCrQTntHhU20PrQnQLZWs\n" +"pOVzqCjRytYtkPEUA1z8QK5gGcVPcOQsowJBALmt2rwPB1NrEo5Bat7noO+Zb3Ob\n" +"WDiYWeE8xkHd95gDlSWiC53ur9aINo6ZeP556jGIgL+el/yHHecJLrQL84sCQH48\n" +"zUxq/C/cb++8UzneJGlPqusiJNTLiAENR1gpmlZfHT1c8Nb9phMsfu0vG29GAfuC\n" +"bzchVLljALCNQK+2gRMCQQCNIgN+R9mRWZhFAcC1sq++YnuSBlw4VwdL/fd1Yg9e\n" +"Ul+U98yPl/NXt8Rs4TRBFcOZjkFI8xv0hQtevTgTmgz+\n" +"-----END RSA PRIVATE KEY-----\n\n"; + char *pubkey = +"-----BEGIN PUBLIC KEY-----\n" +"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChe5/Fzk9SA0vCKBOcu9jBcLb9\n" +"oLv50PeuEfQojhakY+OH8A3QM8A0qIDG6uhTNGPvzCWb/+mKeOB48n5HJpLxlDFy\n" +"P3kyd2yXHIZ/MN8g1nh4FsB0iTkk8QUCJkkan6FCOBrIeLEsGA5AdodzuR+khnCM\n" +"t8vO+NFHZYKAQeynyQIDAQAB\n" +"-----END PUBLIC KEY-----\n\n"; + + priv = pem_read_buf(pkcs1); + + src.v = text; + src.l = strlen(text); + + /* sign */ + sig = eay_rsa_sign(&src, priv); + if (sig == NULL) + printf("sign failed. %s\n", eay_strerror()); + printf("RSA signed data.\n"); + PVDUMP(sig); + + /* verify */ + pub = pem_read_buf(pubkey); + error = eay_rsa_verify(&src, sig, pub); + if (error) + printf("verifying failed.\n"); + else + printf("verified.\n"); +} + +static vchar_t * +pem_read_buf(buf) + char *buf; +{ + BIO *bio; + char *nm = NULL, *header = NULL; + unsigned char *data = NULL; + long len; + vchar_t *ret; + int error; + + bio = BIO_new_mem_buf(buf, strlen(buf)); + error = PEM_read_bio(bio, &nm, &header, &data, &len); + if (error == 0) + errx(1, "%s", eay_strerror()); + ret = vmalloc(len); + if (ret == NULL) + err(1, "vmalloc"); + memcpy(ret->v, data, len); + + return ret; +} + +void +certtest(ac, av) + int ac; + char **av; +{ + char *certpath; + char **certs; + int type; + int error; + + printf("\n**Test for Certificate.**\n"); + + { + char dnstr[] = "C=JP, ST=Kanagawa, L=Fujisawa, O=WIDE Project, OU=KAME Project, CN=Shoichi Sakane/Email=sakane@kame.net"; + vchar_t *asn1dn = NULL, asn1dn0; + char dn0[] = { + 0x30,0x81,0x9a,0x31,0x0b,0x30,0x09,0x06, + 0x03,0x55,0x04,0x06,0x13,0x02,0x4a,0x50, + 0x31,0x11,0x30,0x0f,0x06,0x03,0x55,0x04, + 0x08,0x13,0x08,0x4b,0x61,0x6e,0x61,0x67, + 0x61,0x77,0x61,0x31,0x11,0x30,0x0f,0x06, + 0x03,0x55,0x04,0x07,0x13,0x08,0x46,0x75, + 0x6a,0x69,0x73,0x61,0x77,0x61,0x31,0x15, + 0x30,0x13,0x06,0x03,0x55,0x04,0x0a,0x13, + 0x0c,0x57,0x49,0x44,0x45,0x20,0x50,0x72, + 0x6f,0x6a,0x65,0x63,0x74,0x31,0x15,0x30, + 0x13,0x06,0x03,0x55,0x04,0x0b,0x13,0x0c, + 0x4b,0x41,0x4d,0x45,0x20,0x50,0x72,0x6f, + 0x6a,0x65,0x63,0x74,0x31,0x17,0x30,0x15, + 0x06,0x03,0x55,0x04,0x03,0x13,0x0e,0x53, + 0x68,0x6f,0x69,0x63,0x68,0x69,0x20,0x53, + 0x61,0x6b,0x61,0x6e,0x65,0x31,0x1e,0x30, + 0x1c,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7, + 0x0d,0x01,0x09,0x01, + 0x0c, /* <== XXX */ + 0x0f,0x73,0x61, + 0x6b,0x61,0x6e,0x65,0x40,0x6b,0x61,0x6d, + 0x65,0x2e,0x6e,0x65,0x74, + }; + + printf("check to convert the string into subjectName.\n"); + printf("%s\n", dnstr); + + asn1dn0.v = dn0; + asn1dn0.l = sizeof(dn0); + + asn1dn = eay_str2asn1dn(dnstr, sizeof(dnstr)); + if (asn1dn == NULL || asn1dn->l != asn1dn0.l) + errx(1, "asn1dn length mismatched.\n"); + + /* + * NOTE: The value pointed by "<==" above is different from the + * return of eay_str2asn1dn(). but eay_cmp_asn1dn() can distinguish + * both of the names are same name. + */ + if (eay_cmp_asn1dn(&asn1dn0, asn1dn)) + errx(1, "asn1dn mismatched.\n"); + vfree(asn1dn); + + printf("succeed.\n"); + } + + eay_init_error(); + + /* get certs */ + if (ac > 1) { + certpath = *(av + 1); + certs = getcerts(certpath); + } else { + printf("\nCAUTION: These certificates are probably invalid " + "on your environment because you don't have their " + "issuer's certs in your environment.\n\n"); + + certpath = "/usr/local/openssl/certs"; + certs = getcerts(NULL); + } + + while (*certs != NULL) { + + vchar_t c; + char *str; + vchar_t *vstr; + + printf("===CERT===\n"); + + c.v = *certs; + c.l = strlen(*certs); + + /* print text */ + str = eay_get_x509text(&c); + printf("%s", str); + racoon_free(str); + + /* print ASN.1 of subject name */ + vstr = eay_get_x509asn1subjectname(&c); + if (!vstr) + return; + PVDUMP(vstr); + printf("\n"); + vfree(vstr); + + /* print subject alt name */ + { + int pos; + for (pos = 1; ; pos++) { + error = eay_get_x509subjectaltname(&c, &str, &type, pos); + if (error) { + printf("no subjectaltname found.\n"); + break; + } + if (!str) + break; + printf("SubjectAltName: %d: %s\n", type, str); + racoon_free(str); + } + } + + error = eay_check_x509cert(&c, certpath); + if (error) + printf("ERROR: cert is invalid.\n"); + printf("\n"); + + certs++; + } +} + +static char ** +getcerts(path) + char *path; +{ + char **certs = NULL, **p; + DIR *dirp; + struct dirent *dp; + struct stat sb; + char buf[512]; + int len; + int n; + int fd; + + static char *samplecerts[] = { +/* self signed */ +"-----BEGIN CERTIFICATE-----\n" +"MIICpTCCAg4CAQAwDQYJKoZIhvcNAQEEBQAwgZoxCzAJBgNVBAYTAkpQMREwDwYD\n" +"VQQIEwhLYW5hZ2F3YTERMA8GA1UEBxMIRnVqaXNhd2ExFTATBgNVBAoTDFdJREUg\n" +"UHJvamVjdDEVMBMGA1UECxMMS0FNRSBQcm9qZWN0MRcwFQYDVQQDEw5TaG9pY2hp\n" +"IFNha2FuZTEeMBwGCSqGSIb3DQEJARYPc2FrYW5lQGthbWUubmV0MB4XDTAwMDgy\n" +"NDAxMzc0NFoXDTAwMDkyMzAxMzc0NFowgZoxCzAJBgNVBAYTAkpQMREwDwYDVQQI\n" +"EwhLYW5hZ2F3YTERMA8GA1UEBxMIRnVqaXNhd2ExFTATBgNVBAoTDFdJREUgUHJv\n" +"amVjdDEVMBMGA1UECxMMS0FNRSBQcm9qZWN0MRcwFQYDVQQDEw5TaG9pY2hpIFNh\n" +"a2FuZTEeMBwGCSqGSIb3DQEJARYPc2FrYW5lQGthbWUubmV0MIGfMA0GCSqGSIb3\n" +"DQEBAQUAA4GNADCBiQKBgQCpIQG/H3zn4czAmPBcbkDrYxE1A9vcpghpib3Of0Op\n" +"SsiWIBOyIMiVAzK/I/JotWp3Vdn5fzGp/7DGAbWXAALas2xHkNmTMPpu6qhmNQ57\n" +"kJHZHal24mgc1hwbrI9fb5olvIexx9a1riNPnKMRVHzXYizsyMbf+lJJmZ8QFhWN\n" +"twIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACKs6X/BYycuHI3iop403R3XWMHHnNBN\n" +"5XTHVWiWgR1cMWkq/dp51gn+nPftpdAaYGpqGkiHGhZcXLoBaX9uON3p+7av+sQN\n" +"plXwnvUf2Zsgu+fojskS0gKcDlYiq1O8TOaBgJouFZgr1q6PiYjVEJGogAP28+HN\n" +"M4o+GBFbFoqK\n" +"-----END CERTIFICATE-----\n\n", +/* signed by SSH testing CA + CA1 + CA2 */ +"-----BEGIN X509 CERTIFICATE-----\n" +"MIICtTCCAj+gAwIBAgIEOaR8NjANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJG\n" +"STEkMCIGA1UEChMbU1NIIENvbW11bmljYXRpb25zIFNlY3VyaXR5MREwDwYDVQQL\n" +"EwhXZWIgdGVzdDEbMBkGA1UEAxMSVGVzdCBDQSAxIHN1YiBjYSAyMB4XDTAwMDgy\n" +"NDAwMDAwMFoXDTAwMTAwMTAwMDAwMFowgZoxCzAJBgNVBAYTAkpQMREwDwYDVQQI\n" +"EwhLYW5hZ2F3YTERMA8GA1UEBxMIRnVqaXNhd2ExFTATBgNVBAoTDFdJREUgUHJv\n" +"amVjdDEVMBMGA1UECxMMS0FNRSBQcm9qZWN0MRcwFQYDVQQDEw5TaG9pY2hpIFNh\n" +"a2FuZTEeMBwGCSqGSIb3DQEJAQwPc2FrYW5lQGthbWUubmV0MIGfMA0GCSqGSIb3\n" +"DQEBAQUAA4GNADCBiQKBgQCpIQG/H3zn4czAmPBcbkDrYxE1A9vcpghpib3Of0Op\n" +"SsiWIBOyIMiVAzK/I/JotWp3Vdn5fzGp/7DGAbWXAALas2xHkNmTMPpu6qhmNQ57\n" +"kJHZHal24mgc1hwbrI9fb5olvIexx9a1riNPnKMRVHzXYizsyMbf+lJJmZ8QFhWN\n" +"twIDAQABo18wXTALBgNVHQ8EBAMCBaAwGgYDVR0RBBMwEYEPc2FrYW5lQGthbWUu\n" +"bmV0MDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9sZGFwLnNzaC5maS9jcmxzL2Nh\n" +"MS0yLmNybDANBgkqhkiG9w0BAQUFAANhADtaqual41OWshF/rwCTuR6zySBJysGp\n" +"+qjkp5efCiYKhAu1L4WXlMsV/SNdzspui5tHasPBvUw8gzFsU/VW/B2zuQZkimf1\n" +"u6ZPjUb/vt8vLOPScP5MeH7xrTk9iigsqQ==\n" +"-----END X509 CERTIFICATE-----\n\n", +/* VP100 */ +"-----BEGIN CERTIFICATE-----\n" +"MIICXzCCAcigAwIBAgIEOXGBIzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJG\n" +"STEkMCIGA1UEChMbU1NIIENvbW11bmljYXRpb25zIFNlY3VyaXR5MREwDwYDVQQL\n" +"EwhXZWIgdGVzdDESMBAGA1UEAxMJVGVzdCBDQSAxMB4XDTAwMDcxNjAwMDAwMFoX\n" +"DTAwMDkwMTAwMDAwMFowNTELMAkGA1UEBhMCanAxETAPBgNVBAoTCHRhaGl0ZXN0\n" +"MRMwEQYDVQQDEwpmdXJ1a2F3YS0xMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKB\n" +"gQDUmI2RaAuoLvtRDbASwRhbkj/Oq0BBIKgAqbFknc/EanJSQwZQu82gD88nf7gG\n" +"VEioWmKPLDuEjz5JCuM+k5f7HYHI1wWmz1KFr7UA+avZm4Kp6YKnhuH7soZp7kBL\n" +"hTiZEpL0jdmCWLW3ZXoro55rmPrBsCd+bt8VU6tRZm5dUwIBKaNZMFcwCwYDVR0P\n" +"BAQDAgWgMBYGA1UdEQQPMA2CBVZQMTAwhwQKFIaFMDAGA1UdHwQpMCcwJaAjoCGG\n" +"H2h0dHA6Ly9sZGFwLnNzaC5maS9jcmxzL2NhMS5jcmwwDQYJKoZIhvcNAQEFBQAD\n" +"gYEAKJ/2Co/KYW65mwpGG3CBvsoRL8xyUMHGt6gQpFLHiiHuAdix1ADTL6uoFuYi\n" +"4sE5omQm1wKVv2ZhS03zDtUfKoVEv0HZ7IY3AU/FZT/M5gQvbt43Dki/ma3ock2I\n" +"PPhbLsvXm+GCVh3jvkYGk1zr7VERVeTPtmT+hW63lcxfFp4=\n" +"-----END CERTIFICATE-----\n\n", +/* IKED */ +"-----BEGIN CERTIFICATE-----\n" +"MIIEFTCCA7+gAwIBAgIKYU5X6AAAAAAACTANBgkqhkiG9w0BAQUFADCBljEpMCcG\n" +"CSqGSIb3DQEJARYaeS13YXRhbmFAc2RsLmhpdGFjaGkuY28uanAxCzAJBgNVBAYT\n" +"AkpQMREwDwYDVQQIEwhLQU5BR0FXQTERMA8GA1UEBxMIWW9rb2hhbWExEDAOBgNV\n" +"BAoTB0hJVEFDSEkxDDAKBgNVBAsTA1NETDEWMBQGA1UEAxMNSVBzZWMgVGVzdCBD\n" +"QTAeFw0wMDA3MTUwMjUxNDdaFw0wMTA3MTUwMzAxNDdaMEUxCzAJBgNVBAYTAkpQ\n" +"MREwDwYDVQQIEwhLQU5BR0FXQTEQMA4GA1UEChMHSElUQUNISTERMA8GA1UEAxMI\n" +"V0FUQU5BQkUwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA6Wja5A7Ldzrtx+rMWHEB\n" +"Cyt+/ZoG0qdFQbuuUiU1vOSq+1f+ZSCYAdTq13Lrr6Xfz3jDVFEZLPID9PSTFwq+\n" +"yQIDAQABo4ICPTCCAjkwDgYDVR0PAQH/BAQDAgTwMBMGA1UdJQQMMAoGCCsGAQUF\n" +"CAICMB0GA1UdDgQWBBTkv7/MH5Ra+S1zBAmnUIH5w8ZTUTCB0gYDVR0jBIHKMIHH\n" +"gBQsF2qoaTl5F3GFLKrttaxPJ8j4faGBnKSBmTCBljEpMCcGCSqGSIb3DQEJARYa\n" +"eS13YXRhbmFAc2RsLmhpdGFjaGkuY28uanAxCzAJBgNVBAYTAkpQMREwDwYDVQQI\n" +"EwhLQU5BR0FXQTERMA8GA1UEBxMIWW9rb2hhbWExEDAOBgNVBAoTB0hJVEFDSEkx\n" +"DDAKBgNVBAsTA1NETDEWMBQGA1UEAxMNSVBzZWMgVGVzdCBDQYIQeccIf4GYDIBA\n" +"rS6HSUt8XjB7BgNVHR8EdDByMDagNKAyhjBodHRwOi8vZmxvcmEyMjAvQ2VydEVu\n" +"cm9sbC9JUHNlYyUyMFRlc3QlMjBDQS5jcmwwOKA2oDSGMmZpbGU6Ly9cXGZsb3Jh\n" +"MjIwXENlcnRFbnJvbGxcSVBzZWMlMjBUZXN0JTIwQ0EuY3JsMIGgBggrBgEFBQcB\n" +"AQSBkzCBkDBFBggrBgEFBQcwAoY5aHR0cDovL2Zsb3JhMjIwL0NlcnRFbnJvbGwv\n" +"ZmxvcmEyMjBfSVBzZWMlMjBUZXN0JTIwQ0EuY3J0MEcGCCsGAQUFBzAChjtmaWxl\n" +"Oi8vXFxmbG9yYTIyMFxDZXJ0RW5yb2xsXGZsb3JhMjIwX0lQc2VjJTIwVGVzdCUy\n" +"MENBLmNydDANBgkqhkiG9w0BAQUFAANBAG8yZAWHb6g3zba453Hw5loojVDZO6fD\n" +"9lCsyaxeo9/+7x1JEEcdZ6qL7KKqe7ZBwza+hIN0ITkp2WEWo22gTz4=\n" +"-----END CERTIFICATE-----\n\n", +/* From Entrust */ +"-----BEGIN CERTIFICATE-----\n" +"MIIDXTCCAsagAwIBAgIEOb6khTANBgkqhkiG9w0BAQUFADA4MQswCQYDVQQGEwJV\n" +"UzEQMA4GA1UEChMHRW50cnVzdDEXMBUGA1UECxMOVlBOIEludGVyb3AgUk8wHhcN\n" +"MDAwOTE4MjMwMDM3WhcNMDMwOTE4MjMzMDM3WjBTMQswCQYDVQQGEwJVUzEQMA4G\n" +"A1UEChMHRW50cnVzdDEXMBUGA1UECxMOVlBOIEludGVyb3AgUk8xGTAXBgNVBAMT\n" +"EFNob2ljaGkgU2FrYW5lIDIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKj3\n" +"eXSt1qXxFXzpa265B/NQYk5BZN7pNJg0tlTKBTVV3UgpQ92Bx5DoNfZh11oIv0Sw\n" +"6YnG5p9F9ma36U9HDoD3hVTjAvQKy4ssCsnU1y6v5XOU1QvYQo6UTzgsXUTaIau4\n" +"Lrccl+nyoiNzy3lG51tLR8CxuA+3OOAK9xPjszClAgMBAAGjggFXMIIBUzBABgNV\n" +"HREEOTA3gQ9zYWthbmVAa2FtZS5uZXSHBM6vIHWCHjIwNi0xNzUtMzItMTE3LnZw\n" +"bndvcmtzaG9wLmNvbTATBgNVHSUEDDAKBggrBgEFBQgCAjALBgNVHQ8EBAMCAKAw\n" +"KwYDVR0QBCQwIoAPMjAwMDA5MTgyMzAwMzdagQ8yMDAyMTAyNTExMzAzN1owWgYD\n" +"VR0fBFMwUTBPoE2gS6RJMEcxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFbnRydXN0\n" +"MRcwFQYDVQQLEw5WUE4gSW50ZXJvcCBSTzENMAsGA1UEAxMEQ1JMMTAfBgNVHSME\n" +"GDAWgBTzVmhu0tBoWKwkZE5mXpooE9630DAdBgNVHQ4EFgQUEgBHPtXggJqei5Xz\n" +"92CrWXTJxfAwCQYDVR0TBAIwADAZBgkqhkiG9n0HQQAEDDAKGwRWNS4wAwIEsDAN\n" +"BgkqhkiG9w0BAQUFAAOBgQCIFriNGMUE8GH5LuDrTJfA8uGx8vLy2seljuo694TR\n" +"et/ojp9QnfOJ1PF9iAdGaEaSLfkwhY4fZNZzxic5HBoHLeo9BXLP7i7FByXjvOZC\n" +"Y8++0dC8NVvendIILcJBM5nbDq1TqIbb8K3SP80XhO5JLVJkoZiQftAMjo0peZPO\n" +"EQ==\n" +"-----END CERTIFICATE-----\n\n", + NULL, + }; + + if (path == NULL) + return (char **)&samplecerts; + + stat(path, &sb); + if (!(sb.st_mode & S_IFDIR)) { + printf("ERROR: %s is not directory.\n", path); + exit(0); + } + + dirp = opendir(path); + if (dirp == NULL) { + printf("opendir failed.\n"); + exit(0); + } + + n = 0; + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_type != DT_REG) + continue; + if (strcmp(dp->d_name + dp->d_namlen - 4, "cert")) + continue; + snprintf(buf, sizeof(buf), "%s/%s", path, dp->d_name); + stat(buf, &sb); + + p = (char **)realloc(certs, (n + 1) * sizeof(certs)); + if (p == NULL) + err(1, "realloc"); + certs = p; + + certs[n] = malloc(sb.st_size + 1); + if (certs[n] == NULL) + err(1, "malloc"); + + fd = open(buf, O_RDONLY); + if (fd == -1) + err(1, "open"); + len = read(fd, certs[n], sb.st_size); + if (len == -1) + err(1, "read"); + if (len != sb.st_size) + errx(1, "read: length mismatch"); + certs[n][sb.st_size] = '\0'; + close(fd); + + printf("%s: %d\n", dp->d_name, (int)sb.st_size); + + n++; + } + + p = (char **)realloc(certs, (n + 1) * sizeof(certs)); + if (p == NULL) + err(1, "realloc"); + certs = p; + certs[n] = NULL; + + return certs; +} + +void +ciphertest(ac, av) + int ac; + char **av; +{ + vchar_t data; + vchar_t key; + vchar_t iv0; + vchar_t *res1, *res2, *iv; + + printf("\n**Test for CIPHER.**\n"); + + data.v = str2val("\ +06000017 03000000 73616b61 6e65406b 616d652e 6e657409 0002c104 308202b8 \ +04f05a90 \ + ", 16, &data.l); + key.v = str2val("f59bd70f 81b9b9cc 2a32c7fd 229a4b37", 16, &key.l); + iv0.v = str2val("26b68c90 9467b4ab 7ec29fa0 0b696b55", 16, &iv0.l); + + iv = vmalloc(8); + + /* des */ + printf("DES\n"); + printf("data:\n"); + PVDUMP(&data); + + memcpy(iv->v, iv0.v, 8); + res1 = eay_des_encrypt(&data, &key, iv); + printf("encrypto:\n"); + PVDUMP(res1); + + memcpy(iv->v, iv0.v, 8); + res2 = eay_des_decrypt(res1, &key, iv); + printf("decrypto:\n"); + PVDUMP(res2); + + if (memcmp(data.v, res2->v, data.l)) + printf("XXX NG XXX\n"); + vfree(res1); + vfree(res2); + +#ifdef HAVE_OPENSSL_IDEA_H + /* idea */ + printf("IDEA\n"); + printf("data:\n"); + PVDUMP(&data); + + memcpy(iv->v, iv0.v, 8); + res1 = eay_idea_encrypt(&data, &key, iv); + printf("encrypto:\n"); + PVDUMP(res1); + + memcpy(iv->v, iv0.v, 8); + res2 = eay_idea_decrypt(res1, &key, iv); + printf("decrypto:\n"); + PVDUMP(res2); + + if (memcmp(data.v, res2->v, data.l)) + printf("XXX NG XXX\n"); + vfree(res1); + vfree(res2); +#endif + + /* blowfish */ + printf("BLOWFISH\n"); + printf("data:\n"); + PVDUMP(&data); + + memcpy(iv->v, iv0.v, 8); + res1 = eay_bf_encrypt(&data, &key, iv); + printf("encrypto:\n"); + PVDUMP(res1); + + memcpy(iv->v, iv0.v, 8); + res2 = eay_bf_decrypt(res1, &key, iv); + printf("decrypto:\n"); + PVDUMP(res2); + + if (memcmp(data.v, res2->v, data.l)) + printf("XXX NG XXX\n"); + vfree(res1); + vfree(res2); + +#ifdef HAVE_OPENSSL_RC5_H + /* rc5 */ + printf("RC5\n"); + printf("data:\n"); + PVDUMP(&data); + + memcpy(iv->v, iv0.v, 8); + res1 = eay_bf_encrypt(&data, &key, iv); + printf("encrypto:\n"); + PVDUMP(res1); + + memcpy(iv->v, iv0.v, 8); + res2 = eay_bf_decrypt(res1, &key, iv); + printf("decrypto:\n"); + PVDUMP(res2); + + if (memcmp(data.v, res2->v, data.l)) + printf("XXX NG XXX\n"); + vfree(res1); + vfree(res2); +#endif + + /* 3des */ + printf("3DES\n"); + printf("data:\n"); + PVDUMP(&data); + + memcpy(iv->v, iv0.v, 8); + res1 = eay_3des_encrypt(&data, &key, iv); + printf("encrypto:\n"); + if (res1) + PVDUMP(res1); + + memcpy(iv->v, iv0.v, 8); + res2 = eay_3des_decrypt(res1, &key, iv); + printf("decrypto:\n"); + if (res1) + PVDUMP(res2); + + if (res2 && memcmp(data.v, res2->v, data.l)) + printf("XXX NG XXX\n"); + vfree(res1); + vfree(res2); + + /* cast */ + printf("CAST\n"); + printf("data:\n"); + PVDUMP(&data); + + memcpy(iv->v, iv0.v, 8); + res1 = eay_cast_encrypt(&data, &key, iv); + printf("encrypto:\n"); + PVDUMP(res1); + + memcpy(iv->v, iv0.v, 8); + res2 = eay_cast_decrypt(res1, &key, iv); + printf("decrypto:\n"); + PVDUMP(res2); + + if (memcmp(data.v, res2->v, data.l)) + printf("XXX NG XXX\n"); + vfree(res1); + vfree(res2); + + /* aes */ + iv = vrealloc(iv, 16); + + printf("AES\n"); + printf("data:\n"); + PVDUMP(&data); + + { + vchar_t *buf; + int padlen = 16 - data.l % 16; + buf = vmalloc(data.l + padlen); + memcpy(buf->v, data.v, data.l); + + memcpy(iv->v, iv0.v, 16); + res1 = eay_aes_encrypt(buf, &key, iv); + printf("encrypto:\n"); + PVDUMP(res1); + + memcpy(iv->v, iv0.v, 16); + res2 = eay_aes_decrypt(res1, &key, iv); + printf("decrypto:\n"); + PVDUMP(res2); + + if (memcmp(data.v, res2->v, data.l)) + printf("XXX NG XXX\n"); + vfree(res1); + vfree(res2); + } +} + +void +hmactest(ac, av) + int ac; + char **av; +{ + char *keyword = "hehehe test secret!"; + char *object = "d7e6a6c1876ef0488bb74958b9fee94e"; + char *object1 = "d7e6a6c1876ef048"; + char *object2 = "8bb74958b9fee94e"; + char *r_hmd5 = "5702d7d1 fd1bfc7e 210fc9fa cda7d02c"; + char *r_hsha1 = "309999aa 9779a43e ebdea839 1b4e7ee1 d8646874"; + char *r_hsha2 = "d47262d8 a5b6f39d d8686939 411b3e79 ed2e27f9 2c4ea89f dd0a06ae 0c0aa396"; + vchar_t *key, *data, *data1, *data2, *res; + vchar_t mod; + caddr_t ctx; + + printf("\n**Test for HMAC MD5 & SHA1.**\n"); + + key = vmalloc(strlen(keyword)); + memcpy(key->v, keyword, key->l); + + data = vmalloc(strlen(object)); + data1 = vmalloc(strlen(object1)); + data2 = vmalloc(strlen(object2)); + memcpy(data->v, object, data->l); + memcpy(data1->v, object1, data1->l); + memcpy(data2->v, object2, data2->l); + + /* HMAC MD5 */ + printf("HMAC MD5 by eay_hmacmd5_one()\n"); + res = eay_hmacmd5_one(key, data); + PVDUMP(res); + mod.v = str2val(r_hmd5, 16, &mod.l); + if (memcmp(res->v, mod.v, mod.l)) + printf(" XXX NG XXX\n"); + free(mod.v); + vfree(res); + + /* HMAC MD5 */ + printf("HMAC MD5 by eay_hmacmd5_xxx()\n"); + ctx = eay_hmacmd5_init(key); + eay_hmacmd5_update(ctx, data1); + eay_hmacmd5_update(ctx, data2); + res = eay_hmacmd5_final(ctx); + PVDUMP(res); + mod.v = str2val(r_hmd5, 16, &mod.l); + if (memcmp(res->v, mod.v, mod.l)) + printf(" XXX NG XXX\n"); + free(mod.v); + vfree(res); + + /* HMAC SHA2 */ + printf("HMAC SHA2 by eay_hmacsha2_256_one()\n"); + res = eay_hmacsha2_256_one(key, data); + PVDUMP(res); + mod.v = str2val(r_hsha2, 16, &mod.l); + if (memcmp(res->v, mod.v, mod.l)) + printf(" XXX NG XXX\n"); + free(mod.v); + vfree(res); + + /* HMAC SHA1 */ + printf("HMAC SHA1 by eay_hmacsha1_one()\n"); + res = eay_hmacsha1_one(key, data); + PVDUMP(res); + mod.v = str2val(r_hsha1, 16, &mod.l); + if (memcmp(res->v, mod.v, mod.l)) + printf(" XXX NG XXX\n"); + free(mod.v); + vfree(res); + + /* HMAC MD5 */ + printf("HMAC SHA1 by eay_hmacsha1_xxx()\n"); + ctx = eay_hmacsha1_init(key); + eay_hmacsha1_update(ctx, data1); + eay_hmacsha1_update(ctx, data2); + res = eay_hmacsha1_final(ctx); + PVDUMP(res); + mod.v = str2val(r_hsha1, 16, &mod.l); + if (memcmp(res->v, mod.v, mod.l)) + printf(" XXX NG XXX\n"); + free(mod.v); + vfree(res); + + vfree(data); + vfree(data1); + vfree(data2); + vfree(key); +} + +void +sha1test(ac, av) + int ac; + char **av; +{ + char *word1 = "1234567890", *word2 = "12345678901234567890"; + caddr_t ctx; + vchar_t *buf, *res; + + printf("\n**Test for SHA1.**\n"); + + ctx = eay_sha1_init(); + buf = vmalloc(strlen(word1)); + memcpy(buf->v, word1, buf->l); + eay_sha1_update(ctx, buf); + eay_sha1_update(ctx, buf); + res = eay_sha1_final(ctx); + PVDUMP(res); + vfree(res); + vfree(buf); + + ctx = eay_sha1_init(); + buf = vmalloc(strlen(word2)); + memcpy(buf->v, word2, buf->l); + eay_sha1_update(ctx, buf); + res = eay_sha1_final(ctx); + PVDUMP(res); + vfree(res); + + res = eay_sha1_one(buf); + PVDUMP(res); + vfree(res); + vfree(buf); +} + +void +md5test(ac, av) + int ac; + char **av; +{ + char *word1 = "1234567890", *word2 = "12345678901234567890"; + caddr_t ctx; + vchar_t *buf, *res; + + printf("\n**Test for MD5.**\n"); + + ctx = eay_md5_init(); + buf = vmalloc(strlen(word1)); + memcpy(buf->v, word1, buf->l); + eay_md5_update(ctx, buf); + eay_md5_update(ctx, buf); + res = eay_md5_final(ctx); + PVDUMP(res); + vfree(res); + vfree(buf); + + ctx = eay_md5_init(); + buf = vmalloc(strlen(word2)); + memcpy(buf->v, word2, buf->l); + eay_md5_update(ctx, buf); + res = eay_md5_final(ctx); + PVDUMP(res); + vfree(res); + + res = eay_md5_one(buf); + PVDUMP(res); + vfree(res); + vfree(buf); +} + +void +dhtest(ac, av) + int ac; + char **av; +{ + static struct { + char *name; + char *p; + } px[] = { + { "modp768", OAKLEY_PRIME_MODP768, }, + { "modp1024", OAKLEY_PRIME_MODP1024, }, + { "modp1536", OAKLEY_PRIME_MODP1536, }, + { "modp2048", OAKLEY_PRIME_MODP2048, }, + { "modp3072", OAKLEY_PRIME_MODP3072, }, + { "modp4096", OAKLEY_PRIME_MODP4096, }, + { "modp6144", OAKLEY_PRIME_MODP6144, }, + { "modp8192", OAKLEY_PRIME_MODP8192, }, + }; + vchar_t p1, *pub1, *priv1, *gxy1; + vchar_t p2, *pub2, *priv2, *gxy2; + int i; + + printf("\n**Test for DH.**\n"); + + for (i = 0; i < sizeof(px)/sizeof(px[0]); i++) { + printf("\n**Test for DH %s.**\n", px[i].name); + + p1.v = str2val(px[i].p, 16, &p1.l); + p2.v = str2val(px[i].p, 16, &p2.l); + printf("prime number = \n"); PVDUMP(&p1); + + if (eay_dh_generate(&p1, 2, 96, &pub1, &priv1) < 0) { + printf("error\n"); + return; + } + printf("private key for user 1 = \n"); PVDUMP(priv1); + printf("public key for user 1 = \n"); PVDUMP(pub1); + + if (eay_dh_generate(&p2, 2, 96, &pub2, &priv2) < 0) { + printf("error\n"); + return; + } + printf("private key for user 2 = \n"); PVDUMP(priv2); + printf("public key for user 2 = \n"); PVDUMP(pub2); + + /* process to generate key for user 1 */ + gxy1 = vmalloc(p1.l); + memset(gxy1->v, 0, gxy1->l); + eay_dh_compute(&p1, 2, pub1, priv1, pub2, &gxy1); + printf("sharing gxy1 of user 1 = \n"); PVDUMP(gxy1); + + /* process to generate key for user 2 */ + gxy2 = vmalloc(p1.l); + memset(gxy2->v, 0, gxy2->l); + eay_dh_compute(&p2, 2, pub2, priv2, pub1, &gxy2); + printf("sharing gxy2 of user 2 = \n"); PVDUMP(gxy2); + + if (memcmp(gxy1->v, gxy2->v, gxy1->l)) + printf("ERROR: sharing gxy mismatched.\n"); + + vfree(pub1); + vfree(pub2); + vfree(priv1); + vfree(priv2); + vfree(gxy1); + vfree(gxy2); + } + + return; +} + +void +bntest(ac, av) + int ac; + char **av; +{ + vchar_t *rn; + + printf("\n**Test for generate a random number.**\n"); + + rn = eay_set_random((u_int32_t)96); + PVDUMP(rn); + vfree(rn); +} + +struct { + char *name; + void (*func) __P((int, char **)); +} func[] = { + { "random", bntest, }, + { "dh", dhtest, }, + { "md5", md5test, }, + { "sha1", sha1test, }, + { "hmac", hmactest, }, + { "cipher", ciphertest, }, + { "cert", certtest, }, + { "rsa", rsatest, }, +}; + +int +main(ac, av) + int ac; + char **av; +{ + int i; + int len = sizeof(func)/sizeof(func[0]); + + if (strcmp(*av, "-h") == 0) { + printf("Usage: eaytest ["); + for (i = 0; i < len; i++) { + printf("%s", func[i].name); + if (i != len) + printf("|"); + } + printf("]\n"); + Usage(); + } + + ac--; + av++; + + if (ac == 0) { + for (i = 0; i < len; i++) + (func[i].func)(ac, av); + } else { + for (i = 0; i < len; i++) { + if (strcmp(*av, func[i].name) == 0) { + (func[i].func)(ac, av); + break; + } + } + if (i == len) + Usage(); + } + + exit(0); +} + +void +Usage() +{ + printf("Usage: eaytest [dh|md5|sha1|hmac|cipher]\n"); + printf(" eaytest cert [cert_directory]\n"); + exit(0); +} diff --git a/eaytest.tproj/misc.c b/eaytest.tproj/misc.c new file mode 100644 index 0000000..8906017 --- /dev/null +++ b/eaytest.tproj/misc.c @@ -0,0 +1,167 @@ +/* $KAME: misc.c,v 1.22 2001/07/14 05:48:33 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "debug.h" + +#if 0 +static int bindump __P((void *, size_t)); + +static int +bindump(buf0, len) + void *buf0; + size_t len; +{ + unsigned char *buf = (unsigned char *)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if ((buf[i] & 0x80) || !isprint(buf[i])) + printf("\\x%x", buf[i]); + else + printf("%c", buf[i]); + } + printf("\n"); + + return 0; +} +#endif + +int +hexdump(buf0, len) + void *buf0; + size_t len; +{ + caddr_t buf = (caddr_t)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", (unsigned char)buf[i]); + } + printf("\n"); + + return 0; +} + +char * +bit2str(n, bl) + int n, bl; +{ +#define MAXBITLEN 128 + static char b[MAXBITLEN + 1]; + int i; + + if (bl > MAXBITLEN) + return "Failed to convert."; /* NG */ + memset(b, '0', bl); + b[bl] = '\0'; + + for (i = 0; i < bl; i++) { + if (n & (1 << i)) + b[bl - 1 - i] = '1'; + } + + return b; +} + +const char * +debug_location(file, line, func) + const char *file; + int line; + const char *func; +{ + static char buf[1024]; + const char *p; + + /* truncate pathname */ + p = strrchr(file, '/'); + if (p) + p++; + else + p = file; + + if (func) + snprintf(buf, sizeof(buf), "%s:%d:%s()", p, line, func); + else + snprintf(buf, sizeof(buf), "%s:%d", p, line); + + return buf; +} + +/* + * get file size. + * -1: error occured. + */ +int +getfsize(path) + char *path; +{ + struct stat st; + + if (stat(path, &st) != 0) + return -1; + else + return st.st_size; +} + +/* + * calculate the difference between two times. + * t1: start + * t2: end + */ +double +timedelta(t1, t2) + struct timeval *t1, *t2; +{ + if (t2->tv_usec >= t1->tv_usec) + return t2->tv_sec - t1->tv_sec + + (double)(t2->tv_usec - t1->tv_usec) / 1000000; + + return t2->tv_sec - t1->tv_sec - 1 + + (double)(1000000 + t2->tv_usec - t1->tv_usec) / 1000000; +} diff --git a/eaytest.tproj/misc.h b/eaytest.tproj/misc.h new file mode 100644 index 0000000..c5f2846 --- /dev/null +++ b/eaytest.tproj/misc.h @@ -0,0 +1,46 @@ +/* $KAME: misc.h,v 1.11 2001/07/14 05:48:33 sakane 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. 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. + */ + +#define BIT2STR(b) bit2str(b, sizeof(b)<<3) + +#ifdef HAVE_FUNCTION_MACRO +#define LOCATION debug_location(__FILE__, __LINE__, __FUNCTION__) +#else +#define LOCATION debug_location(__FILE__, __LINE__, NULL) +#endif + +extern int hexdump __P((void *, size_t)); +extern char *bit2str __P((int, int)); +extern void *get_newbuf __P((void *, size_t)); +extern const char *debug_location __P((const char *, int, const char *)); +extern int getfsize __P((char *)); +struct timeval; +extern double timedelta __P((struct timeval *, struct timeval *)); diff --git a/eaytest.tproj/rijndael-alg-fst.c b/eaytest.tproj/rijndael-alg-fst.c new file mode 100644 index 0000000..19f0651 --- /dev/null +++ b/eaytest.tproj/rijndael-alg-fst.c @@ -0,0 +1,492 @@ +/* $KAME: rijndael-alg-fst.c,v 1.9 2001/06/19 15:21:05 itojun Exp $ */ + +/* + * rijndael-alg-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.3: Paulo Barreto + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef _KERNEL +#include +#else +#include +#endif +#include +#include + +#include + +#include +#define bcopy(a, b, c) memcpy((b), (a), (c)) +#define bzero(a, b) memset((a), 0, (b)) +#define panic(a) err(1, (a)) + +int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + /* Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + int j, r, t, rconpointer = 0; + union { + word8 x8[MAXKC][4]; + word32 x32[MAXKC]; + } xtk; +#define tk xtk.x8 + int KC = ROUNDS - 6; + + for (j = KC-1; j >= 0; j--) { + *((word32*)tk[j]) = *((word32*)k[j]); + } + r = 0; + t = 0; + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + + while (r < ROUNDS + 1) { /* while not enough round key material calculated */ + /* calculate new values */ + tk[0][0] ^= S[tk[KC-1][1]]; + tk[0][1] ^= S[tk[KC-1][2]]; + tk[0][2] ^= S[tk[KC-1][3]]; + tk[0][3] ^= S[tk[KC-1][0]]; + tk[0][0] ^= rcon[rconpointer++]; + + if (KC != 8) { + for (j = 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } else { + for (j = 1; j < KC/2; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; + tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; + tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; + tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; + for (j = KC/2 + 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + } + return 0; +#undef tk +} + +int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + word8 *w; + + for (r = 1; r < ROUNDS; r++) { + w = W[r][0]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][1]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][2]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][3]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + } + return 0; +} + +/** + * Encrypt a single block. + */ +int rijndaelEncrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[0][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[0][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[0][3]); + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + for (r = 1; r < ROUNDS-1; r++) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[ROUNDS-1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[ROUNDS-1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[ROUNDS-1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[ROUNDS-1][3]); + b[ 0] = T1[temp[0][0]][1]; + b[ 1] = T1[temp[1][1]][1]; + b[ 2] = T1[temp[2][2]][1]; + b[ 3] = T1[temp[3][3]][1]; + b[ 4] = T1[temp[1][0]][1]; + b[ 5] = T1[temp[2][1]][1]; + b[ 6] = T1[temp[3][2]][1]; + b[ 7] = T1[temp[0][3]][1]; + b[ 8] = T1[temp[2][0]][1]; + b[ 9] = T1[temp[3][1]][1]; + b[10] = T1[temp[0][2]][1]; + b[11] = T1[temp[1][3]][1]; + b[12] = T1[temp[3][0]][1]; + b[13] = T1[temp[0][1]][1]; + b[14] = T1[temp[1][2]][1]; + b[15] = T1[temp[2][3]][1]; + *((word32*)(b )) ^= *((word32*)rk[ROUNDS][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[ROUNDS][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]); + *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Encrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + */ +int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r; + word8 temp[4][4]; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + + *((word32*)a[0]) = *((word32*)a[0]) ^ *((word32*)rk[0][0]); + *((word32*)a[1]) = *((word32*)a[1]) ^ *((word32*)rk[0][1]); + *((word32*)a[2]) = *((word32*)a[2]) ^ *((word32*)rk[0][2]); + *((word32*)a[3]) = *((word32*)a[3]) ^ *((word32*)rk[0][3]); + + for (r = 1; (r <= rounds) && (r < ROUNDS); r++) { + *((word32*)temp[0]) = *((const word32*)T1[a[0][0]]) + ^ *((const word32*)T2[a[1][1]]) + ^ *((const word32*)T3[a[2][2]]) + ^ *((const word32*)T4[a[3][3]]); + *((word32*)temp[1]) = *((const word32*)T1[a[1][0]]) + ^ *((const word32*)T2[a[2][1]]) + ^ *((const word32*)T3[a[3][2]]) + ^ *((const word32*)T4[a[0][3]]); + *((word32*)temp[2]) = *((const word32*)T1[a[2][0]]) + ^ *((const word32*)T2[a[3][1]]) + ^ *((const word32*)T3[a[0][2]]) + ^ *((const word32*)T4[a[1][3]]); + *((word32*)temp[3]) = *((const word32*)T1[a[3][0]]) + ^ *((const word32*)T2[a[0][1]]) + ^ *((const word32*)T3[a[1][2]]) + ^ *((const word32*)T4[a[2][3]]); + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[r][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[r][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[r][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[r][3]); + } + if (rounds == ROUNDS) { + /* last round is special */ + temp[0][0] = T1[a[0][0]][1]; + temp[0][1] = T1[a[1][1]][1]; + temp[0][2] = T1[a[2][2]][1]; + temp[0][3] = T1[a[3][3]][1]; + temp[1][0] = T1[a[1][0]][1]; + temp[1][1] = T1[a[2][1]][1]; + temp[1][2] = T1[a[3][2]][1]; + temp[1][3] = T1[a[0][3]][1]; + temp[2][0] = T1[a[2][0]][1]; + temp[2][1] = T1[a[3][1]][1]; + temp[2][2] = T1[a[0][2]][1]; + temp[2][3] = T1[a[1][3]][1]; + temp[3][0] = T1[a[3][0]][1]; + temp[3][1] = T1[a[0][1]][1]; + temp[3][2] = T1[a[1][2]][1]; + temp[3][3] = T1[a[2][3]][1]; + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[ROUNDS][3]); + } + + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ + +/** + * Decrypt a single block. + */ +int rijndaelDecrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[ROUNDS][3]); + + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + for (r = ROUNDS-1; r > 1; r--) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[1][3]); + b[ 0] = S5[temp[0][0]]; + b[ 1] = S5[temp[3][1]]; + b[ 2] = S5[temp[2][2]]; + b[ 3] = S5[temp[1][3]]; + b[ 4] = S5[temp[1][0]]; + b[ 5] = S5[temp[0][1]]; + b[ 6] = S5[temp[3][2]]; + b[ 7] = S5[temp[2][3]]; + b[ 8] = S5[temp[2][0]]; + b[ 9] = S5[temp[1][1]]; + b[10] = S5[temp[0][2]]; + b[11] = S5[temp[3][3]]; + b[12] = S5[temp[3][0]]; + b[13] = S5[temp[2][1]]; + b[14] = S5[temp[1][2]]; + b[15] = S5[temp[0][3]]; + *((word32*)(b )) ^= *((word32*)rk[0][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[0][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]); + *((word32*)(b+12)) ^= *((word32*)rk[0][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Decrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * Operations rearranged such that the intermediate values + * of decryption correspond with the intermediate values + * of encryption. + */ +int rijndaelDecryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r, i; + word8 temp[4], shift; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + /* first round is special: */ + *(word32 *)a[0] ^= *(word32 *)rk[ROUNDS][0]; + *(word32 *)a[1] ^= *(word32 *)rk[ROUNDS][1]; + *(word32 *)a[2] ^= *(word32 *)rk[ROUNDS][2]; + *(word32 *)a[3] ^= *(word32 *)rk[ROUNDS][3]; + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + /* ROUNDS-1 ordinary rounds */ + for (r = ROUNDS-1; r > rounds; r--) { + *(word32 *)a[0] ^= *(word32 *)rk[r][0]; + *(word32 *)a[1] ^= *(word32 *)rk[r][1]; + *(word32 *)a[2] ^= *(word32 *)rk[r][2]; + *(word32 *)a[3] ^= *(word32 *)rk[r][3]; + + *((word32*)a[0]) = + *((const word32*)U1[a[0][0]]) + ^ *((const word32*)U2[a[0][1]]) + ^ *((const word32*)U3[a[0][2]]) + ^ *((const word32*)U4[a[0][3]]); + + *((word32*)a[1]) = + *((const word32*)U1[a[1][0]]) + ^ *((const word32*)U2[a[1][1]]) + ^ *((const word32*)U3[a[1][2]]) + ^ *((const word32*)U4[a[1][3]]); + + *((word32*)a[2]) = + *((const word32*)U1[a[2][0]]) + ^ *((const word32*)U2[a[2][1]]) + ^ *((const word32*)U3[a[2][2]]) + ^ *((const word32*)U4[a[2][3]]); + + *((word32*)a[3]) = + *((const word32*)U1[a[3][0]]) + ^ *((const word32*)U2[a[3][1]]) + ^ *((const word32*)U3[a[3][2]]) + ^ *((const word32*)U4[a[3][3]]); + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + } + if (rounds == 0) { + /* End with the extra key addition */ + *(word32 *)a[0] ^= *(word32 *)rk[0][0]; + *(word32 *)a[1] ^= *(word32 *)rk[0][1]; + *(word32 *)a[2] ^= *(word32 *)rk[0][2]; + *(word32 *)a[3] ^= *(word32 *)rk[0][3]; + } + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/eaytest.tproj/rijndael-alg-fst.h b/eaytest.tproj/rijndael-alg-fst.h new file mode 100644 index 0000000..4f02543 --- /dev/null +++ b/eaytest.tproj/rijndael-alg-fst.h @@ -0,0 +1,33 @@ +/* $KAME: rijndael-alg-fst.h,v 1.4 2000/10/02 17:14:26 itojun Exp $ */ + +/* + * rijndael-alg-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_ALG_FST_H +#define __RIJNDAEL_ALG_FST_H + +#define RIJNDAEL_MAXKC (256/32) +#define RIJNDAEL_MAXROUNDS 14 + +int rijndaelKeySched(u_int8_t k[RIJNDAEL_MAXKC][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelKeyEncToDec(u_int8_t W[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelEncrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelEncryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +int rijndaelDecrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelDecryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_ALG_FST_H */ diff --git a/eaytest.tproj/rijndael-api-fst.c b/eaytest.tproj/rijndael-api-fst.c new file mode 100644 index 0000000..a3104c2 --- /dev/null +++ b/eaytest.tproj/rijndael-api-fst.c @@ -0,0 +1,495 @@ +/* $KAME: rijndael-api-fst.c,v 1.1.1.1 2001/08/08 09:56:23 sakane Exp $ */ + +/* + * rijndael-api-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.1: Vincent Rijmen + * v2.2: Vincent Rijmen + * v2.3: Paulo Barreto + * v2.4: Vincent Rijmen + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef _KERNEL +#include +#include +#else +#include +#endif +#include +#include +#include + +#include +#define bcopy(a, b, c) memcpy(b, a, c) +#define bzero(a, b) memset(a, 0, b) +#define panic(a) err(1, (a)) + +int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) { + word8 k[MAXKC][4]; + int i; + char *keyMat; + + if (key == NULL) { + return BAD_KEY_INSTANCE; + } + + if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) { + key->direction = direction; + } else { + return BAD_KEY_DIR; + } + + if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) { + key->keyLen = keyLen; + } else { + return BAD_KEY_MAT; + } + + if (keyMaterial != NULL) { + bcopy(keyMaterial, key->keyMaterial, keyLen/8); + } + + key->ROUNDS = keyLen/32 + 6; + + /* initialize key schedule: */ + keyMat = key->keyMaterial; + for (i = 0; i < key->keyLen/8; i++) { + k[i >> 2][i & 3] = (word8)keyMat[i]; + } + rijndaelKeySched(k, key->keySched, key->ROUNDS); + if (direction == DIR_DECRYPT) { + rijndaelKeyEncToDec(key->keySched, key->ROUNDS); + } + + return TRUE; +} + +int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) { + if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) { + cipher->mode = mode; + } else { + return BAD_CIPHER_MODE; + } + if (IV != NULL) { + bcopy(IV, cipher->IV, MAX_IV_SIZE); + } else { + bzero(cipher->IV, MAX_IV_SIZE); + } + return TRUE; +} + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 0 /*STRICT_ALIGN*/ + bcopy(cipher->IV, block, 16); + bcopy(input, iv, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)cipher->IV)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)cipher->IV)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)cipher->IV)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)cipher->IV)[3] ^ ((word32*)input)[3]; +#endif + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + for (i = numBlocks - 1; i > 0; i--) { +#if 0 /*STRICT_ALIGN*/ + bcopy(outBuffer, block, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)outBuffer)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)outBuffer)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)outBuffer)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)outBuffer)[3] ^ ((word32*)input)[3]; +#endif + outBuffer += 16; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + } + break; + + case MODE_CFB1: +#if 0 /*STRICT_ALIGN*/ + bcopy(cipher->IV, iv, 16); +#else /* !STRICT_ALIGN */ + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif /* ?STRICT_ALIGN */ + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((outBuffer[k/8] >> (7-(k&7))) & 1); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +/** + * Encrypt data partitioned in octets, using RFC 2040-like padding. + * + * @param input data to be encrypted (octet sequence) + * @param inputOctets input length in octets (not bits) + * @param outBuffer encrypted output data + * + * @return length in octets (not bits) of the encrypted output buffer. + */ +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16], *iv, *cp; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + padLen = 16 - (inputOctets - 16*numBlocks); + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(ECB)"); + bcopy(input, block, 16 - padLen); + for (cp = block + 16 - padLen; cp < block + 16; cp++) + *cp = padLen; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + case MODE_CBC: + iv = cipher->IV; + for (i = numBlocks; i > 0; i--) { + ((word32*)block)[0] = ((word32*)input)[0] ^ ((word32*)iv)[0]; + ((word32*)block)[1] = ((word32*)input)[1] ^ ((word32*)iv)[1]; + ((word32*)block)[2] = ((word32*)input)[2] ^ ((word32*)iv)[2]; + ((word32*)block)[3] = ((word32*)input)[3] ^ ((word32*)iv)[3]; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + iv = outBuffer; + input += 16; + outBuffer += 16; + } +#if 0 /*XXX i'm not sure that is correct. sakane@kame.net */ + padLen = 16 - (inputOctets - 16*numBlocks); +#else + padLen = 16 - inputOctets % 16; + if (padLen == 16) + padLen = 0; +#endif + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(CBC)"); + for (i = 0; i < 16 - padLen; i++) { + block[i] = input[i] ^ iv[i]; + } + for (i = 16 - padLen; i < 16; i++) { + block[i] = (BYTE)padLen ^ iv[i]; + } + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*(numBlocks + 1); +} + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 0 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= *((word32*)iv[0]); + ((word32*)block)[1] ^= *((word32*)iv[1]); + ((word32*)block)[2] ^= *((word32*)iv[2]); + ((word32*)block)[3] ^= *((word32*)iv[3]); +#if 0 /*STRICT_ALIGN*/ + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); +#else + *((word32*)iv[0]) = ((word32*)input)[0]; ((word32*)outBuffer)[0] = ((word32*)block)[0]; + *((word32*)iv[1]) = ((word32*)input)[1]; ((word32*)outBuffer)[1] = ((word32*)block)[1]; + *((word32*)iv[2]) = ((word32*)input)[2]; ((word32*)outBuffer)[2] = ((word32*)block)[2]; + *((word32*)iv[3]) = ((word32*)input)[3]; ((word32*)outBuffer)[3] = ((word32*)block)[3]; +#endif + input += 16; + outBuffer += 16; + } + break; + + case MODE_CFB1: +#if 0 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV)); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((input[k/8] >> (7-(k&7))) & 1); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16]; + word32 iv[4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_ENCRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + if (inputOctets % 16 != 0) { + return BAD_DATA; + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + padLen = block[15]; + if (padLen >= 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + case MODE_CBC: + bcopy(cipher->IV, iv, 16); + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + padLen = block[15]; + if (padLen <= 0 || padLen > 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*numBlocks - padLen; +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * cipherUpdateRounds: + * + * Encrypts/Decrypts exactly one full block a specified number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * + * Returns: + * TRUE - on success + * BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized) + */ +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer, int rounds) { + int j; + word8 block[4][4]; + + if (cipher == NULL || key == NULL) { + return BAD_CIPHER_STATE; + } + + for (j = 3; j >= 0; j--) { + /* parse input stream into rectangular array */ + *((word32*)block[j]) = *((word32*)(input+4*j)); + } + + switch (key->direction) { + case DIR_ENCRYPT: + rijndaelEncryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + case DIR_DECRYPT: + rijndaelDecryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + default: + return BAD_KEY_DIR; + } + + for (j = 3; j >= 0; j--) { + /* parse rectangular array into output ciphertext bytes */ + *((word32*)(outBuffer+4*j)) = *((word32*)block[j]); + } + + return TRUE; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/eaytest.tproj/rijndael-api-fst.h b/eaytest.tproj/rijndael-api-fst.h new file mode 100644 index 0000000..75b99c3 --- /dev/null +++ b/eaytest.tproj/rijndael-api-fst.h @@ -0,0 +1,103 @@ +/* $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $ */ + +/* + * rijndael-api-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_API_FST_H +#define __RIJNDAEL_API_FST_H + +#include + +/* Defines: + Add any additional defines you need +*/ + +#define DIR_ENCRYPT 0 /* Are we encrpyting? */ +#define DIR_DECRYPT 1 /* Are we decrpyting? */ +#define MODE_ECB 1 /* Are we ciphering in ECB mode? */ +#define MODE_CBC 2 /* Are we ciphering in CBC mode? */ +#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ +#define TRUE 1 +#define FALSE 0 +#define BITSPERBLOCK 128 /* Default number of bits in a cipher block */ + +/* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */ +#define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */ +#define BAD_KEY_MAT -2 /* Key material not of correct length */ +#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ +#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */ +#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ +#define BAD_BLOCK_LENGTH -6 +#define BAD_CIPHER_INSTANCE -7 +#define BAD_DATA -8 /* Data contents are invalid, e.g., invalid padding */ +#define BAD_OTHER -9 /* Unknown error */ + +/* CHANGE POSSIBLE: inclusion of algorithm specific defines */ +#define MAX_KEY_SIZE 64 /* # of ASCII char's needed to represent a key */ +#define MAX_IV_SIZE 16 /* # bytes needed to represent an IV */ + +/* Typedefs: + + Typedef'ed data storage elements. Add any algorithm specific +parameters at the bottom of the structs as appropriate. +*/ + +/* The structure for key information */ +typedef struct { + u_int8_t direction; /* Key used for encrypting or decrypting? */ + int keyLen; /* Length of the key */ + char keyMaterial[MAX_KEY_SIZE+1]; /* Raw key data in ASCII, e.g., user input or KAT values */ + /* The following parameters are algorithm dependent, replace or add as necessary */ + int ROUNDS; /* key-length-dependent number of rounds */ + int blockLen; /* block length */ + union { + u_int8_t xkS8[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */ + u_int32_t xkS32[RIJNDAEL_MAXROUNDS+1][4]; /* key schedule */ + } xKeySched; +#define keySched xKeySched.xkS8 +} keyInstance; + +/* The structure for cipher information */ +typedef struct { /* changed order of the components */ + u_int8_t mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ + u_int8_t IV[MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */ + /* Add any algorithm specific parameters needed here */ + int blockLen; /* Sample: Handles non-128 bit block sizes (if available) */ +} cipherInstance; + +/* Function prototypes */ +/* CHANGED: nothing + TODO: implement the following extensions to setup 192-bit and 256-bit block lengths: + makeKeyEx(): parameter blockLen added + -- this parameter is absolutely necessary if you want to + setup the round keys in a variable block length setting + cipherInitEx(): parameter blockLen added (for obvious reasons) + */ + +int rijndael_makeKey(keyInstance *key, u_int8_t direction, int keyLen, char *keyMaterial); + +int rijndael_cipherInit(cipherInstance *cipher, u_int8_t mode, char *IV); + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer, int Rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_API_FST_H */ diff --git a/eaytest.tproj/sha2.c b/eaytest.tproj/sha2.c new file mode 100644 index 0000000..80deb6a --- /dev/null +++ b/eaytest.tproj/sha2.c @@ -0,0 +1,1102 @@ +/* $KAME: sha2.c,v 1.4 2001/09/02 08:59:55 itojun Exp $ */ + +/* + * sha2.c + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. 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. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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. + * + */ + + +#include +#include +#include +#include +#include + +#include +#include +#define bcopy(a, b, c) memcpy((b), (a), (c)) +#define bzero(a, b) memset((a), 0, (b)) +#define panic(a) err(1, (a)) + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + +#define assert(x) + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/* + * Define the followingsha2_* types to types of the correct length on + * the native archtecture. Most BSD systems and Linux define u_intXX_t + * types. Machines with very recent ANSI C headers, can use the + * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H + * during compile or in the sha.h header file. + * + * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t + * will need to define these three typedefs below (and the appropriate + * ones in sha.h too) by hand according to their system architecture. + * + * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t + * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +#else /* SHA2_USE_INTTYPES_H */ + +typedef u_int8_t sha2_byte; /* Exactly 1 byte */ +typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ +typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void SHA512_Last(SHA512_CTX*); +void SHA256_Transform(SHA256_CTX*, const sha2_word32*); +void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[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 +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH); + bzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (const sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + bzero(context, sizeof(context)); + usedspace = 0; +} + +char *SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + bcopy(sha512_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (const sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} + + +/*** SHA-384: *********************************************************/ +void SHA384_Init(SHA384_CTX* context) { + if (context == (SHA384_CTX*)0) { + return; + } + bcopy(sha384_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { + SHA512_Update((SHA512_CTX*)context, data, len); +} + +void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA384_End(SHA384_CTX* context, char buffer[]) { + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA384_DIGEST_LENGTH); + return buffer; +} + +char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { + SHA384_CTX context; + + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); +} + +/*glue*/ +static struct env_md_st sha2_256_md = { + 0, /*NID_sha1*/ + 0, /*NID_sha1WithRSAEncryption*/ + SHA256_DIGEST_LENGTH, + SHA256_Init, + SHA256_Update, + SHA256_Final, + NULL, NULL, {0, 0, 0, 0}, + SHA256_BLOCK_LENGTH, + sizeof(struct env_md_st *) + sizeof(SHA256_CTX), +}; + +struct env_md_st *EVP_sha2_256(void) +{ + return(&sha2_256_md); +} + +static struct env_md_st sha2_384_md = { + 0, /*NID_sha1*/ + 0, /*NID_sha1WithRSAEncryption*/ + SHA384_DIGEST_LENGTH, + SHA384_Init, + SHA384_Update, + SHA384_Final, + NULL, NULL, {0, 0, 0, 0}, + SHA384_BLOCK_LENGTH, + sizeof(struct env_md_st *) + sizeof(SHA384_CTX), +}; + +struct env_md_st *EVP_sha2_384(void) +{ + return(&sha2_384_md); +} + +static struct env_md_st sha2_512_md = { + 0, /*NID_sha1*/ + 0, /*NID_sha1WithRSAEncryption*/ + SHA512_DIGEST_LENGTH, + SHA512_Init, + SHA512_Update, + SHA512_Final, + NULL, NULL, {0, 0, 0, 0}, /*EVP_PKEY_RSA_method*/ + SHA512_BLOCK_LENGTH, + sizeof(struct env_md_st *) + sizeof(SHA512_CTX), +}; + +struct env_md_st *EVP_sha2_512(void) +{ + return(&sha2_512_md); +} diff --git a/eaytest.tproj/sha2.h b/eaytest.tproj/sha2.h new file mode 100644 index 0000000..65f1d45 --- /dev/null +++ b/eaytest.tproj/sha2.h @@ -0,0 +1,144 @@ +/* $KAME: sha2.h,v 1.1.1.1 2001/08/08 09:56:28 sakane Exp $ */ + +/* + * sha2.h + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. 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. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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. + * + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +/* NOTE: If your architecture does not define either u_intXX_t types or + * uintXX_t (from inttypes.h), you may need to define things by hand + * for your system: + */ +#if 0 +typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ +typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ +typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ +#endif +/* + * Most BSD systems already define u_intXX_t types, as does Linux. + * Some systems, however, like Compaq's Tru64 Unix instead can use + * uintXX_t types defined by very recent ANSI C standards and included + * in the file: + * + * #include + * + * If you choose to use then please define: + * + * #define SHA2_USE_INTTYPES_H + * + * Or on the command line during compile: + * + * cc -DSHA2_USE_INTTYPES_H ... + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#else /* SHA2_USE_INTTYPES_H */ + +typedef struct _SHA256_CTX { + u_int32_t state[8]; + u_int64_t bitcount; + u_int8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + u_int64_t state[8]; + u_int64_t bitcount[2]; + u_int8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#endif /* SHA2_USE_INTTYPES_H */ + +typedef SHA512_CTX SHA384_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ + +void SHA256_Init __P((SHA256_CTX *)); +void SHA256_Update __P((SHA256_CTX*, const u_int8_t*, size_t)); +void SHA256_Final __P((u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*)); +char* SHA256_End __P((SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH])); +char* SHA256_Data __P((const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH])); + +void SHA384_Init __P((SHA384_CTX*)); +void SHA384_Update __P((SHA384_CTX*, const u_int8_t*, size_t)); +void SHA384_Final __P((u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*)); +char* SHA384_End __P((SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH])); +char* SHA384_Data __P((const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH])); + +void SHA512_Init __P((SHA512_CTX*)); +void SHA512_Update __P((SHA512_CTX*, const u_int8_t*, size_t)); +void SHA512_Final __P((u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*)); +char* SHA512_End __P((SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH])); +char* SHA512_Data __P((const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH])); + +struct env_md_st *EVP_sha2_256 __P((void)); +struct env_md_st *EVP_sha2_384 __P((void)); +struct env_md_st *EVP_sha2_512 __P((void)); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/eaytest.tproj/str2val.c b/eaytest.tproj/str2val.c new file mode 100644 index 0000000..72aee51 --- /dev/null +++ b/eaytest.tproj/str2val.c @@ -0,0 +1,122 @@ +/* $KAME: str2val.c,v 1.10 2001/04/03 15:51:57 thorpej 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. 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. + */ + +#include +#include +#include + +#include +#include + +#include "str2val.h" +#include "gcmalloc.h" + +/* + * exchange a value to a hex string. + * must free buffer allocated later. + */ +caddr_t +val2str(buf, mlen) + const char *buf; + size_t mlen; +{ + caddr_t new; + size_t len = (mlen * 2) + mlen / 8 + 10; + size_t i, j; + + if ((new = racoon_malloc(len)) == 0) return(0); + + for (i = 0, j = 0; i < mlen; i++) { + snprintf(&new[j], len - j, "%02x", (u_char)buf[i]); + j += 2; + if (i % 8 == 7) { + new[j++] = ' '; + new[j] = '\0'; + } + } + new[j] = '\0'; + + return(new); +} + +/* + * exchange a string based "base" to a value. + */ +char * +str2val(str, base, len) + const char *str; + int base; + size_t *len; +{ + int f; + size_t i; + char *dst; + char *rp; + const char *p; + char b[3]; + + i = 0; + for (p = str; *p != '\0'; p++) { + if (isxdigit(*p)) + i++; + else if (isspace(*p)) + ; + else + return NULL; + } + if (i == 0 || (i % 2) != 0) + return NULL; + i /= 2; + + if ((dst = racoon_malloc(i)) == NULL) + return NULL; + + i = 0; + f = 0; + for (rp = dst, p = str; *p != '\0'; p++) { + if (isxdigit(*p)) { + if (!f) { + b[0] = *p; + f = 1; + } else { + b[1] = *p; + b[2] = '\0'; + *rp++ = (char)strtol(b, NULL, base); + i++; + f = 0; + } + } + } + + *len = i; + + return(dst); +} diff --git a/eaytest.tproj/str2val.h b/eaytest.tproj/str2val.h new file mode 100644 index 0000000..15f5245 --- /dev/null +++ b/eaytest.tproj/str2val.h @@ -0,0 +1,33 @@ +/* $KAME: str2val.h,v 1.5 2000/10/04 17:41:04 itojun 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. 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. + */ + +extern caddr_t val2str __P((const char *, size_t)); +extern char *str2val __P((const char *, int, size_t *)); diff --git a/eaytest.tproj/vmbuf.c b/eaytest.tproj/vmbuf.c new file mode 100644 index 0000000..cdb4110 --- /dev/null +++ b/eaytest.tproj/vmbuf.c @@ -0,0 +1,115 @@ +/* $KAME: vmbuf.c,v 1.10 2001/04/03 15:51:57 thorpej 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. 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. + */ + +#define NONEED_DRM +#include +#include + +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "debug.h" +#include "gcmalloc.h" + +vchar_t * +vmalloc(size) + size_t size; +{ + vchar_t *var; + + if ((var = (vchar_t *)racoon_malloc(sizeof(*var))) == NULL) + return NULL; + + var->l = size; + var->v = (caddr_t)racoon_calloc(1, size); + if (var->v == NULL) { + (void)racoon_free(var); + return NULL; + } + + return var; +} + +vchar_t * +vrealloc(ptr, size) + vchar_t *ptr; + size_t size; +{ + caddr_t v; + + if (ptr != NULL) { + if ((v = (caddr_t)racoon_realloc(ptr->v, size)) == NULL) { + (void)vfree(ptr); + return NULL; + } + memset(v + ptr->l, 0, size - ptr->l); + ptr->v = v; + ptr->l = size; + } else { + if ((ptr = vmalloc(size)) == NULL) + return NULL; + } + + return ptr; +} + +void +vfree(var) + vchar_t *var; +{ + if (var == NULL) + return; + + if (var->v) + (void)racoon_free(var->v); + + (void)racoon_free(var); + + return; +} + +vchar_t * +vdup(src) + vchar_t *src; +{ + vchar_t *new; + + if ((new = vmalloc(src->l)) == NULL) + return NULL; + + memcpy(new->v, src->v, src->l); + + return new; +} diff --git a/eaytest.tproj/vmbuf.h b/eaytest.tproj/vmbuf.h new file mode 100644 index 0000000..2ebdb3f --- /dev/null +++ b/eaytest.tproj/vmbuf.h @@ -0,0 +1,63 @@ +/* $KAME: vmbuf.h,v 1.7 2000/10/04 17:41:05 itojun 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. 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. + */ + +/* + * bp v + * v v + * ........................ + * <--------------> l + * <----------------------> bl + */ +typedef struct _vchar_t_ { +#if notyet + u_int32_t t; /* type of the value */ + vchar_t *n; /* next vchar_t buffer */ + size_t bl; /* length of the buffer */ + caddr_t bp; /* pointer to the buffer */ +#endif + size_t l; /* length of the value */ + caddr_t v; /* place holder to the pointer to the value */ +} vchar_t; + +#define VPTRINIT(p) \ +do { \ + if (p) { \ + vfree(p); \ + (p) = NULL; \ + } \ +} while(0); + +#define vfree vmbuf_free + +extern vchar_t *vmalloc __P((size_t)); +extern vchar_t *vrealloc __P((vchar_t *, size_t)); +extern void vfree __P((vchar_t *)); +extern vchar_t *vdup __P((vchar_t *)); diff --git a/ftp.tproj/Makefile.postamble b/ftp.tproj/Makefile.postamble deleted file mode 100644 index 7823726..0000000 --- a/ftp.tproj/Makefile.postamble +++ /dev/null @@ -1,123 +0,0 @@ -############################################################################### -# NeXT Makefile.postamble -# Copyright 1996, NeXT Software, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. Additional -# rules (e.g., after_install) that are defined by the developer should be -# defined in this file. -# -############################################################################### -# -# Here are the variables exported by the common "app" makefiles that can be -# used in any customizations you make to the template below: -# -# PRODUCT_ROOT - Name of the directory to which resources are copied. -# OFILE_DIR - Directory into which .o object files are generated. -# (Note that this name is calculated based on the target -# architectures specified in Project Builder). -# DERIVED_SRC_DIR - Directory used for all other derived files -# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations -# -# NAME - name of application, bundle, subproject, palette, etc. -# LANGUAGE - langage in which the project is written (default "English") -# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project -# GLOBAL_RESOURCES - non-localized resources of project -# PROJECTVERSION - version of ProjectBuilder project (NS3.X = 1.1, NS4.0 = 2.0) -# ICONSECTIONS - Specifies icon sections when linking executable -# -# CLASSES - Class implementation files in project. -# HFILES - Header files in project. -# MFILES - Other Objective-C source files in project. -# CFILES - Other C source files in project. -# PSWFILES - .psw files in the project -# PSWMFILES - .pswm files in the project -# SUBPROJECTS - Subprojects of this project -# BUNDLES - Bundle subprojects of this project -# OTHERSRCS - Other miscellaneous sources of this project -# OTHERLINKED - Source files not matching a standard source extention -# -# LIBS - Libraries to link with when making app target -# DEBUG_LIBS - Libraries to link with when making debug target -# PROF_LIBS - Libraries to link with when making profile target -# OTHERLINKEDOFILES - Other relocatable files to (always) link in. -# -# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles -# MAKEFILEDIR - Directory in which to find $(MAKEFILE) -# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make) -# INSTALLDIR - Directory app will be installed into by 'install' target -# -############################################################################### - - -# Change defaults assumed by the standard makefiles here. Edit the -# following default values as appropriate. (Note that if no Makefile.postamble -# exists, these values will have defaults set in common.make). - -# Versioning of frameworks, libraries, bundles, and palettes: -#CURRENTLY_ACTIVE_VERSION = YES - # Set to "NO" to produce a compatibility binary -#DEPLOY_WITH_VERSION_NAME = A - # This should be incremented as your API changes. -#COMPATIBILITY_PROJECT_VERSION = 1 - # This should be incremented as your API grows. -#CURRENT_PROJECT_VERSION = 1 - # Defaults to using the "vers_string" hack. - -# Some compiler flags can be easily overridden here, but onlytake effect at -# the top-level: -#OPTIMIZATION_CFLAG = -O -#DEBUG_SYMBOLS_CFLAG = -g -#WARNING_CFLAGS = -Wmost -#DEBUG_BUILD_CFLAGS = -DDEBUG -#PROFILE_BUILD_CFLAGS = -pg -DPROFILE - -# This definition will suppress stripping of debug symbols when an executable -# is installed. By default it is YES. -# STRIP_ON_INSTALL = NO - -# Flags passed to yacc -#YFLAGS = -d - -# Library and Framework projects only: -# 1. If you want something other than the default .dylib name, override it here -#DYLIB_INSTALL_NAME = lib$(NAME).dylib - -# 2. If you want to change the -install_name flag from the absolute path to the development area, change it here. One good choice is the installation directory. Another one might be none at all. -#DYLIB_INSTALL_DIR = $(INSTALLDIR) - -# Ownership and permissions of files installed by 'install' target -#INSTALL_AS_USER = root - # User/group ownership -#INSTALL_AS_GROUP = wheel - # (probably want to set both of these) -#INSTALL_PERMISSIONS = - # If set, 'install' chmod's executable to this - -# Options to strip for various project types. Note: -S strips debugging symbols -# (executables can be stripped down further with -x or, if they load no bundles, with no -# options at all). -#APP_STRIP_OPTS = -S -#TOOL_STRIP_OPTS = -S -#LIBRARY_STRIP_OPTS = -S - # for .a archives -#DYNAMIC_STRIP_OPTS = -S - # for bundles and shared libraries -STRIPFLAGS = - -######################################################################### -# Put rules to extend the behavior of the standard Makefiles here. "Official" -# user-defined rules are: -# * before_install -# * after_install -# * after_installhdrs -# You should avoid redefining things like "install" or "app", as they are -# owned by the top-level Makefile API and no context has been set up for where -# derived files should go. -# -# Note: on MS Windows, executables, have an extension, so rules and dependencies -# for generated tools should use $(EXECUTABLE_EXT) on the end. diff --git a/ftp.tproj/Makefile.preamble b/ftp.tproj/Makefile.preamble deleted file mode 100644 index 74ce95a..0000000 --- a/ftp.tproj/Makefile.preamble +++ /dev/null @@ -1,130 +0,0 @@ -############################################################################### -# NeXT Makefile.preamble -# Copyright 1996, NeXT Software, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project. Each node in a project -# tree of sub-projects, tools, etc. should have its own Makefile.preamble and -# Makefile.postamble. -# -############################################################################### -## Configure the flags passed to $(CC) here. These flags will also be -## inherited by all nested sub-projects and bundles. Put your -I, -D, -U, and -## -L flags in ProjectBuilder's Build Options inspector if at all possible. -## To change the default flags that get passed to ${CC} -## (e.g. change -O to -O2), see Makefile.postamble. - -# Flags passed to compiler (in addition to -g, -O, etc) -OTHER_CFLAGS = -# Flags passed to ld (in addition to -ObjC, etc.) -OTHER_LDFLAGS = -# Flags passed to libtool when building libraries -OTHER_LIBTOOL_FLAGS = -# For ordering named sections on NEXTSTEP (see ld(1)) -SECTORDER_FLAGS = - -# If you do not want any headers exported before compilations begin, -# uncomment the following line. This can be a big time saver. -#SKIP_EXPORTING_HEADERS = YES - -# Stuff related to exporting headers from this project that isn't already -# handled by PB. -OTHER_PUBLIC_HEADERS = -OTHER_PROJECT_HEADERS = -OTHER_PRIVATE_HEADERS = - -# Set these two macros if you want a precomp to be built as part of -# installation. The cc -precomp will be run in the public header directory -# on the specified public header files with the specified additional flags. -PUBLIC_PRECOMPILED_HEADERS = -PUBLIC_PRECOMPILED_HEADERS_CFLAGS = - -# Set this for library projects if you want to publish header files. If your -# app or tool project exports headers Don't -# include $(DSTROOT); this is added for you automatically. -PUBLIC_HEADER_DIR = -PRIVATE_HEADER_DIR = - -# If, in a subproject, you want to append to the parent's PUBLIC_HEADER_DIR# -# (say, to add a subdirectory like "/sys"), you can use: -PUBLIC_HEADER_DIR_SUFFIX = -PRIVATE_HEADER_DIR_SUFFIX = - -# Set this for dynamic library projects on platforms where code which references -# a dynamic library must link against an import library (i.e., Windows NT) -# Don't include $(DSTROOT); this is added for you automatically. -IMPORT_LIBRARY_DIR = - -# Additional (non-localized) resources for this project, which can be generated -OTHER_RESOURCES = - -# Uncomment this to produce a static archive-style (.a) library -#LIBRARY_STYLE = STATIC - -# Set this to YES if you don't want a final libtool call for a library/framework. -BUILD_OFILES_LIST_ONLY = - -# Additional relocatables to be linked into this project -OTHER_OFILES = -# Additional libraries to link against -OTHER_LIBS = -# To include a version string, project source must exist in a directory named -# $(NAME).%d[.%d][.%d] and the following line must be uncommented. -# OTHER_GENERATED_OFILES = $(VERS_OFILE) - -## Configure how things get built here. Additional dependencies, source files, -## derived files, and build order should be specified here. - -# Other dependencies of this project -OTHER_PRODUCT_DEPENDS = -# Built *before* building subprojects/bundles -OTHER_INITIAL_TARGETS = -# Other source files maintained by .pre/postamble -OTHER_SOURCEFILES = -# Additional files to be removed by `make clean' -OTHER_GARBAGE = - -# Targets to build before installation -OTHER_INSTALL_DEPENDS = - -# More obscure flags you might want to set for pswrap, yacc, lex, etc. -PSWFLAGS = -YFLAGS = -LFLAGS = - -## Delete this line if you want fast and loose cleans that will not remove -## things like precomps and user-defined OTHER_GARBAGE in subprojects. -CLEAN_ALL_SUBPROJECTS = YES - -## Add more obscure source files here to cause them to be automatically -## processed by the appropriate tool. Note that these files should also be -## added to "Supporting Files" in ProjectBuilder. The desired .o files that -## result from these files should also be added to OTHER_OFILES above so they -## will be linked in. - -# .msg files that should have msgwrap run on them -MSGFILES = -# .defs files that should have mig run on them -DEFSFILES = -# .mig files (no .defs files) that should have mig run on them -MIGFILES = -# .x files that should have rpcgen run on them -RPCFILES = - -## Add additional Help directories here (add them to the project as "Other -## Resources" in Project Builder) so that they will be compressed into .store -## files and copied into the app wrapper. If the help directories themselves -## need to also be in the app wrapper, then a cp command will need to be added -## in an after_install target. -OTHER_HELP_DIRS = - -# After you have saved your project using the 4.0 PB, you will automatically -# start using the makefiles in $(SYSTEM_DEVELOPER_DIR)/Makefiles/project. If you should -# need to revert back to the old 3.3 Makefile behavior, override MAKEFILEDIR to -# be $(SYSTEM_DEVELOPER_DIR)/Makefiles/app. - -# Don't add more rules here unless you want the first one to be the default -# target for make! Put all your targets in Makefile.postamble. - diff --git a/ftp.tproj/cmds.c b/ftp.tproj/cmds.c deleted file mode 100644 index 6dd3f48..0000000 --- a/ftp.tproj/cmds.c +++ /dev/null @@ -1,2236 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * 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. - */ - -/* - * FTP User Program -- Command Routines. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ftp_var.h" -#include "pathnames.h" - -jmp_buf jabort; -char *mname; -char *home = "/"; - -/* - * `Another' gets another argument, and stores the new argc and argv. - * It reverts to the top level (via main.c's intr()) on EOF/error. - * - * Returns false if no new arguments have been added. - */ -int -another(pargc, pargv, prompt) - int *pargc; - char ***pargv; - char *prompt; -{ - int len = strlen(line), ret; - - if (len >= sizeof(line) - 3) { - printf("sorry, arguments too long\n"); - intr(); - } - printf("(%s) ", prompt); - line[len++] = ' '; - if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) - intr(); - len += strlen(&line[len]); - if (len > 0 && line[len - 1] == '\n') - line[len - 1] = '\0'; - makeargv(); - ret = margc > *pargc; - *pargc = margc; - *pargv = margv; - return (ret); -} - -/* - * Connect to peer server and - * auto-login, if possible. - */ -void -setpeer(argc, argv) - int argc; - char *argv[]; -{ - char *host; - short port; - - if (connected) { - printf("Already connected to %s, use close first.\n", - hostname); - code = -1; - return; - } - if (argc < 2) - (void) another(&argc, &argv, "to"); - if (argc < 2 || argc > 3) { - printf("usage: %s host-name [port]\n", argv[0]); - code = -1; - return; - } - port = sp->s_port; - if (argc > 2) { - port = atoi(argv[2]); - if (port <= 0) { - printf("%s: bad port number-- %s\n", argv[1], argv[2]); - printf ("usage: %s host-name [port]\n", argv[0]); - code = -1; - return; - } - port = htons(port); - } - host = hookup(argv[1], port); - if (host) { - int overbose; - - connected = 1; - /* - * Set up defaults for FTP. - */ - (void) strcpy(typename, "ascii"), type = TYPE_A; - curtype = TYPE_A; - (void) strcpy(formname, "non-print"), form = FORM_N; - (void) strcpy(modename, "stream"), mode = MODE_S; - (void) strcpy(structname, "file"), stru = STRU_F; - (void) strcpy(bytename, "8"), bytesize = 8; - if (autologin) - (void) login(argv[1]); - -#if (defined(unix) || defined(__APPLE__)) && NBBY == 8 -/* - * this ifdef is to keep someone form "porting" this to an incompatible - * system and not checking this out. This way they have to think about it. - */ - overbose = verbose; - if (debug == 0) - verbose = -1; - if (command("SYST") == COMPLETE && overbose) { - char *cp, c; - cp = strchr(reply_string+4, ' '); - if (cp == NULL) - cp = strchr(reply_string+4, '\r'); - if (cp) { - if (cp[-1] == '.') - cp--; - c = *cp; - *cp = '\0'; - } - - printf("Remote system type is %s.\n", - reply_string+4); - if (cp) - *cp = c; - } - if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { - if (proxy) - unix_proxy = 1; - else - unix_server = 1; - /* - * Set type to 0 (not specified by user), - * meaning binary by default, but don't bother - * telling server. We can use binary - * for text files unless changed by the user. - */ - type = 0; - (void) strcpy(typename, "binary"); - if (overbose) - printf("Using %s mode to transfer files.\n", - typename); - } else { - if (proxy) - unix_proxy = 0; - else - unix_server = 0; - if (overbose && - !strncmp(reply_string, "215 TOPS20", 10)) - printf( -"Remember to set tenex mode when transfering binary files from this machine.\n"); - } - verbose = overbose; -#endif /* unix */ - } -} - -struct types { - char *t_name; - char *t_mode; - int t_type; - char *t_arg; -} types[] = { - { "ascii", "A", TYPE_A, 0 }, - { "binary", "I", TYPE_I, 0 }, - { "image", "I", TYPE_I, 0 }, - { "ebcdic", "E", TYPE_E, 0 }, - { "tenex", "L", TYPE_L, bytename }, - { NULL } -}; - -/* - * Set transfer type. - */ -void -settype(argc, argv) - int argc; - char *argv[]; -{ - struct types *p; - int comret; - - if (argc > 2) { - char *sep; - - printf("usage: %s [", argv[0]); - sep = " "; - for (p = types; p->t_name; p++) { - printf("%s%s", sep, p->t_name); - sep = " | "; - } - printf(" ]\n"); - code = -1; - return; - } - if (argc < 2) { - printf("Using %s mode to transfer files.\n", typename); - code = 0; - return; - } - for (p = types; p->t_name; p++) - if (strcmp(argv[1], p->t_name) == 0) - break; - if (p->t_name == 0) { - printf("%s: unknown mode\n", argv[1]); - code = -1; - return; - } - if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) - comret = command ("TYPE %s %s", p->t_mode, p->t_arg); - else - comret = command("TYPE %s", p->t_mode); - if (comret == COMPLETE) { - (void) strcpy(typename, p->t_name); - curtype = type = p->t_type; - } -} - -/* - * Internal form of settype; changes current type in use with server - * without changing our notion of the type for data transfers. - * Used to change to and from ascii for listings. - */ -void -changetype(newtype, show) - int newtype, show; -{ - struct types *p; - int comret, oldverbose = verbose; - - if (newtype == 0) - newtype = TYPE_I; - if (newtype == curtype) - return; - if (debug == 0 && show == 0) - verbose = 0; - for (p = types; p->t_name; p++) - if (newtype == p->t_type) - break; - if (p->t_name == 0) { - printf("ftp: internal error: unknown type %d\n", newtype); - return; - } - if (newtype == TYPE_L && bytename[0] != '\0') - comret = command("TYPE %s %s", p->t_mode, bytename); - else - comret = command("TYPE %s", p->t_mode); - if (comret == COMPLETE) - curtype = newtype; - verbose = oldverbose; -} - -char *stype[] = { - "type", - "", - 0 -}; - -/* - * Set binary transfer type. - */ -/*VARARGS*/ -void -setbinary(argc, argv) - int argc; - char **argv; -{ - - stype[1] = "binary"; - settype(2, stype); -} - -/* - * Set ascii transfer type. - */ -/*VARARGS*/ -void -setascii(argc, argv) - int argc; - char *argv[]; -{ - - stype[1] = "ascii"; - settype(2, stype); -} - -/* - * Set tenex transfer type. - */ -/*VARARGS*/ -void -settenex(argc, argv) - int argc; - char *argv[]; -{ - - stype[1] = "tenex"; - settype(2, stype); -} - -/* - * Set file transfer mode. - */ -/*ARGSUSED*/ -void -setftmode(argc, argv) - int argc; - char *argv[]; -{ - - printf("We only support %s mode, sorry.\n", modename); - code = -1; -} - -/* - * Set file transfer format. - */ -/*ARGSUSED*/ -void -setform(argc, argv) - int argc; - char *argv[]; -{ - - printf("We only support %s format, sorry.\n", formname); - code = -1; -} - -/* - * Set file transfer structure. - */ -/*ARGSUSED*/ -void -setstruct(argc, argv) - int argc; - char *argv[]; -{ - - printf("We only support %s structure, sorry.\n", structname); - code = -1; -} - -/* - * Send a single file. - */ -void -put(argc, argv) - int argc; - char *argv[]; -{ - char *cmd; - int loc = 0; - char *oldargv1, *oldargv2; - - if (argc == 2) { - argc++; - argv[2] = argv[1]; - loc++; - } - if (argc < 2 && !another(&argc, &argv, "local-file")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "remote-file")) { -usage: - printf("usage: %s local-file remote-file\n", argv[0]); - code = -1; - return; - } - oldargv1 = argv[1]; - oldargv2 = argv[2]; - if (!globulize(&argv[1])) { - code = -1; - return; - } - /* - * If "globulize" modifies argv[1], and argv[2] is a copy of - * the old argv[1], make it a copy of the new argv[1]. - */ - if (argv[1] != oldargv1 && argv[2] == oldargv1) { - argv[2] = argv[1]; - } - cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); - if (loc && ntflag) { - argv[2] = dotrans(argv[2]); - } - if (loc && mapflag) { - argv[2] = domap(argv[2]); - } - sendrequest(cmd, argv[1], argv[2], - argv[1] != oldargv1 || argv[2] != oldargv2); -} - -/* - * Send multiple files. - */ -void -mput(argc, argv) - int argc; - char **argv; -{ - int i; - sig_t oldintr; - int ointer; - char *tp; - - if (argc < 2 && !another(&argc, &argv, "local-files")) { - printf("usage: %s local-files\n", argv[0]); - code = -1; - return; - } - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - (void) setjmp(jabort); - if (proxy) { - char *cp, *tp2, tmpbuf[MAXPATHLEN]; - - while ((cp = remglob(argv,0)) != NULL) { - if (*cp == 0) { - mflag = 0; - continue; - } - if (mflag && confirm(argv[0], cp)) { - tp = cp; - if (mcase) { - while (*tp && !islower(*tp)) { - tp++; - } - if (!*tp) { - tp = cp; - tp2 = tmpbuf; - while ((*tp2 = *tp) != NULL) { - if (isupper(*tp2)) { - *tp2 = 'a' + *tp2 - 'A'; - } - tp++; - tp2++; - } - } - tp = tmpbuf; - } - if (ntflag) { - tp = dotrans(tp); - } - if (mapflag) { - tp = domap(tp); - } - sendrequest((sunique) ? "STOU" : "STOR", - cp, tp, cp != tp || !interactive); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mput")) { - mflag++; - } - interactive = ointer; - } - } - } - (void) signal(SIGINT, oldintr); - mflag = 0; - return; - } - for (i = 1; i < argc; i++) { - char **cpp, **gargs; - glob_t gl; - int flags; - - if (!doglob) { - if (mflag && confirm(argv[0], argv[i])) { - tp = (ntflag) ? dotrans(argv[i]) : argv[i]; - tp = (mapflag) ? domap(tp) : tp; - sendrequest((sunique) ? "STOU" : "STOR", - argv[i], tp, tp != argv[i] || !interactive); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mput")) { - mflag++; - } - interactive = ointer; - } - } - continue; - } - - memset(&gl, 0, sizeof(gl)); - flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { - warnx("%s: not found", argv[i]); - globfree(&gl); - continue; - } - for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) { - if (mflag && confirm(argv[0], *cpp)) { - tp = (ntflag) ? dotrans(*cpp) : *cpp; - tp = (mapflag) ? domap(tp) : tp; - sendrequest((sunique) ? "STOU" : "STOR", - *cpp, tp, *cpp != tp || !interactive); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mput")) { - mflag++; - } - interactive = ointer; - } - } - } - globfree(&gl); - } - (void) signal(SIGINT, oldintr); - mflag = 0; -} - -void -reget(argc, argv) - int argc; - char *argv[]; -{ - - (void) getit(argc, argv, 1, "r+w"); -} - -void -get(argc, argv) - int argc; - char *argv[]; -{ - - (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" ); -} - -/* - * Receive one file. - */ -int -getit(argc, argv, restartit, mode) - int argc; - char *argv[]; - char *mode; - int restartit; -{ - int loc = 0; - char *oldargv1, *oldargv2; - - if (argc == 2) { - argc++; - argv[2] = argv[1]; - loc++; - } - if (argc < 2 && !another(&argc, &argv, "remote-file")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "local-file")) { -usage: - printf("usage: %s remote-file [ local-file ]\n", argv[0]); - code = -1; - return (0); - } - oldargv1 = argv[1]; - oldargv2 = argv[2]; - if (!globulize(&argv[2])) { - code = -1; - return (0); - } - if (loc && mcase) { - char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; - - while (*tp && !islower(*tp)) { - tp++; - } - if (!*tp) { - tp = argv[2]; - tp2 = tmpbuf; - while ((*tp2 = *tp) != NULL) { - if (isupper(*tp2)) { - *tp2 = 'a' + *tp2 - 'A'; - } - tp++; - tp2++; - } - argv[2] = tmpbuf; - } - } - if (loc && ntflag) - argv[2] = dotrans(argv[2]); - if (loc && mapflag) - argv[2] = domap(argv[2]); - if (restartit) { - struct stat stbuf; - int ret; - - ret = stat(argv[2], &stbuf); - if (restartit == 1) { - if (ret < 0) { - warn("local: %s", argv[2]); - return (0); - } - restart_point = stbuf.st_size; - } else { - if (ret == 0) { - int overbose; - - overbose = verbose; - if (debug == 0) - verbose = -1; - if (command("MDTM %s", argv[1]) == COMPLETE) { - int yy, mo, day, hour, min, sec; - struct tm *tm; - verbose = overbose; - sscanf(reply_string, - "%*s %04d%02d%02d%02d%02d%02d", - &yy, &mo, &day, &hour, &min, &sec); - tm = gmtime(&stbuf.st_mtime); - tm->tm_mon++; - if (tm->tm_year > yy%100) - return (1); - if ((tm->tm_year == yy%100 && - tm->tm_mon > mo) || - (tm->tm_mon == mo && - tm->tm_mday > day) || - (tm->tm_mday == day && - tm->tm_hour > hour) || - (tm->tm_hour == hour && - tm->tm_min > min) || - (tm->tm_min == min && - tm->tm_sec > sec)) - return (1); - } else { - printf("%s\n", reply_string); - verbose = overbose; - return (0); - } - } - } - } - - recvrequest("RETR", argv[2], argv[1], mode, - argv[1] != oldargv1 || argv[2] != oldargv2); - restart_point = 0; - return (0); -} - -/* ARGSUSED */ -void -mabort(signo) - int signo; -{ - int ointer; - - printf("\n"); - (void) fflush(stdout); - if (mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with", mname)) { - interactive = ointer; - longjmp(jabort,0); - } - interactive = ointer; - } - mflag = 0; - longjmp(jabort,0); -} - -/* - * Get multiple files. - */ -void -mget(argc, argv) - int argc; - char **argv; -{ - sig_t oldintr; - int ch, ointer; - char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; - - if (argc < 2 && !another(&argc, &argv, "remote-files")) { - printf("usage: %s remote-files\n", argv[0]); - code = -1; - return; - } - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - (void) setjmp(jabort); - while ((cp = remglob(argv,proxy)) != NULL) { - if (*cp == '\0') { - mflag = 0; - continue; - } - if (mflag && confirm(argv[0], cp)) { - tp = cp; - if (mcase) { - for (tp2 = tmpbuf; ch = *tp++;) - *tp2++ = isupper(ch) ? tolower(ch) : ch; - tp = tmpbuf; - } - if (ntflag) { - tp = dotrans(tp); - } - if (mapflag) { - tp = domap(tp); - } - recvrequest("RETR", tp, cp, "w", - tp != cp || !interactive); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with","mget")) { - mflag++; - } - interactive = ointer; - } - } - } - (void) signal(SIGINT,oldintr); - mflag = 0; -} - -char * -remglob(argv,doswitch) - char *argv[]; - int doswitch; -{ - char temp[16]; - static char buf[MAXPATHLEN]; - static FILE *ftemp = NULL; - static char **args; - int oldverbose, oldhash; - char *cp, *mode; - - if (!mflag) { - if (!doglob) { - args = NULL; - } - else { - if (ftemp) { - (void) fclose(ftemp); - ftemp = NULL; - } - } - return (NULL); - } - if (!doglob) { - if (args == NULL) - args = argv; - if ((cp = *++args) == NULL) - args = NULL; - return (cp); - } - if (ftemp == NULL) { - (void) strcpy(temp, _PATH_TMP); - (void) mktemp(temp); - oldverbose = verbose, verbose = 0; - oldhash = hash, hash = 0; - if (doswitch) { - pswitch(!proxy); - } - for (mode = "w"; *++argv != NULL; mode = "a") - recvrequest ("NLST", temp, *argv, mode, 0); - if (doswitch) { - pswitch(!proxy); - } - verbose = oldverbose; hash = oldhash; - ftemp = fopen(temp, "r"); - (void) unlink(temp); - if (ftemp == NULL) { - printf("can't find list of remote files, oops\n"); - return (NULL); - } - } - if (fgets(buf, sizeof (buf), ftemp) == NULL) { - (void) fclose(ftemp), ftemp = NULL; - return (NULL); - } - if ((cp = strchr(buf, '\n')) != NULL) - *cp = '\0'; - return (buf); -} - -char * -onoff(bool) - int bool; -{ - - return (bool ? "on" : "off"); -} - -/* - * Show status. - */ -/*ARGSUSED*/ -void -status(argc, argv) - int argc; - char *argv[]; -{ - int i; - - if (connected) - printf("Connected to %s.\n", hostname); - else - printf("Not connected.\n"); - if (!proxy) { - pswitch(1); - if (connected) { - printf("Connected for proxy commands to %s.\n", hostname); - } - else { - printf("No proxy connection.\n"); - } - pswitch(0); - } - printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", - modename, typename, formname, structname); - printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", - onoff(verbose), onoff(bell), onoff(interactive), - onoff(doglob)); - printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), - onoff(runique)); - printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); - if (ntflag) { - printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); - } - else { - printf("Ntrans: off\n"); - } - if (mapflag) { - printf("Nmap: (in) %s (out) %s\n", mapin, mapout); - } - else { - printf("Nmap: off\n"); - } - printf("Hash mark printing: %s; Use of PORT cmds: %s\n", - onoff(hash), onoff(sendport)); - if (macnum > 0) { - printf("Macros:\n"); - for (i=0; i 1) { - val = atoi(argv[1]); - if (val < 0) { - printf("%s: bad debugging value.\n", argv[1]); - code = -1; - return; - } - } else - val = !debug; - debug = val; - if (debug) - options |= SO_DEBUG; - else - options &= ~SO_DEBUG; - printf("Debugging %s (debug=%d).\n", onoff(debug), debug); - code = debug > 0; -} - -/* - * Set current working directory - * on remote machine. - */ -void -cd(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "remote-directory")) { - printf("usage: %s remote-directory\n", argv[0]); - code = -1; - return; - } - if (command("CWD %s", argv[1]) == ERROR && code == 500) { - if (verbose) - printf("CWD command not recognized, trying XCWD\n"); - (void) command("XCWD %s", argv[1]); - } -} - -/* - * Set current working directory - * on local machine. - */ -void -lcd(argc, argv) - int argc; - char *argv[]; -{ - char buf[MAXPATHLEN]; - - if (argc < 2) - argc++, argv[1] = home; - if (argc != 2) { - printf("usage: %s local-directory\n", argv[0]); - code = -1; - return; - } - if (!globulize(&argv[1])) { - code = -1; - return; - } - if (chdir(argv[1]) < 0) { - warn("local: %s", argv[1]); - code = -1; - return; - } - if (getwd(buf) != NULL) - printf("Local directory now %s\n", buf); - else - warnx("getwd: %s", buf); - code = 0; -} - -/* - * Delete a single file. - */ -void -delete(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "remote-file")) { - printf("usage: %s remote-file\n", argv[0]); - code = -1; - return; - } - (void) command("DELE %s", argv[1]); -} - -/* - * Delete multiple files. - */ -void -mdelete(argc, argv) - int argc; - char **argv; -{ - sig_t oldintr; - int ointer; - char *cp; - - if (argc < 2 && !another(&argc, &argv, "remote-files")) { - printf("usage: %s remote-files\n", argv[0]); - code = -1; - return; - } - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - (void) setjmp(jabort); - while ((cp = remglob(argv,0)) != NULL) { - if (*cp == '\0') { - mflag = 0; - continue; - } - if (mflag && confirm(argv[0], cp)) { - (void) command("DELE %s", cp); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with", "mdelete")) { - mflag++; - } - interactive = ointer; - } - } - } - (void) signal(SIGINT, oldintr); - mflag = 0; -} - -/* - * Rename a remote file. - */ -void -renamefile(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "from-name")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "to-name")) { -usage: - printf("%s from-name to-name\n", argv[0]); - code = -1; - return; - } - if (command("RNFR %s", argv[1]) == CONTINUE) - (void) command("RNTO %s", argv[2]); -} - -/* - * Get a directory listing - * of remote files. - */ -void -ls(argc, argv) - int argc; - char *argv[]; -{ - char *cmd; - - if (argc < 2) - argc++, argv[1] = NULL; - if (argc < 3) - argc++, argv[2] = "-"; - if (argc > 3) { - printf("usage: %s remote-directory local-file\n", argv[0]); - code = -1; - return; - } - cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; - if (strcmp(argv[2], "-") && !globulize(&argv[2])) { - code = -1; - return; - } - if (strcmp(argv[2], "-") && *argv[2] != '|') - if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { - code = -1; - return; - } - recvrequest(cmd, argv[2], argv[1], "w", 0); -} - -/* - * Get a directory listing - * of multiple remote files. - */ -void -mls(argc, argv) - int argc; - char **argv; -{ - sig_t oldintr; - int ointer, i; - char *cmd, mode[1], *dest; - - if (argc < 2 && !another(&argc, &argv, "remote-files")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "local-file")) { -usage: - printf("usage: %s remote-files local-file\n", argv[0]); - code = -1; - return; - } - dest = argv[argc - 1]; - argv[argc - 1] = NULL; - if (strcmp(dest, "-") && *dest != '|') - if (!globulize(&dest) || - !confirm("output to local-file:", dest)) { - code = -1; - return; - } - cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; - mname = argv[0]; - mflag = 1; - oldintr = signal(SIGINT, mabort); - (void) setjmp(jabort); - for (i = 1; mflag && i < argc-1; ++i) { - *mode = (i == 1) ? 'w' : 'a'; - recvrequest(cmd, dest, argv[i], mode, 0); - if (!mflag && fromatty) { - ointer = interactive; - interactive = 1; - if (confirm("Continue with", argv[0])) { - mflag ++; - } - interactive = ointer; - } - } - (void) signal(SIGINT, oldintr); - mflag = 0; -} - -/* - * Do a shell escape - */ -/*ARGSUSED*/ -void -shell(argc, argv) - int argc; - char **argv; -{ - pid_t pid; - sig_t old1, old2; - char shellnam[40], *shell, *namep; - union wait status; - - old1 = signal (SIGINT, SIG_IGN); - old2 = signal (SIGQUIT, SIG_IGN); - if ((pid = fork()) == 0) { - for (pid = 3; pid < 20; pid++) - (void) close(pid); - (void) signal(SIGINT, SIG_DFL); - (void) signal(SIGQUIT, SIG_DFL); - shell = getenv("SHELL"); - if (shell == NULL) - shell = _PATH_BSHELL; - namep = strrchr(shell,'/'); - if (namep == NULL) - namep = shell; - (void) strcpy(shellnam,"-"); - (void) strcat(shellnam, ++namep); - if (strcmp(namep, "sh") != 0) - shellnam[0] = '+'; - if (debug) { - printf ("%s\n", shell); - (void) fflush (stdout); - } - if (argc > 1) { - execl(shell,shellnam,"-c",altarg,(char *)0); - } - else { - execl(shell,shellnam,(char *)0); - } - warn("%s", shell); - code = -1; - exit(1); - } - if (pid > 0) - while (wait((int *)&status) != pid) - ; - (void) signal(SIGINT, old1); - (void) signal(SIGQUIT, old2); - if (pid == -1) { - warn("%s", "Try again later"); - code = -1; - } - else { - code = 0; - } -} - -/* - * Send new user information (re-login) - */ -void -user(argc, argv) - int argc; - char **argv; -{ - char acct[80]; - int n, aflag = 0; - - if (argc < 2) - (void) another(&argc, &argv, "username"); - if (argc < 2 || argc > 4) { - printf("usage: %s username [password] [account]\n", argv[0]); - code = -1; - return; - } - n = command("USER %s", argv[1]); - if (n == CONTINUE) { - if (argc < 3 ) - argv[2] = getpass("Password: "), argc++; - n = command("PASS %s", argv[2]); - } - if (n == CONTINUE) { - if (argc < 4) { - printf("Account: "); (void) fflush(stdout); - (void) fgets(acct, sizeof(acct) - 1, stdin); - acct[strlen(acct) - 1] = '\0'; - argv[3] = acct; argc++; - } - n = command("ACCT %s", argv[3]); - aflag++; - } - if (n != COMPLETE) { - fprintf(stdout, "Login failed.\n"); - return; - } - if (!aflag && argc == 4) { - (void) command("ACCT %s", argv[3]); - } -} - -/* - * Print working directory. - */ -/*VARARGS*/ -void -pwd(argc, argv) - int argc; - char *argv[]; -{ - int oldverbose = verbose; - - /* - * If we aren't verbose, this doesn't do anything! - */ - verbose = 1; - if (command("PWD") == ERROR && code == 500) { - printf("PWD command not recognized, trying XPWD\n"); - (void) command("XPWD"); - } - verbose = oldverbose; -} - -/* - * Make a directory. - */ -void -makedir(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "directory-name")) { - printf("usage: %s directory-name\n", argv[0]); - code = -1; - return; - } - if (command("MKD %s", argv[1]) == ERROR && code == 500) { - if (verbose) - printf("MKD command not recognized, trying XMKD\n"); - (void) command("XMKD %s", argv[1]); - } -} - -/* - * Remove a directory. - */ -void -removedir(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "directory-name")) { - printf("usage: %s directory-name\n", argv[0]); - code = -1; - return; - } - if (command("RMD %s", argv[1]) == ERROR && code == 500) { - if (verbose) - printf("RMD command not recognized, trying XRMD\n"); - (void) command("XRMD %s", argv[1]); - } -} - -/* - * Send a line, verbatim, to the remote machine. - */ -void -quote(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "command line to send")) { - printf("usage: %s line-to-send\n", argv[0]); - code = -1; - return; - } - quote1("", argc, argv); -} - -/* - * Send a SITE command to the remote machine. The line - * is sent verbatim to the remote machine, except that the - * word "SITE" is added at the front. - */ -void -site(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { - printf("usage: %s line-to-send\n", argv[0]); - code = -1; - return; - } - quote1("SITE ", argc, argv); -} - -/* - * Turn argv[1..argc) into a space-separated string, then prepend initial text. - * Send the result as a one-line command and get response. - */ -void -quote1(initial, argc, argv) - char *initial; - int argc; - char **argv; -{ - int i, len; - char buf[BUFSIZ]; /* must be >= sizeof(line) */ - - (void) strcpy(buf, initial); - if (argc > 1) { - len = strlen(buf); - len += strlen(strcpy(&buf[len], argv[1])); - for (i = 2; i < argc; i++) { - buf[len++] = ' '; - len += strlen(strcpy(&buf[len], argv[i])); - } - } - if (command(buf) == PRELIM) { - while (getreply(0) == PRELIM) - continue; - } -} - -void -do_chmod(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "mode")) - goto usage; - if (argc < 3 && !another(&argc, &argv, "file-name")) { -usage: - printf("usage: %s mode file-name\n", argv[0]); - code = -1; - return; - } - (void) command("SITE CHMOD %s %s", argv[1], argv[2]); -} - -void -do_umask(argc, argv) - int argc; - char *argv[]; -{ - int oldverbose = verbose; - - verbose = 1; - (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); - verbose = oldverbose; -} - -void -idle(argc, argv) - int argc; - char *argv[]; -{ - int oldverbose = verbose; - - verbose = 1; - (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); - verbose = oldverbose; -} - -/* - * Ask the other side for help. - */ -void -rmthelp(argc, argv) - int argc; - char *argv[]; -{ - int oldverbose = verbose; - - verbose = 1; - (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); - verbose = oldverbose; -} - -/* - * Terminate session and exit. - */ -/*VARARGS*/ -void -quit(argc, argv) - int argc; - char *argv[]; -{ - - if (connected) - disconnect(0, 0); - pswitch(1); - if (connected) { - disconnect(0, 0); - } - exit(0); -} - -/* - * Terminate session, but don't exit. - */ -void -disconnect(argc, argv) - int argc; - char *argv[]; -{ - - if (!connected) - return; - (void) command("QUIT"); - if (cout) { - (void) fclose(cout); - } - cout = NULL; - connected = 0; - data = -1; - if (!proxy) { - macnum = 0; - } -} - -int -confirm(cmd, file) - char *cmd, *file; -{ - char line[BUFSIZ]; - - if (!interactive) - return (1); - printf("%s %s? ", cmd, file); - (void) fflush(stdout); - if (fgets(line, sizeof line, stdin) == NULL) - return (0); - return (*line != 'n' && *line != 'N'); -} - -void -fatal(msg) - char *msg; -{ - - errx(1, "%s", msg); -} - -/* - * Glob a local file name specification with - * the expectation of a single return value. - * Can't control multiple values being expanded - * from the expression, we return only the first. - */ -int -globulize(cpp) - char **cpp; -{ - glob_t gl; - int flags; - - if (!doglob) - return (1); - - flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - memset(&gl, 0, sizeof(gl)); - if (glob(*cpp, flags, NULL, &gl) || - gl.gl_pathc == 0) { - warnx("%s: not found", *cpp); - globfree(&gl); - return (0); - } - *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */ - globfree(&gl); - return (1); -} - -void -account(argc,argv) - int argc; - char **argv; -{ - char acct[50], *ap; - - if (argc > 1) { - ++argv; - --argc; - (void) strncpy(acct,*argv,49); - acct[49] = '\0'; - while (argc > 1) { - --argc; - ++argv; - (void) strncat(acct,*argv, 49-strlen(acct)); - } - ap = acct; - } - else { - ap = getpass("Account:"); - } - (void) command("ACCT %s", ap); -} - -jmp_buf abortprox; - -void -proxabort() -{ - - if (!proxy) { - pswitch(1); - } - if (connected) { - proxflag = 1; - } - else { - proxflag = 0; - } - pswitch(0); - longjmp(abortprox,1); -} - -void -doproxy(argc, argv) - int argc; - char *argv[]; -{ - struct cmd *c; - sig_t oldintr; - - if (argc < 2 && !another(&argc, &argv, "command")) { - printf("usage: %s command\n", argv[0]); - code = -1; - return; - } - c = getcmd(argv[1]); - if (c == (struct cmd *) -1) { - printf("?Ambiguous command\n"); - (void) fflush(stdout); - code = -1; - return; - } - if (c == 0) { - printf("?Invalid command\n"); - (void) fflush(stdout); - code = -1; - return; - } - if (!c->c_proxy) { - printf("?Invalid proxy command\n"); - (void) fflush(stdout); - code = -1; - return; - } - if (setjmp(abortprox)) { - code = -1; - return; - } - oldintr = signal(SIGINT, proxabort); - pswitch(1); - if (c->c_conn && !connected) { - printf("Not connected\n"); - (void) fflush(stdout); - pswitch(0); - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - (*c->c_handler)(argc-1, argv+1); - if (connected) { - proxflag = 1; - } - else { - proxflag = 0; - } - pswitch(0); - (void) signal(SIGINT, oldintr); -} - -void -setcase(argc, argv) - int argc; - char *argv[]; -{ - - mcase = !mcase; - printf("Case mapping %s.\n", onoff(mcase)); - code = mcase; -} - -void -setcr(argc, argv) - int argc; - char *argv[]; -{ - - crflag = !crflag; - printf("Carriage Return stripping %s.\n", onoff(crflag)); - code = crflag; -} - -void -setntrans(argc,argv) - int argc; - char *argv[]; -{ - if (argc == 1) { - ntflag = 0; - printf("Ntrans off.\n"); - code = ntflag; - return; - } - ntflag++; - code = ntflag; - (void) strncpy(ntin, argv[1], 16); - ntin[16] = '\0'; - if (argc == 2) { - ntout[0] = '\0'; - return; - } - (void) strncpy(ntout, argv[2], 16); - ntout[16] = '\0'; -} - -char * -dotrans(name) - char *name; -{ - static char new[MAXPATHLEN]; - char *cp1, *cp2 = new; - int i, ostop, found; - - for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) - continue; - for (cp1 = name; *cp1; cp1++) { - found = 0; - for (i = 0; *(ntin + i) && i < 16; i++) { - if (*cp1 == *(ntin + i)) { - found++; - if (i < ostop) { - *cp2++ = *(ntout + i); - } - break; - } - } - if (!found) { - *cp2++ = *cp1; - } - } - *cp2 = '\0'; - return (new); -} - -void -setnmap(argc, argv) - int argc; - char *argv[]; -{ - char *cp; - - if (argc == 1) { - mapflag = 0; - printf("Nmap off.\n"); - code = mapflag; - return; - } - if (argc < 3 && !another(&argc, &argv, "mapout")) { - printf("Usage: %s [mapin mapout]\n",argv[0]); - code = -1; - return; - } - mapflag = 1; - code = 1; - cp = strchr(altarg, ' '); - if (proxy) { - while(*++cp == ' ') - continue; - altarg = cp; - cp = strchr(altarg, ' '); - } - *cp = '\0'; - (void) strncpy(mapin, altarg, MAXPATHLEN - 1); - while (*++cp == ' ') - continue; - (void) strncpy(mapout, cp, MAXPATHLEN - 1); -} - -char * -domap(name) - char *name; -{ - static char new[MAXPATHLEN]; - char *cp1 = name, *cp2 = mapin; - char *tp[9], *te[9]; - int i, toks[9], toknum = 0, match = 1; - - for (i=0; i < 9; ++i) { - toks[i] = 0; - } - while (match && *cp1 && *cp2) { - switch (*cp2) { - case '\\': - if (*++cp2 != *cp1) { - match = 0; - } - break; - case '$': - if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { - if (*cp1 != *(++cp2+1)) { - toks[toknum = *cp2 - '1']++; - tp[toknum] = cp1; - while (*++cp1 && *(cp2+1) - != *cp1); - te[toknum] = cp1; - } - cp2++; - break; - } - /* FALLTHROUGH */ - default: - if (*cp2 != *cp1) { - match = 0; - } - break; - } - if (match && *cp1) { - cp1++; - } - if (match && *cp2) { - cp2++; - } - } - if (!match && *cp1) /* last token mismatch */ - { - toks[toknum] = 0; - } - cp1 = new; - *cp1 = '\0'; - cp2 = mapout; - while (*cp2) { - match = 0; - switch (*cp2) { - case '\\': - if (*(cp2 + 1)) { - *cp1++ = *++cp2; - } - break; - case '[': -LOOP: - if (*++cp2 == '$' && isdigit(*(cp2+1))) { - if (*++cp2 == '0') { - char *cp3 = name; - - while (*cp3) { - *cp1++ = *cp3++; - } - match = 1; - } - else if (toks[toknum = *cp2 - '1']) { - char *cp3 = tp[toknum]; - - while (cp3 != te[toknum]) { - *cp1++ = *cp3++; - } - match = 1; - } - } - else { - while (*cp2 && *cp2 != ',' && - *cp2 != ']') { - if (*cp2 == '\\') { - cp2++; - } - else if (*cp2 == '$' && - isdigit(*(cp2+1))) { - if (*++cp2 == '0') { - char *cp3 = name; - - while (*cp3) { - *cp1++ = *cp3++; - } - } - else if (toks[toknum = - *cp2 - '1']) { - char *cp3=tp[toknum]; - - while (cp3 != - te[toknum]) { - *cp1++ = *cp3++; - } - } - } - else if (*cp2) { - *cp1++ = *cp2++; - } - } - if (!*cp2) { - printf("nmap: unbalanced brackets\n"); - return (name); - } - match = 1; - cp2--; - } - if (match) { - while (*++cp2 && *cp2 != ']') { - if (*cp2 == '\\' && *(cp2 + 1)) { - cp2++; - } - } - if (!*cp2) { - printf("nmap: unbalanced brackets\n"); - return (name); - } - break; - } - switch (*++cp2) { - case ',': - goto LOOP; - case ']': - break; - default: - cp2--; - goto LOOP; - } - break; - case '$': - if (isdigit(*(cp2 + 1))) { - if (*++cp2 == '0') { - char *cp3 = name; - - while (*cp3) { - *cp1++ = *cp3++; - } - } - else if (toks[toknum = *cp2 - '1']) { - char *cp3 = tp[toknum]; - - while (cp3 != te[toknum]) { - *cp1++ = *cp3++; - } - } - break; - } - /* intentional drop through */ - default: - *cp1++ = *cp2; - break; - } - cp2++; - } - *cp1 = '\0'; - if (!*new) { - return (name); - } - return (new); -} - -void -setpassive(argc, argv) - int argc; - char *argv[]; -{ - - passivemode = !passivemode; - printf("Passive mode %s.\n", onoff(passivemode)); - code = passivemode; -} - -void -setsunique(argc, argv) - int argc; - char *argv[]; -{ - - sunique = !sunique; - printf("Store unique %s.\n", onoff(sunique)); - code = sunique; -} - -void -setrunique(argc, argv) - int argc; - char *argv[]; -{ - - runique = !runique; - printf("Receive unique %s.\n", onoff(runique)); - code = runique; -} - -/* change directory to perent directory */ -void -cdup(argc, argv) - int argc; - char *argv[]; -{ - - if (command("CDUP") == ERROR && code == 500) { - if (verbose) - printf("CDUP command not recognized, trying XCUP\n"); - (void) command("XCUP"); - } -} - -/* restart transfer at specific point */ -void -restart(argc, argv) - int argc; - char *argv[]; -{ - - if (argc != 2) - printf("restart: offset not specified\n"); - else { - restart_point = atol(argv[1]); - printf("restarting at %qd. %s\n", restart_point, - "execute get, put or append to initiate transfer"); - } -} - -/* show remote system type */ -void -syst(argc, argv) - int argc; - char *argv[]; -{ - - (void) command("SYST"); -} - -void -macdef(argc, argv) - int argc; - char *argv[]; -{ - char *tmp; - int c; - - if (macnum == 16) { - printf("Limit of 16 macros have already been defined\n"); - code = -1; - return; - } - if (argc < 2 && !another(&argc, &argv, "macro name")) { - printf("Usage: %s macro_name\n",argv[0]); - code = -1; - return; - } - if (interactive) { - printf("Enter macro line by line, terminating it with a null line\n"); - } - (void) strncpy(macros[macnum].mac_name, argv[1], 8); - if (macnum == 0) { - macros[macnum].mac_start = macbuf; - } - else { - macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; - } - tmp = macros[macnum].mac_start; - while (tmp != macbuf+4096) { - if ((c = getchar()) == EOF) { - printf("macdef:end of file encountered\n"); - code = -1; - return; - } - if ((*tmp = c) == '\n') { - if (tmp == macros[macnum].mac_start) { - macros[macnum++].mac_end = tmp; - code = 0; - return; - } - if (*(tmp-1) == '\0') { - macros[macnum++].mac_end = tmp - 1; - code = 0; - return; - } - *tmp = '\0'; - } - tmp++; - } - while (1) { - while ((c = getchar()) != '\n' && c != EOF) - /* LOOP */; - if (c == EOF || getchar() == '\n') { - printf("Macro not defined - 4k buffer exceeded\n"); - code = -1; - return; - } - } -} - -/* - * get size of file on remote machine - */ -void -sizecmd(argc, argv) - int argc; - char *argv[]; -{ - - if (argc < 2 && !another(&argc, &argv, "filename")) { - printf("usage: %s filename\n", argv[0]); - code = -1; - return; - } - (void) command("SIZE %s", argv[1]); -} - -/* - * get last modification time of file on remote machine - */ -void -modtime(argc, argv) - int argc; - char *argv[]; -{ - int overbose; - - if (argc < 2 && !another(&argc, &argv, "filename")) { - printf("usage: %s filename\n", argv[0]); - code = -1; - return; - } - overbose = verbose; - if (debug == 0) - verbose = -1; - if (command("MDTM %s", argv[1]) == COMPLETE) { - int yy, mo, day, hour, min, sec; - sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, - &day, &hour, &min, &sec); - /* might want to print this in local time */ - printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], - mo, day, yy, hour, min, sec); - } else - printf("%s\n", reply_string); - verbose = overbose; -} - -/* - * show status on reomte machine - */ -void -rmtstatus(argc, argv) - int argc; - char *argv[]; -{ - - (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); -} - -/* - * get file if modtime is more recent than current file - */ -void -newer(argc, argv) - int argc; - char *argv[]; -{ - - if (getit(argc, argv, -1, "w")) - printf("Local file \"%s\" is newer than remote file \"%s\"\n", - argv[2], argv[1]); -} diff --git a/ftp.tproj/cmdtab.c b/ftp.tproj/cmdtab.c deleted file mode 100644 index 177dd59..0000000 --- a/ftp.tproj/cmdtab.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * 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. - */ - -#include -#include "ftp_var.h" - -/* - * User FTP -- Command Tables. - */ - -char accounthelp[] = "send account command to remote server"; -char appendhelp[] = "append to a file"; -char asciihelp[] = "set ascii transfer type"; -char beephelp[] = "beep when command completed"; -char binaryhelp[] = "set binary transfer type"; -char casehelp[] = "toggle mget upper/lower case id mapping"; -char cdhelp[] = "change remote working directory"; -char cduphelp[] = "change remote working directory to parent directory"; -char chmodhelp[] = "change file permissions of remote file"; -char connecthelp[] = "connect to remote tftp"; -char crhelp[] = "toggle carriage return stripping on ascii gets"; -char deletehelp[] = "delete remote file"; -char debughelp[] = "toggle/set debugging mode"; -char dirhelp[] = "list contents of remote directory"; -char disconhelp[] = "terminate ftp session"; -char domachelp[] = "execute macro"; -char formhelp[] = "set file transfer format"; -char globhelp[] = "toggle metacharacter expansion of local file names"; -char hashhelp[] = "toggle printing `#' for each buffer transferred"; -char helphelp[] = "print local help information"; -char idlehelp[] = "get (set) idle timer on remote side"; -char lcdhelp[] = "change local working directory"; -char lshelp[] = "list contents of remote directory"; -char macdefhelp[] = "define a macro"; -char mdeletehelp[] = "delete multiple files"; -char mdirhelp[] = "list contents of multiple remote directories"; -char mgethelp[] = "get multiple files"; -char mkdirhelp[] = "make directory on the remote machine"; -char mlshelp[] = "list contents of multiple remote directories"; -char modtimehelp[] = "show last modification time of remote file"; -char modehelp[] = "set file transfer mode"; -char mputhelp[] = "send multiple files"; -char newerhelp[] = "get file if remote file is newer than local file "; -char nlisthelp[] = "nlist contents of remote directory"; -char nmaphelp[] = "set templates for default file name mapping"; -char ntranshelp[] = "set translation table for default file name mapping"; -char porthelp[] = "toggle use of PORT cmd for each data connection"; -char prompthelp[] = "force interactive prompting on multiple commands"; -char proxyhelp[] = "issue command on alternate connection"; -char pwdhelp[] = "print working directory on remote machine"; -char quithelp[] = "terminate ftp session and exit"; -char quotehelp[] = "send arbitrary ftp command"; -char receivehelp[] = "receive file"; -char regethelp[] = "get file restarting at end of local file"; -char remotehelp[] = "get help from remote server"; -char renamehelp[] = "rename file"; -char restarthelp[]= "restart file transfer at bytecount"; -char rmdirhelp[] = "remove directory on the remote machine"; -char rmtstatushelp[]="show status of remote machine"; -char runiquehelp[] = "toggle store unique for local files"; -char resethelp[] = "clear queued command replies"; -char sendhelp[] = "send one file"; -char passivehelp[] = "enter passive transfer mode"; -char sitehelp[] = "send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information"; -char shellhelp[] = "escape to the shell"; -char sizecmdhelp[] = "show size of remote file"; -char statushelp[] = "show current status"; -char structhelp[] = "set file transfer structure"; -char suniquehelp[] = "toggle store unique on remote machine"; -char systemhelp[] = "show remote system type"; -char tenexhelp[] = "set tenex file transfer type"; -char tracehelp[] = "toggle packet tracing"; -char typehelp[] = "set file transfer type"; -char umaskhelp[] = "get (set) umask on remote side"; -char userhelp[] = "send new user information"; -char verbosehelp[] = "toggle verbose mode"; - -struct cmd cmdtab[] = { - { "!", shellhelp, 0, 0, 0, shell }, - { "$", domachelp, 1, 0, 0, domacro }, - { "account", accounthelp, 0, 1, 1, account}, - { "append", appendhelp, 1, 1, 1, put }, - { "ascii", asciihelp, 0, 1, 1, setascii }, - { "bell", beephelp, 0, 0, 0, setbell }, - { "binary", binaryhelp, 0, 1, 1, setbinary }, - { "bye", quithelp, 0, 0, 0, quit }, - { "case", casehelp, 0, 0, 1, setcase }, - { "cd", cdhelp, 0, 1, 1, cd }, - { "cdup", cduphelp, 0, 1, 1, cdup }, - { "chmod", chmodhelp, 0, 1, 1, do_chmod }, - { "close", disconhelp, 0, 1, 1, disconnect }, - { "cr", crhelp, 0, 0, 0, setcr }, - { "delete", deletehelp, 0, 1, 1, delete }, - { "debug", debughelp, 0, 0, 0, setdebug }, - { "dir", dirhelp, 1, 1, 1, ls }, - { "disconnect", disconhelp, 0, 1, 1, disconnect }, - { "form", formhelp, 0, 1, 1, setform }, - { "get", receivehelp, 1, 1, 1, get }, - { "glob", globhelp, 0, 0, 0, setglob }, - { "hash", hashhelp, 0, 0, 0, sethash }, - { "help", helphelp, 0, 0, 1, help }, - { "idle", idlehelp, 0, 1, 1, idle }, - { "image", binaryhelp, 0, 1, 1, setbinary }, - { "lcd", lcdhelp, 0, 0, 0, lcd }, - { "ls", lshelp, 1, 1, 1, ls }, - { "macdef", macdefhelp, 0, 0, 0, macdef }, - { "mdelete", mdeletehelp, 1, 1, 1, mdelete }, - { "mdir", mdirhelp, 1, 1, 1, mls }, - { "mget", mgethelp, 1, 1, 1, mget }, - { "mkdir", mkdirhelp, 0, 1, 1, makedir }, - { "mls", mlshelp, 1, 1, 1, mls }, - { "mode", modehelp, 0, 1, 1, setftmode }, - { "modtime", modtimehelp, 0, 1, 1, modtime }, - { "mput", mputhelp, 1, 1, 1, mput }, - { "newer", newerhelp, 1, 1, 1, newer }, - { "nmap", nmaphelp, 0, 0, 1, setnmap }, - { "nlist", nlisthelp, 1, 1, 1, ls }, - { "ntrans", ntranshelp, 0, 0, 1, setntrans }, - { "open", connecthelp, 0, 0, 1, setpeer }, - { "passive", passivehelp, 0, 0, 0, setpassive }, - { "prompt", prompthelp, 0, 0, 0, setprompt }, - { "proxy", proxyhelp, 0, 0, 1, doproxy }, - { "sendport", porthelp, 0, 0, 0, setport }, - { "put", sendhelp, 1, 1, 1, put }, - { "pwd", pwdhelp, 0, 1, 1, pwd }, - { "quit", quithelp, 0, 0, 0, quit }, - { "quote", quotehelp, 1, 1, 1, quote }, - { "recv", receivehelp, 1, 1, 1, get }, - { "reget", regethelp, 1, 1, 1, reget }, - { "rstatus", rmtstatushelp, 0, 1, 1, rmtstatus }, - { "rhelp", remotehelp, 0, 1, 1, rmthelp }, - { "rename", renamehelp, 0, 1, 1, renamefile }, - { "reset", resethelp, 0, 1, 1, reset }, - { "restart", restarthelp, 1, 1, 1, restart }, - { "rmdir", rmdirhelp, 0, 1, 1, removedir }, - { "runique", runiquehelp, 0, 0, 1, setrunique }, - { "send", sendhelp, 1, 1, 1, put }, - { "site", sitehelp, 0, 1, 1, site }, - { "size", sizecmdhelp, 1, 1, 1, sizecmd }, - { "status", statushelp, 0, 0, 1, status }, - { "struct", structhelp, 0, 1, 1, setstruct }, - { "system", systemhelp, 0, 1, 1, syst }, - { "sunique", suniquehelp, 0, 0, 1, setsunique }, - { "tenex", tenexhelp, 0, 1, 1, settenex }, - { "trace", tracehelp, 0, 0, 0, settrace }, - { "type", typehelp, 0, 1, 1, settype }, - { "user", userhelp, 0, 1, 1, user }, - { "umask", umaskhelp, 0, 1, 1, do_umask }, - { "verbose", verbosehelp, 0, 0, 0, setverbose }, - { "?", helphelp, 0, 0, 1, help }, - { 0 }, -}; - -int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1; diff --git a/ftp.tproj/domacro.c b/ftp.tproj/domacro.c deleted file mode 100644 index 19f0539..0000000 --- a/ftp.tproj/domacro.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1993, 1994 - * 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. - */ - - -#include -#include -#include -#include - -#include "ftp_var.h" - -void -domacro(argc, argv) - int argc; - char *argv[]; -{ - int i, j, count = 2, loopflg = 0; - char *cp1, *cp2, line2[200]; - struct cmd *c; - - if (argc < 2 && !another(&argc, &argv, "macro name")) { - printf("Usage: %s macro_name.\n", argv[0]); - code = -1; - return; - } - for (i = 0; i < macnum; ++i) { - if (!strncmp(argv[1], macros[i].mac_name, 9)) { - break; - } - } - if (i == macnum) { - printf("'%s' macro not found.\n", argv[1]); - code = -1; - return; - } - (void) strcpy(line2, line); -TOP: - cp1 = macros[i].mac_start; - while (cp1 != macros[i].mac_end) { - while (isspace(*cp1)) { - cp1++; - } - cp2 = line; - while (*cp1 != '\0') { - switch(*cp1) { - case '\\': - *cp2++ = *++cp1; - break; - case '$': - if (isdigit(*(cp1+1))) { - j = 0; - while (isdigit(*++cp1)) { - j = 10*j + *cp1 - '0'; - } - cp1--; - if (argc - 2 >= j) { - (void) strcpy(cp2, argv[j+1]); - cp2 += strlen(argv[j+1]); - } - break; - } - if (*(cp1+1) == 'i') { - loopflg = 1; - cp1++; - if (count < argc) { - (void) strcpy(cp2, argv[count]); - cp2 += strlen(argv[count]); - } - break; - } - /* intentional drop through */ - default: - *cp2++ = *cp1; - break; - } - if (*cp1 != '\0') { - cp1++; - } - } - *cp2 = '\0'; - makeargv(); - c = getcmd(margv[0]); - if (c == (struct cmd *)-1) { - printf("?Ambiguous command\n"); - code = -1; - } - else if (c == 0) { - printf("?Invalid command\n"); - code = -1; - } - else if (c->c_conn && !connected) { - printf("Not connected.\n"); - code = -1; - } - else { - if (verbose) { - printf("%s\n",line); - } - (*c->c_handler)(margc, margv); - if (bell && c->c_bell) { - (void) putchar('\007'); - } - (void) strcpy(line, line2); - makeargv(); - argc = margc; - argv = margv; - } - if (cp1 != macros[i].mac_end) { - cp1++; - } - } - if (loopflg && ++count < argc) { - goto TOP; - } -} diff --git a/ftp.tproj/extern.h b/ftp.tproj/extern.h deleted file mode 100644 index e23f324..0000000 --- a/ftp.tproj/extern.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 1994 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. - * - * @(#)extern.h 8.3 (Berkeley) 10/9/94 - */ - -struct timeval; -struct fd_set; - -void abort_remote __P((FILE *)); -void abortpt __P(()); -void abortrecv __P(()); -void abortsend __P(()); -void account __P((int, char **)); -int another __P((int *, char ***, char *)); -void blkfree __P((char **)); -void cd __P((int, char **)); -void cdup __P((int, char **)); -void changetype __P((int, int)); -void cmdabort __P(()); -void cmdscanner __P((int)); -int command __P((const char *, ...)); -int confirm __P((char *, char *)); -FILE *dataconn __P((char *)); -void delete __P((int, char **)); -void disconnect __P((int, char **)); -void do_chmod __P((int, char **)); -void do_umask __P((int, char **)); -void domacro __P((int, char **)); -char *domap __P((char *)); -void doproxy __P((int, char **)); -char *dotrans __P((char *)); -int empty __P((struct fd_set *, int)); -void fatal __P((char *)); -void get __P((int, char **)); -struct cmd *getcmd __P((char *)); -int getit __P((int, char **, int, char *)); -int getreply __P((int)); -int globulize __P((char **)); -char *gunique __P((char *)); -void help __P((int, char **)); -char *hookup __P((char *, int)); -void idle __P((int, char **)); -int initconn __P((void)); -void intr __P(()); -void lcd __P((int, char **)); -int login __P((char *)); -void lostpeer __P(()); -void ls __P((int, char **)); -void mabort __P((int)); -void macdef __P((int, char **)); -void makeargv __P((void)); -void makedir __P((int, char **)); -void mdelete __P((int, char **)); -void mget __P((int, char **)); -void mls __P((int, char **)); -void modtime __P((int, char **)); -void mput __P((int, char **)); -char *onoff __P((int)); -void newer __P((int, char **)); -void proxabort __P(()); -void proxtrans __P((char *, char *, char *)); -void psabort __P(()); -void pswitch __P((int)); -void ptransfer __P((char *, long, struct timeval *, struct timeval *)); -void put __P((int, char **)); -void pwd __P((int, char **)); -void quit __P((int, char **)); -void quote __P((int, char **)); -void quote1 __P((char *, int, char **)); -void recvrequest __P((char *, char *, char *, char *, int)); -void reget __P((int, char **)); -char *remglob __P((char **, int)); -void removedir __P((int, char **)); -void renamefile __P((int, char **)); -void reset __P((int, char **)); -void restart __P((int, char **)); -void rmthelp __P((int, char **)); -void rmtstatus __P((int, char **)); -int ruserpass __P((char *, char **, char **, char **)); -void sendrequest __P((char *, char *, char *, int)); -void setascii __P((int, char **)); -void setbell __P((int, char **)); -void setbinary __P((int, char **)); -void setcase __P((int, char **)); -void setcr __P((int, char **)); -void setdebug __P((int, char **)); -void setform __P((int, char **)); -void setftmode __P((int, char **)); -void setglob __P((int, char **)); -void sethash __P((int, char **)); -void setnmap __P((int, char **)); -void setntrans __P((int, char **)); -void setpassive __P((int, char **)); -void setpeer __P((int, char **)); -void setport __P((int, char **)); -void setprompt __P((int, char **)); -void setrunique __P((int, char **)); -void setstruct __P((int, char **)); -void setsunique __P((int, char **)); -void settenex __P((int, char **)); -void settrace __P((int, char **)); -void settype __P((int, char **)); -void setverbose __P((int, char **)); -void shell __P((int, char **)); -void site __P((int, char **)); -void sizecmd __P((int, char **)); -char *slurpstring __P((void)); -void status __P((int, char **)); -void syst __P((int, char **)); -void tvsub __P((struct timeval *, struct timeval *, struct timeval *)); -void user __P((int, char **)); - -extern jmp_buf abortprox; -extern int abrtflag; -extern struct cmd cmdtab[]; -extern FILE *cout; -extern int data; -extern char *home; -extern jmp_buf jabort; -extern int proxy; -extern char reply_string[]; -extern off_t restart_point; -extern int NCMDS; diff --git a/ftp.tproj/ftp.1 b/ftp.tproj/ftp.1 deleted file mode 100644 index 79dcbae..0000000 --- a/ftp.tproj/ftp.1 +++ /dev/null @@ -1,1157 +0,0 @@ -.\" Copyright (c) 1985, 1989, 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. -.\" -.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94 -.\" -.Dd October 9, 1994 -.Dt FTP 1 -.Os BSD 4.2 -.Sh NAME -.Nm ftp -.Nd -.Tn ARPANET -file transfer program -.Sh SYNOPSIS -.Nm ftp -.Op Fl v -.Op Fl d -.Op Fl i -.Op Fl n -.Op Fl g -.Op Ar host -.Sh DESCRIPTION -.Nm Ftp -is the user interface to the -.Tn ARPANET -standard File Transfer Protocol. -The program allows a user to transfer files to and from a -remote network site. -.Pp -Options may be specified at the command line, or to the -command interpreter. -.Bl -tag -width flag -.It Fl v -Verbose option forces -.Nm ftp -to show all responses from the remote server, as well -as report on data transfer statistics. -.It Fl n -Restrains -.Nm ftp -from attempting \*(Lqauto-login\*(Rq upon initial connection. -If auto-login is enabled, -.Nm ftp -will check the -.Pa .netrc -(see below) file in the user's home directory for an entry describing -an account on the remote machine. -If no entry exists, -.Nm ftp -will prompt for the remote machine login name (default is the user -identity on the local machine), and, if necessary, prompt for a password -and an account with which to login. -.It Fl i -Turns off interactive prompting during -multiple file transfers. -.It Fl d -Enables debugging. -.It Fl g -Disables file name globbing. -.El -.Pp -The client host with which -.Nm ftp -is to communicate may be specified on the command line. -If this is done, -.Nm ftp -will immediately attempt to establish a connection to an -.Tn FTP -server on that host; otherwise, -.Nm ftp -will enter its command interpreter and await instructions -from the user. -When -.Nm ftp -is awaiting commands from the user the prompt -.Ql ftp> -is provided to the user. -The following commands are recognized -by -.Nm ftp : -.Bl -tag -width Fl -.It Ic \&! Op Ar command Op Ar args -Invoke an interactive shell on the local machine. -If there are arguments, the first is taken to be a command to execute -directly, with the rest of the arguments as its arguments. -.It Ic \&$ Ar macro-name Op Ar args -Execute the macro -.Ar macro-name -that was defined with the -.Ic macdef -command. -Arguments are passed to the macro unglobbed. -.It Ic account Op Ar passwd -Supply a supplemental password required by a remote system for access -to resources once a login has been successfully completed. -If no argument is included, the user will be prompted for an account -password in a non-echoing input mode. -.It Ic append Ar local-file Op Ar remote-file -Append a local file to a file on the remote machine. -If -.Ar remote-file -is left unspecified, the local file name is used in naming the -remote file after being altered by any -.Ic ntrans -or -.Ic nmap -setting. -File transfer uses the current settings for -.Ic type , -.Ic format , -.Ic mode , -and -.Ic structure . -.It Ic ascii -Set the file transfer -.Ic type -to network -.Tn ASCII . -This is the default type. -.It Ic bell -Arrange that a bell be sounded after each file transfer -command is completed. -.It Ic binary -Set the file transfer -.Ic type -to support binary image transfer. -.It Ic bye -Terminate the -.Tn FTP -session with the remote server -and exit -.Nm ftp . -An end of file will also terminate the session and exit. -.It Ic case -Toggle remote computer file name case mapping during -.Ic mget -commands. -When -.Ic case -is on (default is off), remote computer file names with all letters in -upper case are written in the local directory with the letters mapped -to lower case. -.It Ic \&cd Ar remote-directory -Change the working directory on the remote machine -to -.Ar remote-directory . -.It Ic cdup -Change the remote machine working directory to the parent of the -current remote machine working directory. -.It Ic chmod Ar mode file-name -Change the permission modes of the file -.Ar file-name -on the remote -sytem to -.Ar mode . -.It Ic close -Terminate the -.Tn FTP -session with the remote server, and -return to the command interpreter. -Any defined macros are erased. -.It Ic \&cr -Toggle carriage return stripping during -ascii type file retrieval. -Records are denoted by a carriage return/linefeed sequence -during ascii type file transfer. -When -.Ic \&cr -is on (the default), carriage returns are stripped from this -sequence to conform with the -.Ux -single linefeed record -delimiter. -Records on -.Pf non\- Ns Ux -remote systems may contain single linefeeds; -when an ascii type transfer is made, these linefeeds may be -distinguished from a record delimiter only when -.Ic \&cr -is off. -.It Ic delete Ar remote-file -Delete the file -.Ar remote-file -on the remote machine. -.It Ic debug Op Ar debug-value -Toggle debugging mode. -If an optional -.Ar debug-value -is specified it is used to set the debugging level. -When debugging is on, -.Nm ftp -prints each command sent to the remote machine, preceded -by the string -.Ql \-\-> -.It Xo -.Ic dir -.Op Ar remote-directory -.Op Ar local-file -.Xc -Print a listing of the directory contents in the -directory, -.Ar remote-directory , -and, optionally, placing the output in -.Ar local-file . -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic dir -output. -If no directory is specified, the current working -directory on the remote machine is used. -If no local -file is specified, or -.Ar local-file -is -.Fl , -output comes to the terminal. -.It Ic disconnect -A synonym for -.Ar close . -.It Ic form Ar format -Set the file transfer -.Ic form -to -.Ar format . -The default format is \*(Lqfile\*(Rq. -.It Ic get Ar remote-file Op Ar local-file -Retrieve the -.Ar remote-file -and store it on the local machine. -If the local -file name is not specified, it is given the same -name it has on the remote machine, subject to -alteration by the current -.Ic case , -.Ic ntrans , -and -.Ic nmap -settings. -The current settings for -.Ic type , -.Ic form , -.Ic mode , -and -.Ic structure -are used while transferring the file. -.It Ic glob -Toggle filename expansion for -.Ic mdelete , -.Ic mget -and -.Ic mput . -If globbing is turned off with -.Ic glob , -the file name arguments -are taken literally and not expanded. -Globbing for -.Ic mput -is done as in -.Xr csh 1 . -For -.Ic mdelete -and -.Ic mget , -each remote file name is expanded -separately on the remote machine and the lists are not merged. -Expansion of a directory name is likely to be -different from expansion of the name of an ordinary file: -the exact result depends on the foreign operating system and ftp server, -and can be previewed by doing -.Ql mls remote-files \- -Note: -.Ic mget -and -.Ic mput -are not meant to transfer -entire directory subtrees of files. -That can be done by -transferring a -.Xr tar 1 -archive of the subtree (in binary mode). -.It Ic hash -Toggle hash-sign (``#'') printing for each data block -transferred. -The size of a data block is 1024 bytes. -.It Ic help Op Ar command -Print an informative message about the meaning of -.Ar command . -If no argument is given, -.Nm ftp -prints a list of the known commands. -.It Ic idle Op Ar seconds -Set the inactivity timer on the remote server to -.Ar seconds -seconds. -If -.Ar seconds -is omitted, the current inactivity timer is printed. -.It Ic lcd Op Ar directory -Change the working directory on the local machine. -If -no -.Ar directory -is specified, the user's home directory is used. -.It Xo -.Ic \&ls -.Op Ar remote-directory -.Op Ar local-file -.Xc -Print a listing of the contents of a -directory on the remote machine. -The listing includes any system-dependent information that the server -chooses to include; for example, most -.Ux -systems will produce -output from the command -.Ql ls \-l . -(See also -.Ic nlist . ) -If -.Ar remote-directory -is left unspecified, the current working directory is used. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic \&ls -output. -If no local file is specified, or if -.Ar local-file -is -.Sq Fl , -the output is sent to the terminal. -.It Ic macdef Ar macro-name -Define a macro. -Subsequent lines are stored as the macro -.Ar macro-name ; -a null line (consecutive newline characters -in a file or -carriage returns from the terminal) terminates macro input mode. -There is a limit of 16 macros and 4096 total characters in all -defined macros. -Macros remain defined until a -.Ic close -command is executed. -The macro processor interprets `$' and `\e' as special characters. -A `$' followed by a number (or numbers) is replaced by the -corresponding argument on the macro invocation command line. -A `$' followed by an `i' signals that macro processor that the -executing macro is to be looped. -On the first pass `$i' is -replaced by the first argument on the macro invocation command line, -on the second pass it is replaced by the second argument, and so on. -A `\e' followed by any character is replaced by that character. -Use the `\e' to prevent special treatment of the `$'. -.It Ic mdelete Op Ar remote-files -Delete the -.Ar remote-files -on the remote machine. -.It Ic mdir Ar remote-files local-file -Like -.Ic dir , -except multiple remote files may be specified. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic mdir -output. -.It Ic mget Ar remote-files -Expand the -.Ar remote-files -on the remote machine -and do a -.Ic get -for each file name thus produced. -See -.Ic glob -for details on the filename expansion. -Resulting file names will then be processed according to -.Ic case , -.Ic ntrans , -and -.Ic nmap -settings. -Files are transferred into the local working directory, -which can be changed with -.Ql lcd directory ; -new local directories can be created with -.Ql "\&! mkdir directory" . -.It Ic mkdir Ar directory-name -Make a directory on the remote machine. -.It Ic mls Ar remote-files local-file -Like -.Ic nlist , -except multiple remote files may be specified, -and the -.Ar local-file -must be specified. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic mls -output. -.It Ic mode Op Ar mode-name -Set the file transfer -.Ic mode -to -.Ar mode-name . -The default mode is \*(Lqstream\*(Rq mode. -.It Ic modtime Ar file-name -Show the last modification time of the file on the remote machine. -.It Ic mput Ar local-files -Expand wild cards in the list of local files given as arguments -and do a -.Ic put -for each file in the resulting list. -See -.Ic glob -for details of filename expansion. -Resulting file names will then be processed according to -.Ic ntrans -and -.Ic nmap -settings. -.It Ic newer Ar file-name -Get the file only if the modification time of the remote file is more -recent that the file on the current system. -If the file does not -exist on the current system, the remote file is considered -.Ic newer . -Otherwise, this command is identical to -.Ar get . -.It Xo -.Ic nlist -.Op Ar remote-directory -.Op Ar local-file -.Xc -Print a list of the files in a -directory on the remote machine. -If -.Ar remote-directory -is left unspecified, the current working directory is used. -If interactive prompting is on, -.Nm ftp -will prompt the user to verify that the last argument is indeed the -target local file for receiving -.Ic nlist -output. -If no local file is specified, or if -.Ar local-file -is -.Fl , -the output is sent to the terminal. -.It Ic nmap Op Ar inpattern outpattern -Set or unset the filename mapping mechanism. -If no arguments are specified, the filename mapping mechanism is unset. -If arguments are specified, remote filenames are mapped during -.Ic mput -commands and -.Ic put -commands issued without a specified remote target filename. -If arguments are specified, local filenames are mapped during -.Ic mget -commands and -.Ic get -commands issued without a specified local target filename. -This command is useful when connecting to a -.No non\- Ns Ux -remote computer -with different file naming conventions or practices. -The mapping follows the pattern set by -.Ar inpattern -and -.Ar outpattern . -.Op Ar Inpattern -is a template for incoming filenames (which may have already been -processed according to the -.Ic ntrans -and -.Ic case -settings). -Variable templating is accomplished by including the -sequences `$1', `$2', ..., `$9' in -.Ar inpattern . -Use `\\' to prevent this special treatment of the `$' character. -All other characters are treated literally, and are used to determine the -.Ic nmap -.Op Ar inpattern -variable values. -For example, given -.Ar inpattern -$1.$2 and the remote file name "mydata.data", $1 would have the value -"mydata", and $2 would have the value "data". -The -.Ar outpattern -determines the resulting mapped filename. -The sequences `$1', `$2', ...., `$9' are replaced by any value resulting -from the -.Ar inpattern -template. -The sequence `$0' is replace by the original filename. -Additionally, the sequence -.Ql Op Ar seq1 , Ar seq2 -is replaced by -.Op Ar seq1 -if -.Ar seq1 -is not a null string; otherwise it is replaced by -.Ar seq2 . -For example, the command -.Pp -.Bd -literal -offset indent -compact -nmap $1.$2.$3 [$1,$2].[$2,file] -.Ed -.Pp -would yield -the output filename "myfile.data" for input filenames "myfile.data" and -"myfile.data.old", "myfile.file" for the input filename "myfile", and -"myfile.myfile" for the input filename ".myfile". -Spaces may be included in -.Ar outpattern , -as in the example: `nmap $1 sed "s/ *$//" > $1' . -Use the `\e' character to prevent special treatment -of the `$','[','[', and `,' characters. -.It Ic ntrans Op Ar inchars Op Ar outchars -Set or unset the filename character translation mechanism. -If no arguments are specified, the filename character -translation mechanism is unset. -If arguments are specified, characters in -remote filenames are translated during -.Ic mput -commands and -.Ic put -commands issued without a specified remote target filename. -If arguments are specified, characters in -local filenames are translated during -.Ic mget -commands and -.Ic get -commands issued without a specified local target filename. -This command is useful when connecting to a -.No non\- Ns Ux -remote computer -with different file naming conventions or practices. -Characters in a filename matching a character in -.Ar inchars -are replaced with the corresponding character in -.Ar outchars . -If the character's position in -.Ar inchars -is longer than the length of -.Ar outchars , -the character is deleted from the file name. -.It Ic open Ar host Op Ar port -Establish a connection to the specified -.Ar host -.Tn FTP -server. -An optional port number may be supplied, -in which case, -.Nm ftp -will attempt to contact an -.Tn FTP -server at that port. -If the -.Ic auto-login -option is on (default), -.Nm ftp -will also attempt to automatically log the user in to -the -.Tn FTP -server (see below). -.It Ic passive -Toggle passive mode. If passive mode is turned on -(default is off), the ftp client will -send a -.Dv PASV -command for all data connections instead of the usual -.Dv PORT -command. The -.Dv PASV -command requests that the remote server open a port for the data connection -and return the address of that port. The remote server listens on that -port and the client connects to it. When using the more traditional -.Dv PORT -command, the client listens on a port and sends that address to the remote -server, who connects back to it. Passive mode is useful when using -.Nm ftp -through a gateway router or host that controls the directionality of -traffic. -(Note that though ftp servers are required to support the -.Dv PASV -command by RFC 1123, some do not.) -.It Ic prompt -Toggle interactive prompting. -Interactive prompting -occurs during multiple file transfers to allow the -user to selectively retrieve or store files. -If prompting is turned off (default is on), any -.Ic mget -or -.Ic mput -will transfer all files, and any -.Ic mdelete -will delete all files. -.It Ic proxy Ar ftp-command -Execute an ftp command on a secondary control connection. -This command allows simultaneous connection to two remote ftp -servers for transferring files between the two servers. -The first -.Ic proxy -command should be an -.Ic open , -to establish the secondary control connection. -Enter the command "proxy ?" to see other ftp commands executable on the -secondary connection. -The following commands behave differently when prefaced by -.Ic proxy : -.Ic open -will not define new macros during the auto-login process, -.Ic close -will not erase existing macro definitions, -.Ic get -and -.Ic mget -transfer files from the host on the primary control connection -to the host on the secondary control connection, and -.Ic put , -.Ic mput , -and -.Ic append -transfer files from the host on the secondary control connection -to the host on the primary control connection. -Third party file transfers depend upon support of the ftp protocol -.Dv PASV -command by the server on the secondary control connection. -.It Ic put Ar local-file Op Ar remote-file -Store a local file on the remote machine. -If -.Ar remote-file -is left unspecified, the local file name is used -after processing according to any -.Ic ntrans -or -.Ic nmap -settings -in naming the remote file. -File transfer uses the -current settings for -.Ic type , -.Ic format , -.Ic mode , -and -.Ic structure . -.It Ic pwd -Print the name of the current working directory on the remote -machine. -.It Ic quit -A synonym for -.Ic bye . -.It Ic quote Ar arg1 arg2 ... -The arguments specified are sent, verbatim, to the remote -.Tn FTP -server. -.It Ic recv Ar remote-file Op Ar local-file -A synonym for get. -.It Ic reget Ar remote-file Op Ar local-file -Reget acts like get, except that if -.Ar local-file -exists and is -smaller than -.Ar remote-file , -.Ar local-file -is presumed to be -a partially transferred copy of -.Ar remote-file -and the transfer -is continued from the apparent point of failure. -This command -is useful when transferring very large files over networks that -are prone to dropping connections. -.It Ic remotehelp Op Ar command-name -Request help from the remote -.Tn FTP -server. -If a -.Ar command-name -is specified it is supplied to the server as well. -.It Ic remotestatus Op Ar file-name -With no arguments, show status of remote machine. -If -.Ar file-name -is specified, show status of -.Ar file-name -on remote machine. -.It Xo -.Ic rename -.Op Ar from -.Op Ar to -.Xc -Rename the file -.Ar from -on the remote machine, to the file -.Ar to . -.It Ic reset -Clear reply queue. -This command re-synchronizes command/reply sequencing with the remote -ftp server. -Resynchronization may be necessary following a violation of the ftp protocol -by the remote server. -.It Ic restart Ar marker -Restart the immediately following -.Ic get -or -.Ic put -at the -indicated -.Ar marker . -On -.Ux -systems, marker is usually a byte -offset into the file. -.It Ic rmdir Ar directory-name -Delete a directory on the remote machine. -.It Ic runique -Toggle storing of files on the local system with unique filenames. -If a file already exists with a name equal to the target -local filename for a -.Ic get -or -.Ic mget -command, a ".1" is appended to the name. -If the resulting name matches another existing file, -a ".2" is appended to the original name. -If this process continues up to ".99", an error -message is printed, and the transfer does not take place. -The generated unique filename will be reported. -Note that -.Ic runique -will not affect local files generated from a shell command -(see below). -The default value is off. -.It Ic send Ar local-file Op Ar remote-file -A synonym for put. -.It Ic sendport -Toggle the use of -.Dv PORT -commands. -By default, -.Nm ftp -will attempt to use a -.Dv PORT -command when establishing -a connection for each data transfer. -The use of -.Dv PORT -commands can prevent delays -when performing multiple file transfers. -If the -.Dv PORT -command fails, -.Nm ftp -will use the default data port. -When the use of -.Dv PORT -commands is disabled, no attempt will be made to use -.Dv PORT -commands for each data transfer. -This is useful -for certain -.Tn FTP -implementations which do ignore -.Dv PORT -commands but, incorrectly, indicate they've been accepted. -.It Ic site Ar arg1 arg2 ... -The arguments specified are sent, verbatim, to the remote -.Tn FTP -server as a -.Dv SITE -command. -.It Ic size Ar file-name -Return size of -.Ar file-name -on remote machine. -.It Ic status -Show the current status of -.Nm ftp . -.It Ic struct Op Ar struct-name -Set the file transfer -.Ar structure -to -.Ar struct-name . -By default \*(Lqstream\*(Rq structure is used. -.It Ic sunique -Toggle storing of files on remote machine under unique file names. -Remote ftp server must support ftp protocol -.Dv STOU -command for -successful completion. -The remote server will report unique name. -Default value is off. -.It Ic system -Show the type of operating system running on the remote machine. -.It Ic tenex -Set the file transfer type to that needed to -talk to -.Tn TENEX -machines. -.It Ic trace -Toggle packet tracing. -.It Ic type Op Ar type-name -Set the file transfer -.Ic type -to -.Ar type-name . -If no type is specified, the current type -is printed. -The default type is network -.Tn ASCII . -.It Ic umask Op Ar newmask -Set the default umask on the remote server to -.Ar newmask . -If -.Ar newmask -is omitted, the current umask is printed. -.It Xo -.Ic user Ar user-name -.Op Ar password -.Op Ar account -.Xc -Identify yourself to the remote -.Tn FTP -server. -If the -.Ar password -is not specified and the server requires it, -.Nm ftp -will prompt the user for it (after disabling local echo). -If an -.Ar account -field is not specified, and the -.Tn FTP -server -requires it, the user will be prompted for it. -If an -.Ar account -field is specified, an account command will -be relayed to the remote server after the login sequence -is completed if the remote server did not require it -for logging in. -Unless -.Nm ftp -is invoked with \*(Lqauto-login\*(Rq disabled, this -process is done automatically on initial connection to -the -.Tn FTP -server. -.It Ic verbose -Toggle verbose mode. -In verbose mode, all responses from -the -.Tn FTP -server are displayed to the user. -In addition, -if verbose is on, when a file transfer completes, statistics -regarding the efficiency of the transfer are reported. -By default, -verbose is on. -.It Ic ? Op Ar command -A synonym for help. -.El -.Pp -Command arguments which have embedded spaces may be quoted with -quote `"' marks. -.Sh ABORTING A FILE TRANSFER -To abort a file transfer, use the terminal interrupt key -(usually Ctrl-C). -Sending transfers will be immediately halted. -Receiving transfers will be halted by sending a ftp protocol -.Dv ABOR -command to the remote server, and discarding any further data received. -The speed at which this is accomplished depends upon the remote -server's support for -.Dv ABOR -processing. -If the remote server does not support the -.Dv ABOR -command, an -.Ql ftp> -prompt will not appear until the remote server has completed -sending the requested file. -.Pp -The terminal interrupt key sequence will be ignored when -.Nm ftp -has completed any local processing and is awaiting a reply -from the remote server. -A long delay in this mode may result from the ABOR processing described -above, or from unexpected behavior by the remote server, including -violations of the ftp protocol. -If the delay results from unexpected remote server behavior, the local -.Nm ftp -program must be killed by hand. -.Sh FILE NAMING CONVENTIONS -Files specified as arguments to -.Nm ftp -commands are processed according to the following rules. -.Bl -enum -.It -If the file name -.Sq Fl -is specified, the -.Ar stdin -(for reading) or -.Ar stdout -(for writing) is used. -.It -If the first character of the file name is -.Sq \&| , -the -remainder of the argument is interpreted as a shell command. -.Nm Ftp -then forks a shell, using -.Xr popen 3 -with the argument supplied, and reads (writes) from the stdout -(stdin). -If the shell command includes spaces, the argument -must be quoted; e.g. -\*(Lq" ls -lt"\*(Rq. -A particularly -useful example of this mechanism is: \*(Lqdir more\*(Rq. -.It -Failing the above checks, if ``globbing'' is enabled, -local file names are expanded -according to the rules used in the -.Xr csh 1 ; -c.f. the -.Ic glob -command. -If the -.Nm ftp -command expects a single local file (.e.g. -.Ic put ) , -only the first filename generated by the "globbing" operation is used. -.It -For -.Ic mget -commands and -.Ic get -commands with unspecified local file names, the local filename is -the remote filename, which may be altered by a -.Ic case , -.Ic ntrans , -or -.Ic nmap -setting. -The resulting filename may then be altered if -.Ic runique -is on. -.It -For -.Ic mput -commands and -.Ic put -commands with unspecified remote file names, the remote filename is -the local filename, which may be altered by a -.Ic ntrans -or -.Ic nmap -setting. -The resulting filename may then be altered by the remote server if -.Ic sunique -is on. -.El -.Sh FILE TRANSFER PARAMETERS -The FTP specification specifies many parameters which may -affect a file transfer. -The -.Ic type -may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary), -\*(Lqebcdic\*(Rq, and \*(Lqlocal byte size\*(Rq (for -.Tn PDP Ns -10's -and -.Tn PDP Ns -20's -mostly). -.Nm Ftp -supports the ascii and image types of file transfer, -plus local byte size 8 for -.Ic tenex -mode transfers. -.Pp -.Nm Ftp -supports only the default values for the remaining -file transfer parameters: -.Ic mode , -.Ic form , -and -.Ic struct . -.Sh THE .netrc FILE -The -.Pa .netrc -file contains login and initialization information -used by the auto-login process. -It resides in the user's home directory. -The following tokens are recognized; they may be separated by spaces, -tabs, or new-lines: -.Bl -tag -width password -.It Ic machine Ar name -Identify a remote machine -.Ar name . -The auto-login process searches the -.Pa .netrc -file for a -.Ic machine -token that matches the remote machine specified on the -.Nm ftp -command line or as an -.Ic open -command argument. -Once a match is made, the subsequent -.Pa .netrc -tokens are processed, -stopping when the end of file is reached or another -.Ic machine -or a -.Ic default -token is encountered. -.It Ic default -This is the same as -.Ic machine -.Ar name -except that -.Ic default -matches any name. -There can be only one -.Ic default -token, and it must be after all -.Ic machine -tokens. -This is normally used as: -.Pp -.Dl default login anonymous password user@site -.Pp -thereby giving the user -.Ar automatic -anonymous ftp login to -machines not specified in -.Pa .netrc . -This can be overridden -by using the -.Fl n -flag to disable auto-login. -.It Ic login Ar name -Identify a user on the remote machine. -If this token is present, the auto-login process will initiate -a login using the specified -.Ar name . -.It Ic password Ar string -Supply a password. -If this token is present, the auto-login process will supply the -specified string if the remote server requires a password as part -of the login process. -Note that if this token is present in the -.Pa .netrc -file for any user other -than -.Ar anonymous , -.Nm ftp -will abort the auto-login process if the -.Pa .netrc -is readable by -anyone besides the user. -.It Ic account Ar string -Supply an additional account password. -If this token is present, the auto-login process will supply the -specified string if the remote server requires an additional -account password, or the auto-login process will initiate an -.Dv ACCT -command if it does not. -.It Ic macdef Ar name -Define a macro. -This token functions like the -.Nm ftp -.Ic macdef -command functions. -A macro is defined with the specified name; its contents begin with the -next -.Pa .netrc -line and continue until a null line (consecutive new-line -characters) is encountered. -If a macro named -.Ic init -is defined, it is automatically executed as the last step in the -auto-login process. -.El -.Sh ENVIRONMENT -.Nm Ftp -utilizes the following environment variables. -.Bl -tag -width Fl -.It Ev HOME -For default location of a -.Pa .netrc -file, if one exists. -.It Ev SHELL -For default shell. -.El -.Sh SEE ALSO -.Xr ftpd 8 -.Sh HISTORY -The -.Nm ftp -command appeared in -.Bx 4.2 . -.Sh BUGS -Correct execution of many commands depends upon proper behavior -by the remote server. -.Pp -An error in the treatment of carriage returns -in the -.Bx 4.2 -ascii-mode transfer code -has been corrected. -This correction may result in incorrect transfers of binary files -to and from -.Bx 4.2 -servers using the ascii type. -Avoid this problem by using the binary image type. diff --git a/ftp.tproj/ftp.c b/ftp.tproj/ftp.c deleted file mode 100644 index a2a54a9..0000000 --- a/ftp.tproj/ftp.c +++ /dev/null @@ -1,1542 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * 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. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ftp_var.h" - -extern int h_errno; - -struct sockaddr_in hisctladdr; -struct sockaddr_in data_addr; -int data = -1; -int abrtflag = 0; -jmp_buf ptabort; -int ptabflg; -int ptflag = 0; -struct sockaddr_in myctladdr; -off_t restart_point = 0; - -FILE *cin, *cout; - -char * -hookup(host, port) - char *host; - int port; -{ - struct hostent *hp = 0; - int s, len, tos; - static char hostnamebuf[80]; - - memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); - hisctladdr.sin_addr.s_addr = inet_addr(host); - if (hisctladdr.sin_addr.s_addr != -1) { - hisctladdr.sin_family = AF_INET; - (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf)); - } else { - hp = gethostbyname(host); - if (hp == NULL) { - warnx("%s: %s", host, hstrerror(h_errno)); - code = -1; - return ((char *) 0); - } - hisctladdr.sin_family = hp->h_addrtype; - memmove((caddr_t)&hisctladdr.sin_addr, - hp->h_addr_list[0], hp->h_length); - (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); - } - hostname = hostnamebuf; - s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); - if (s < 0) { - warn("socket"); - code = -1; - return (0); - } - hisctladdr.sin_port = port; - while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { - if (hp && hp->h_addr_list[1]) { - int oerrno = errno; - char *ia; - - ia = inet_ntoa(hisctladdr.sin_addr); - errno = oerrno; - warn("connect to address %s", ia); - hp->h_addr_list++; - memmove((caddr_t)&hisctladdr.sin_addr, - hp->h_addr_list[0], hp->h_length); - fprintf(stdout, "Trying %s...\n", - inet_ntoa(hisctladdr.sin_addr)); - (void) close(s); - s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); - if (s < 0) { - warn("socket"); - code = -1; - return (0); - } - continue; - } - warn("connect"); - code = -1; - goto bad; - } - len = sizeof (myctladdr); - if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { - warn("getsockname"); - code = -1; - goto bad; - } -#ifdef IP_TOS - tos = IPTOS_LOWDELAY; - if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) - warn("setsockopt TOS (ignored)"); -#endif - cin = fdopen(s, "r"); - cout = fdopen(s, "w"); - if (cin == NULL || cout == NULL) { - warnx("fdopen failed."); - if (cin) - (void) fclose(cin); - if (cout) - (void) fclose(cout); - code = -1; - goto bad; - } - if (verbose) - printf("Connected to %s.\n", hostname); - if (getreply(0) > 2) { /* read startup message from server */ - if (cin) - (void) fclose(cin); - if (cout) - (void) fclose(cout); - code = -1; - goto bad; - } -#ifdef SO_OOBINLINE - { - int on = 1; - - if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) - < 0 && debug) { - warn("setsockopt"); - } - } -#endif /* SO_OOBINLINE */ - - return (hostname); -bad: - (void) close(s); - return ((char *)0); -} - -int -login(host) - char *host; -{ - char tmp[80]; - char *user, *pass, *acct; - int n, aflag = 0; - - user = pass = acct = 0; - if (ruserpass(host, &user, &pass, &acct) < 0) { - code = -1; - return (0); - } - while (user == NULL) { - char *myname = getlogin(); - - if (myname == NULL) { - struct passwd *pp = getpwuid(getuid()); - - if (pp != NULL) - myname = pp->pw_name; - } - if (myname) - printf("Name (%s:%s): ", host, myname); - else - printf("Name (%s): ", host); - (void) fgets(tmp, sizeof(tmp) - 1, stdin); - tmp[strlen(tmp) - 1] = '\0'; - if (*tmp == '\0') - user = myname; - else - user = tmp; - } - n = command("USER %s", user); - if (n == CONTINUE) { - if (pass == NULL) - pass = getpass("Password:"); - n = command("PASS %s", pass); - } - if (n == CONTINUE) { - aflag++; - acct = getpass("Account:"); - n = command("ACCT %s", acct); - } - if (n != COMPLETE) { - warnx("Login failed."); - return (0); - } - if (!aflag && acct != NULL) - (void) command("ACCT %s", acct); - if (proxy) - return (1); - for (n = 0; n < macnum; ++n) { - if (!strcmp("init", macros[n].mac_name)) { - (void) strcpy(line, "$init"); - makeargv(); - domacro(margc, margv); - break; - } - } - return (1); -} - -void -cmdabort() -{ - - printf("\n"); - (void) fflush(stdout); - abrtflag++; - if (ptflag) - longjmp(ptabort,1); -} - -int command(const char *fmt, ...) -{ - va_list ap; - int r; - sig_t oldintr; - - abrtflag = 0; - if (debug) { - printf("---> "); - va_start(ap, fmt); - if (strncmp("PASS ", fmt, 5) == 0) - printf("PASS XXXX"); - else - vfprintf(stdout, fmt, ap); - va_end(ap); - printf("\n"); - (void) fflush(stdout); - } - if (cout == NULL) { - warn("No control connection for command"); - code = -1; - return (0); - } - oldintr = signal(SIGINT, cmdabort); - va_start(ap, fmt); - vfprintf(cout, fmt, ap); - va_end(ap); - fprintf(cout, "\r\n"); - (void) fflush(cout); - cpend = 1; - r = getreply(!strcmp(fmt, "QUIT")); - if (abrtflag && oldintr != SIG_IGN) - (*oldintr)(SIGINT); - (void) signal(SIGINT, oldintr); - return (r); -} - -char reply_string[BUFSIZ]; /* last line of previous reply */ - -int -getreply(expecteof) - int expecteof; -{ - int c, n; - int dig; - int originalcode = 0, continuation = 0; - sig_t oldintr; - int pflag = 0; - char *cp, *pt = pasv; - - oldintr = signal(SIGINT, cmdabort); - for (;;) { - dig = n = code = 0; - cp = reply_string; - while ((c = getc(cin)) != '\n') { - if (c == IAC) { /* handle telnet commands */ - switch (c = getc(cin)) { - case WILL: - case WONT: - c = getc(cin); - fprintf(cout, "%c%c%c", IAC, DONT, c); - (void) fflush(cout); - break; - case DO: - case DONT: - c = getc(cin); - fprintf(cout, "%c%c%c", IAC, WONT, c); - (void) fflush(cout); - break; - default: - break; - } - continue; - } - dig++; - if (c == EOF) { - if (expecteof) { - (void) signal(SIGINT,oldintr); - code = 221; - return (0); - } - lostpeer(); - if (verbose) { - printf("421 Service not available, remote server has closed connection\n"); - (void) fflush(stdout); - } - code = 421; - return (4); - } - if (c != '\r' && (verbose > 0 || - (verbose > -1 && n == '5' && dig > 4))) { - if (proxflag && - (dig == 1 || dig == 5 && verbose == 0)) - printf("%s:",hostname); - (void) putchar(c); - } - if (dig < 4 && isdigit(c)) - code = code * 10 + (c - '0'); - if (!pflag && code == 227) - pflag = 1; - if (dig > 4 && pflag == 1 && isdigit(c)) - pflag = 2; - if (pflag == 2) { - if (c != '\r' && c != ')') - *pt++ = c; - else { - *pt = '\0'; - pflag = 3; - } - } - if (dig == 4 && c == '-') { - if (continuation) - code = 0; - continuation++; - } - if (n == 0) - n = c; - if (cp < &reply_string[sizeof(reply_string) - 1]) - *cp++ = c; - } - if (verbose > 0 || verbose > -1 && n == '5') { - (void) putchar(c); - (void) fflush (stdout); - } - if (continuation && code != originalcode) { - if (originalcode == 0) - originalcode = code; - continue; - } - *cp = '\0'; - if (n != '1') - cpend = 0; - (void) signal(SIGINT,oldintr); - if (code == 421 || originalcode == 421) - lostpeer(); - if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) - (*oldintr)(SIGINT); - return (n - '0'); - } -} - -int -empty(mask, sec) - struct fd_set *mask; - int sec; -{ - struct timeval t; - - t.tv_sec = (long) sec; - t.tv_usec = 0; - return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); -} - -jmp_buf sendabort; - -void -abortsend() -{ - - mflag = 0; - abrtflag = 0; - printf("\nsend aborted\nwaiting for remote to finish abort\n"); - (void) fflush(stdout); - longjmp(sendabort, 1); -} - -#define HASHBYTES 1024 - -void -sendrequest(cmd, local, remote, printnames) - char *cmd, *local, *remote; - int printnames; -{ - struct stat st; - struct timeval start, stop; - int c, d; - FILE *fin, *dout = 0, *popen(); - int (*closefunc) __P((FILE *)); - sig_t oldintr, oldintp; - long bytes = 0, hashbytes = HASHBYTES; - char *lmode, buf[BUFSIZ], *bufp; - - if (verbose && printnames) { - if (local && *local != '-') - printf("local: %s ", local); - if (remote) - printf("remote: %s\n", remote); - } - if (proxy) { - proxtrans(cmd, local, remote); - return; - } - if (curtype != type) - changetype(type, 0); - closefunc = NULL; - oldintr = NULL; - oldintp = NULL; - lmode = "w"; - if (setjmp(sendabort)) { - while (cpend) { - (void) getreply(0); - } - if (data >= 0) { - (void) close(data); - data = -1; - } - if (oldintr) - (void) signal(SIGINT,oldintr); - if (oldintp) - (void) signal(SIGPIPE,oldintp); - code = -1; - return; - } - oldintr = signal(SIGINT, abortsend); - if (strcmp(local, "-") == 0) - fin = stdin; - else if (*local == '|') { - oldintp = signal(SIGPIPE,SIG_IGN); - fin = popen(local + 1, "r"); - if (fin == NULL) { - warn("%s", local + 1); - (void) signal(SIGINT, oldintr); - (void) signal(SIGPIPE, oldintp); - code = -1; - return; - } - closefunc = pclose; - } else { - fin = fopen(local, "r"); - if (fin == NULL) { - warn("local: %s", local); - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - closefunc = fclose; - if (fstat(fileno(fin), &st) < 0 || - (st.st_mode&S_IFMT) != S_IFREG) { - fprintf(stdout, "%s: not a plain file.\n", local); - (void) signal(SIGINT, oldintr); - fclose(fin); - code = -1; - return; - } - } - if (initconn()) { - (void) signal(SIGINT, oldintr); - if (oldintp) - (void) signal(SIGPIPE, oldintp); - code = -1; - if (closefunc != NULL) - (*closefunc)(fin); - return; - } - if (setjmp(sendabort)) - goto abort; - - if (restart_point && - (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { - int rc; - - switch (curtype) { - case TYPE_A: - rc = fseek(fin, (long) restart_point, SEEK_SET); - break; - case TYPE_I: - case TYPE_L: - rc = lseek(fileno(fin), restart_point, SEEK_SET); - break; - } - if (rc < 0) { - warn("local: %s", local); - restart_point = 0; - if (closefunc != NULL) - (*closefunc)(fin); - return; - } - if (command("REST %ld", (long) restart_point) - != CONTINUE) { - restart_point = 0; - if (closefunc != NULL) - (*closefunc)(fin); - return; - } - restart_point = 0; - lmode = "r+w"; - } - if (remote) { - if (command("%s %s", cmd, remote) != PRELIM) { - (void) signal(SIGINT, oldintr); - if (oldintp) - (void) signal(SIGPIPE, oldintp); - if (closefunc != NULL) - (*closefunc)(fin); - return; - } - } else - if (command("%s", cmd) != PRELIM) { - (void) signal(SIGINT, oldintr); - if (oldintp) - (void) signal(SIGPIPE, oldintp); - if (closefunc != NULL) - (*closefunc)(fin); - return; - } - dout = dataconn(lmode); - if (dout == NULL) - goto abort; - (void) gettimeofday(&start, (struct timezone *)0); - oldintp = signal(SIGPIPE, SIG_IGN); - switch (curtype) { - - case TYPE_I: - case TYPE_L: - errno = d = 0; - while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { - bytes += c; - for (bufp = buf; c > 0; c -= d, bufp += d) - if ((d = write(fileno(dout), bufp, c)) <= 0) - break; - if (hash) { - while (bytes >= hashbytes) { - (void) putchar('#'); - hashbytes += HASHBYTES; - } - (void) fflush(stdout); - } - } - if (hash && bytes > 0) { - if (bytes < HASHBYTES) - (void) putchar('#'); - (void) putchar('\n'); - (void) fflush(stdout); - } - if (c < 0) - warn("local: %s", local); - if (d < 0) { - if (errno != EPIPE) - warn("netout"); - bytes = -1; - } - break; - - case TYPE_A: - while ((c = getc(fin)) != EOF) { - if (c == '\n') { - while (hash && (bytes >= hashbytes)) { - (void) putchar('#'); - (void) fflush(stdout); - hashbytes += HASHBYTES; - } - if (ferror(dout)) - break; - (void) putc('\r', dout); - bytes++; - } - (void) putc(c, dout); - bytes++; - /* if (c == '\r') { */ - /* (void) putc('\0', dout); // this violates rfc */ - /* bytes++; */ - /* } */ - } - if (hash) { - if (bytes < hashbytes) - (void) putchar('#'); - (void) putchar('\n'); - (void) fflush(stdout); - } - if (ferror(fin)) - warn("local: %s", local); - if (ferror(dout)) { - if (errno != EPIPE) - warn("netout"); - bytes = -1; - } - break; - } - if (closefunc != NULL) - (*closefunc)(fin); - (void) fclose(dout); - (void) gettimeofday(&stop, (struct timezone *)0); - (void) getreply(0); - (void) signal(SIGINT, oldintr); - if (oldintp) - (void) signal(SIGPIPE, oldintp); - if (bytes > 0) - ptransfer("sent", bytes, &start, &stop); - return; -abort: - (void) signal(SIGINT, oldintr); - if (oldintp) - (void) signal(SIGPIPE, oldintp); - if (!cpend) { - code = -1; - return; - } - if (data >= 0) { - (void) close(data); - data = -1; - } - if (dout) - (void) fclose(dout); - (void) getreply(0); - code = -1; - if (closefunc != NULL && fin != NULL) - (*closefunc)(fin); - (void) gettimeofday(&stop, (struct timezone *)0); - if (bytes > 0) - ptransfer("sent", bytes, &start, &stop); -} - -jmp_buf recvabort; - -void -abortrecv() -{ - - mflag = 0; - abrtflag = 0; - printf("\nreceive aborted\nwaiting for remote to finish abort\n"); - (void) fflush(stdout); - longjmp(recvabort, 1); -} - -void -recvrequest(cmd, local, remote, lmode, printnames) - char *cmd, *local, *remote, *lmode; - int printnames; -{ - FILE *fout, *din = 0; - int (*closefunc) __P((FILE *)); - sig_t oldintr, oldintp; - int c, d, is_retr, tcrflag, bare_lfs = 0; - static int bufsize; - static char *buf; - long bytes = 0, hashbytes = HASHBYTES; - struct timeval start, stop; - struct stat st; - - is_retr = strcmp(cmd, "RETR") == 0; - if (is_retr && verbose && printnames) { - if (local && *local != '-') - printf("local: %s ", local); - if (remote) - printf("remote: %s\n", remote); - } - if (proxy && is_retr) { - proxtrans(cmd, local, remote); - return; - } - closefunc = NULL; - oldintr = NULL; - oldintp = NULL; - tcrflag = !crflag && is_retr; - if (setjmp(recvabort)) { - while (cpend) { - (void) getreply(0); - } - if (data >= 0) { - (void) close(data); - data = -1; - } - if (oldintr) - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - oldintr = signal(SIGINT, abortrecv); - if (strcmp(local, "-") && *local != '|') { - if (access(local, 2) < 0) { - char *dir = strrchr(local, '/'); - - if (errno != ENOENT && errno != EACCES) { - warn("local: %s", local); - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - if (dir != NULL) - *dir = 0; - d = access(dir ? local : ".", 2); - if (dir != NULL) - *dir = '/'; - if (d < 0) { - warn("local: %s", local); - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - if (!runique && errno == EACCES && - chmod(local, 0600) < 0) { - warn("local: %s", local); - (void) signal(SIGINT, oldintr); - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - if (runique && errno == EACCES && - (local = gunique(local)) == NULL) { - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - } - else if (runique && (local = gunique(local)) == NULL) { - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - } - if (!is_retr) { - if (curtype != TYPE_A) - changetype(TYPE_A, 0); - } else if (curtype != type) - changetype(type, 0); - if (initconn()) { - (void) signal(SIGINT, oldintr); - code = -1; - return; - } - if (setjmp(recvabort)) - goto abort; - if (is_retr && restart_point && - command("REST %ld", (long) restart_point) != CONTINUE) - return; - if (remote) { - if (command("%s %s", cmd, remote) != PRELIM) { - (void) signal(SIGINT, oldintr); - return; - } - } else { - if (command("%s", cmd) != PRELIM) { - (void) signal(SIGINT, oldintr); - return; - } - } - din = dataconn("r"); - if (din == NULL) - goto abort; - if (strcmp(local, "-") == 0) - fout = stdout; - else if (*local == '|') { - oldintp = signal(SIGPIPE, SIG_IGN); - fout = popen(local + 1, "w"); - if (fout == NULL) { - warn("%s", local+1); - goto abort; - } - closefunc = pclose; - } else { - fout = fopen(local, lmode); - if (fout == NULL) { - warn("local: %s", local); - goto abort; - } - closefunc = fclose; - } - if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) - st.st_blksize = BUFSIZ; - if (st.st_blksize > bufsize) { - if (buf) - (void) free(buf); - buf = malloc((unsigned)st.st_blksize); - if (buf == NULL) { - warn("malloc"); - bufsize = 0; - goto abort; - } - bufsize = st.st_blksize; - } - (void) gettimeofday(&start, (struct timezone *)0); - switch (curtype) { - - case TYPE_I: - case TYPE_L: - if (restart_point && - lseek(fileno(fout), restart_point, SEEK_SET) < 0) { - warn("local: %s", local); - if (closefunc != NULL) - (*closefunc)(fout); - return; - } - errno = d = 0; - while ((c = read(fileno(din), buf, bufsize)) > 0) { - if ((d = write(fileno(fout), buf, c)) != c) - break; - bytes += c; - if (hash) { - while (bytes >= hashbytes) { - (void) putchar('#'); - hashbytes += HASHBYTES; - } - (void) fflush(stdout); - } - } - if (hash && bytes > 0) { - if (bytes < HASHBYTES) - (void) putchar('#'); - (void) putchar('\n'); - (void) fflush(stdout); - } - if (c < 0) { - if (errno != EPIPE) - warn("netin"); - bytes = -1; - } - if (d < c) { - if (d < 0) - warn("local: %s", local); - else - warnx("%s: short write", local); - } - break; - - case TYPE_A: - if (restart_point) { - int i, n, ch; - - if (fseek(fout, 0L, SEEK_SET) < 0) - goto done; - n = restart_point; - for (i = 0; i++ < n;) { - if ((ch = getc(fout)) == EOF) - goto done; - if (ch == '\n') - i++; - } - if (fseek(fout, 0L, SEEK_CUR) < 0) { -done: - warn("local: %s", local); - if (closefunc != NULL) - (*closefunc)(fout); - return; - } - } - while ((c = getc(din)) != EOF) { - if (c == '\n') - bare_lfs++; - while (c == '\r') { - while (hash && (bytes >= hashbytes)) { - (void) putchar('#'); - (void) fflush(stdout); - hashbytes += HASHBYTES; - } - bytes++; - if ((c = getc(din)) != '\n' || tcrflag) { - if (ferror(fout)) - goto break2; - (void) putc('\r', fout); - if (c == '\0') { - bytes++; - goto contin2; - } - if (c == EOF) - goto contin2; - } - } - (void) putc(c, fout); - bytes++; - contin2: ; - } -break2: - if (bare_lfs) { - printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); - printf("File may not have transferred correctly.\n"); - } - if (hash) { - if (bytes < hashbytes) - (void) putchar('#'); - (void) putchar('\n'); - (void) fflush(stdout); - } - if (ferror(din)) { - if (errno != EPIPE) - warn("netin"); - bytes = -1; - } - if (ferror(fout)) - warn("local: %s", local); - break; - } - if (closefunc != NULL) - (*closefunc)(fout); - (void) signal(SIGINT, oldintr); - if (oldintp) - (void) signal(SIGPIPE, oldintp); - (void) fclose(din); - (void) gettimeofday(&stop, (struct timezone *)0); - (void) getreply(0); - if (bytes > 0 && is_retr) - ptransfer("received", bytes, &start, &stop); - return; -abort: - -/* abort using RFC959 recommended IP,SYNC sequence */ - - if (oldintp) - (void) signal(SIGPIPE, oldintr); - (void) signal(SIGINT, SIG_IGN); - if (!cpend) { - code = -1; - (void) signal(SIGINT, oldintr); - return; - } - - abort_remote(din); - code = -1; - if (data >= 0) { - (void) close(data); - data = -1; - } - if (closefunc != NULL && fout != NULL) - (*closefunc)(fout); - if (din) - (void) fclose(din); - (void) gettimeofday(&stop, (struct timezone *)0); - if (bytes > 0) - ptransfer("received", bytes, &start, &stop); - (void) signal(SIGINT, oldintr); -} - -/* - * Need to start a listen on the data channel before we send the command, - * otherwise the server's connect may fail. - */ -int -initconn() -{ - char *p, *a; - int result, len, tmpno = 0; - int on = 1; - int a0, a1, a2, a3, p0, p1; - - if (passivemode) { - data = socket(AF_INET, SOCK_STREAM, 0); - if (data < 0) { - perror("ftp: socket"); - return(1); - } - if ((options & SO_DEBUG) && - setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, - sizeof (on)) < 0) - perror("ftp: setsockopt (ignored)"); - if (command("PASV") != COMPLETE) { - printf("Passive mode refused.\n"); - goto bad; - } - - /* - * What we've got at this point is a string of comma - * separated one-byte unsigned integer values. - * The first four are the an IP address. The fifth is - * the MSB of the port number, the sixth is the LSB. - * From that we'll prepare a sockaddr_in. - */ - - if (sscanf(pasv,"%d,%d,%d,%d,%d,%d", - &a0, &a1, &a2, &a3, &p0, &p1) != 6) { - printf("Passive mode address scan failure. " - "Shouldn't happen!\n"); - goto bad; - } - - bzero(&data_addr, sizeof(data_addr)); - data_addr.sin_family = AF_INET; - a = (char *)&data_addr.sin_addr.s_addr; - a[0] = a0 & 0xff; - a[1] = a1 & 0xff; - a[2] = a2 & 0xff; - a[3] = a3 & 0xff; - p = (char *)&data_addr.sin_port; - p[0] = p0 & 0xff; - p[1] = p1 & 0xff; - - if (connect(data, (struct sockaddr *)&data_addr, - sizeof(data_addr)) < 0) { - perror("ftp: connect"); - goto bad; - } -#ifdef IP_TOS - on = IPTOS_THROUGHPUT; - if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, - sizeof(int)) < 0) - perror("ftp: setsockopt TOS (ignored)"); -#endif - return(0); - } - -noport: - data_addr = myctladdr; - if (sendport) - data_addr.sin_port = 0; /* let system pick one */ - if (data != -1) - (void) close(data); - data = socket(AF_INET, SOCK_STREAM, 0); - if (data < 0) { - warn("socket"); - if (tmpno) - sendport = 1; - return (1); - } - if (!sendport) - if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { - warn("setsockopt (reuse address)"); - goto bad; - } - if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { - warn("bind"); - goto bad; - } - if (options & SO_DEBUG && - setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) - warn("setsockopt (ignored)"); - len = sizeof (data_addr); - if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { - warn("getsockname"); - goto bad; - } - if (listen(data, 1) < 0) - warn("listen"); - if (sendport) { - a = (char *)&data_addr.sin_addr; - p = (char *)&data_addr.sin_port; -#define UC(b) (((int)b)&0xff) - result = - command("PORT %d,%d,%d,%d,%d,%d", - UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - UC(p[0]), UC(p[1])); - if (result == ERROR && sendport == -1) { - sendport = 0; - tmpno = 1; - goto noport; - } - return (result != COMPLETE); - } - if (tmpno) - sendport = 1; -#ifdef IP_TOS - on = IPTOS_THROUGHPUT; - if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) - warn("setsockopt TOS (ignored)"); -#endif - return (0); -bad: - (void) close(data), data = -1; - if (tmpno) - sendport = 1; - return (1); -} - -FILE * -dataconn(lmode) - char *lmode; -{ - struct sockaddr_in from; - int s, fromlen = sizeof (from), tos; - - if (passivemode) - return (fdopen(data, lmode)); - - s = accept(data, (struct sockaddr *) &from, &fromlen); - if (s < 0) { - warn("accept"); - (void) close(data), data = -1; - return (NULL); - } - (void) close(data); - data = s; -#ifdef IP_TOS - tos = IPTOS_THROUGHPUT; - if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) - warn("setsockopt TOS (ignored)"); -#endif - return (fdopen(data, lmode)); -} - -void -ptransfer(direction, bytes, t0, t1) - char *direction; - long bytes; - struct timeval *t0, *t1; -{ - struct timeval td; - float s; - long bs; - - if (verbose) { - tvsub(&td, t1, t0); - s = td.tv_sec + (td.tv_usec / 1000000.); -#define nz(x) ((x) == 0 ? 1 : (x)) - bs = bytes / nz(s); - printf("%ld bytes %s in %.3g seconds (%ld bytes/s)\n", - bytes, direction, s, bs); - } -} - -/* -void -tvadd(tsum, t0) - struct timeval *tsum, *t0; -{ - - tsum->tv_sec += t0->tv_sec; - tsum->tv_usec += t0->tv_usec; - if (tsum->tv_usec > 1000000) - tsum->tv_sec++, tsum->tv_usec -= 1000000; -} -*/ - -void -tvsub(tdiff, t1, t0) - struct timeval *tdiff, *t1, *t0; -{ - - tdiff->tv_sec = t1->tv_sec - t0->tv_sec; - tdiff->tv_usec = t1->tv_usec - t0->tv_usec; - if (tdiff->tv_usec < 0) - tdiff->tv_sec--, tdiff->tv_usec += 1000000; -} - -void -psabort() -{ - - abrtflag++; -} - -void -pswitch(flag) - int flag; -{ - sig_t oldintr; - static struct comvars { - int connect; - char name[MAXHOSTNAMELEN]; - struct sockaddr_in mctl; - struct sockaddr_in hctl; - FILE *in; - FILE *out; - int tpe; - int curtpe; - int cpnd; - int sunqe; - int runqe; - int mcse; - int ntflg; - char nti[17]; - char nto[17]; - int mapflg; - char mi[MAXPATHLEN]; - char mo[MAXPATHLEN]; - } proxstruct, tmpstruct; - struct comvars *ip, *op; - - abrtflag = 0; - oldintr = signal(SIGINT, psabort); - if (flag) { - if (proxy) - return; - ip = &tmpstruct; - op = &proxstruct; - proxy++; - } else { - if (!proxy) - return; - ip = &proxstruct; - op = &tmpstruct; - proxy = 0; - } - ip->connect = connected; - connected = op->connect; - if (hostname) { - (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); - ip->name[strlen(ip->name)] = '\0'; - } else - ip->name[0] = 0; - hostname = op->name; - ip->hctl = hisctladdr; - hisctladdr = op->hctl; - ip->mctl = myctladdr; - myctladdr = op->mctl; - ip->in = cin; - cin = op->in; - ip->out = cout; - cout = op->out; - ip->tpe = type; - type = op->tpe; - ip->curtpe = curtype; - curtype = op->curtpe; - ip->cpnd = cpend; - cpend = op->cpnd; - ip->sunqe = sunique; - sunique = op->sunqe; - ip->runqe = runique; - runique = op->runqe; - ip->mcse = mcase; - mcase = op->mcse; - ip->ntflg = ntflag; - ntflag = op->ntflg; - (void) strncpy(ip->nti, ntin, 16); - (ip->nti)[strlen(ip->nti)] = '\0'; - (void) strcpy(ntin, op->nti); - (void) strncpy(ip->nto, ntout, 16); - (ip->nto)[strlen(ip->nto)] = '\0'; - (void) strcpy(ntout, op->nto); - ip->mapflg = mapflag; - mapflag = op->mapflg; - (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); - (ip->mi)[strlen(ip->mi)] = '\0'; - (void) strcpy(mapin, op->mi); - (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); - (ip->mo)[strlen(ip->mo)] = '\0'; - (void) strcpy(mapout, op->mo); - (void) signal(SIGINT, oldintr); - if (abrtflag) { - abrtflag = 0; - (*oldintr)(SIGINT); - } -} - -void -abortpt() -{ - - printf("\n"); - (void) fflush(stdout); - ptabflg++; - mflag = 0; - abrtflag = 0; - longjmp(ptabort, 1); -} - -void -proxtrans(cmd, local, remote) - char *cmd, *local, *remote; -{ - sig_t oldintr; - int secndflag = 0, prox_type, nfnd; - char *cmd2; - struct fd_set mask; - - if (strcmp(cmd, "RETR")) - cmd2 = "RETR"; - else - cmd2 = runique ? "STOU" : "STOR"; - if ((prox_type = type) == 0) { - if (unix_server && unix_proxy) - prox_type = TYPE_I; - else - prox_type = TYPE_A; - } - if (curtype != prox_type) - changetype(prox_type, 1); - if (command("PASV") != COMPLETE) { - printf("proxy server does not support third party transfers.\n"); - return; - } - pswitch(0); - if (!connected) { - printf("No primary connection\n"); - pswitch(1); - code = -1; - return; - } - if (curtype != prox_type) - changetype(prox_type, 1); - if (command("PORT %s", pasv) != COMPLETE) { - pswitch(1); - return; - } - if (setjmp(ptabort)) - goto abort; - oldintr = signal(SIGINT, abortpt); - if (command("%s %s", cmd, remote) != PRELIM) { - (void) signal(SIGINT, oldintr); - pswitch(1); - return; - } - sleep(2); - pswitch(1); - secndflag++; - if (command("%s %s", cmd2, local) != PRELIM) - goto abort; - ptflag++; - (void) getreply(0); - pswitch(0); - (void) getreply(0); - (void) signal(SIGINT, oldintr); - pswitch(1); - ptflag = 0; - printf("local: %s remote: %s\n", local, remote); - return; -abort: - (void) signal(SIGINT, SIG_IGN); - ptflag = 0; - if (strcmp(cmd, "RETR") && !proxy) - pswitch(1); - else if (!strcmp(cmd, "RETR") && proxy) - pswitch(0); - if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ - if (command("%s %s", cmd2, local) != PRELIM) { - pswitch(0); - if (cpend) - abort_remote((FILE *) NULL); - } - pswitch(1); - if (ptabflg) - code = -1; - (void) signal(SIGINT, oldintr); - return; - } - if (cpend) - abort_remote((FILE *) NULL); - pswitch(!proxy); - if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ - if (command("%s %s", cmd2, local) != PRELIM) { - pswitch(0); - if (cpend) - abort_remote((FILE *) NULL); - pswitch(1); - if (ptabflg) - code = -1; - (void) signal(SIGINT, oldintr); - return; - } - } - if (cpend) - abort_remote((FILE *) NULL); - pswitch(!proxy); - if (cpend) { - FD_ZERO(&mask); - FD_SET(fileno(cin), &mask); - if ((nfnd = empty(&mask, 10)) <= 0) { - if (nfnd < 0) { - warn("abort"); - } - if (ptabflg) - code = -1; - lostpeer(); - } - (void) getreply(0); - (void) getreply(0); - } - if (proxy) - pswitch(0); - pswitch(1); - if (ptabflg) - code = -1; - (void) signal(SIGINT, oldintr); -} - -void -reset(argc, argv) - int argc; - char *argv[]; -{ - struct fd_set mask; - int nfnd = 1; - - FD_ZERO(&mask); - while (nfnd > 0) { - FD_SET(fileno(cin), &mask); - if ((nfnd = empty(&mask,0)) < 0) { - warn("reset"); - code = -1; - lostpeer(); - } - else if (nfnd) { - (void) getreply(0); - } - } -} - -char * -gunique(local) - char *local; -{ - static char new[MAXPATHLEN]; - char *cp = strrchr(local, '/'); - int d, count=0; - char ext = '1'; - - if (cp) - *cp = '\0'; - d = access(cp ? local : ".", 2); - if (cp) - *cp = '/'; - if (d < 0) { - warn("local: %s", local); - return ((char *) 0); - } - (void) strcpy(new, local); - cp = new + strlen(new); - *cp++ = '.'; - while (!d) { - if (++count == 100) { - printf("runique: can't find unique file name.\n"); - return ((char *) 0); - } - *cp++ = ext; - *cp = '\0'; - if (ext == '9') - ext = '0'; - else - ext++; - if ((d = access(new, 0)) < 0) - break; - if (ext != '0') - cp--; - else if (*(cp - 2) == '.') - *(cp - 1) = '1'; - else { - *(cp - 2) = *(cp - 2) + 1; - cp--; - } - } - return (new); -} - -void -abort_remote(din) - FILE *din; -{ - char buf[BUFSIZ]; - int nfnd; - struct fd_set mask; - - /* - * send IAC in urgent mode instead of DM because 4.3BSD places oob mark - * after urgent byte rather than before as is protocol now - */ - sprintf(buf, "%c%c%c", IAC, IP, IAC); - if (send(fileno(cout), buf, 3, MSG_OOB) != 3) - warn("abort"); - fprintf(cout,"%cABOR\r\n", DM); - (void) fflush(cout); - FD_ZERO(&mask); - FD_SET(fileno(cin), &mask); - if (din) { - FD_SET(fileno(din), &mask); - } - if ((nfnd = empty(&mask, 10)) <= 0) { - if (nfnd < 0) { - warn("abort"); - } - if (ptabflg) - code = -1; - lostpeer(); - } - if (din && FD_ISSET(fileno(din), &mask)) { - while (read(fileno(din), buf, BUFSIZ) > 0) - /* LOOP */; - } - if (getreply(0) == ERROR && code == 552) { - /* 552 needed for nic style abort */ - (void) getreply(0); - } - (void) getreply(0); -} diff --git a/ftp.tproj/ftp_var.c b/ftp.tproj/ftp_var.c deleted file mode 100644 index f1f972b..0000000 --- a/ftp.tproj/ftp_var.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * 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. - * - * @(#)ftp_var.h 8.4 (Berkeley) 10/9/94 - */ - -#include - -#include "ftp_var.h" - -/* - * FTP global variables. - */ - -#include -#include - -#include "extern.h" - -/* - * Options and other state info. - */ -int trace; /* trace packets exchanged */ -int hash; /* print # for each buffer transferred */ -int sendport; /* use PORT cmd for each data connection */ -int verbose; /* print messages coming back from server */ -int connected; /* connected to server */ -int fromatty; /* input is from a terminal */ -int interactive; /* interactively prompt on m* cmds */ -int debug; /* debugging level */ -int bell; /* ring bell on cmd completion */ -int doglob; /* glob local file names */ -int autologin; /* establish user account on connection */ -int proxy; /* proxy server connection active */ -int proxflag; /* proxy connection exists */ -int sunique; /* store files on server with unique name */ -int runique; /* store local files with unique name */ -int mcase; /* map upper to lower case for mget names */ -int ntflag; /* use ntin ntout tables for name translation */ -int mapflag; /* use mapin mapout templates on file names */ -int code; /* return/reply code for ftp command */ -int crflag; /* if 1, strip car. rets. on ascii gets */ -char pasv[64]; /* passive port for proxy data connection */ -int passivemode; /* passive mode enabled */ -char *altarg; /* argv[1] with no shell-like preprocessing */ -char ntin[17]; /* input translation table */ -char ntout[17]; /* output translation table */ -char mapin[MAXPATHLEN]; /* input map template */ -char mapout[MAXPATHLEN]; /* output map template */ -char typename[32]; /* name of file transfer type */ -int type; /* requested file transfer type */ -int curtype; /* current file transfer type */ -char structname[32]; /* name of file transfer structure */ -int stru; /* file transfer structure */ -char formname[32]; /* name of file transfer format */ -int form; /* file transfer format */ -char modename[32]; /* name of file transfer mode */ -int mode; /* file transfer mode */ -char bytename[32]; /* local byte size in ascii */ -int bytesize; /* local byte size in binary */ - -char *hostname; /* name of host connected to */ -int unix_server; /* server is unix, can use binary for ascii */ -int unix_proxy; /* proxy is unix, can use binary for ascii */ - -struct servent *sp; /* service spec for tcp/ftp */ - -jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ - -char line[200]; /* input line buffer */ -char *stringbase; /* current scan point in line buffer */ -char argbuf[200]; /* argument storage buffer */ -char *argbase; /* current storage point in arg buffer */ -int margc; /* count of arguments on input line */ -char *margv[20]; /* args parsed from input line */ -int cpend; /* flag: if != 0, then pending server reply */ -int mflag; /* flag: if != 0, then active multi command */ - -int options; /* used during socket creation */ - -int macnum; /* number of defined macros */ -struct macel macros[16]; -char macbuf[4096]; diff --git a/ftp.tproj/ftp_var.h b/ftp.tproj/ftp_var.h deleted file mode 100644 index ad7f790..0000000 --- a/ftp.tproj/ftp_var.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * 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. - * - * @(#)ftp_var.h 8.4 (Berkeley) 10/9/94 - */ - -/* - * FTP global variables. - */ - -#include -#include - -#include "extern.h" - -/* - * Options and other state info. - */ -extern int trace; /* trace packets exchanged */ -extern int hash; /* pr int # for each buffer transferred */ -extern int sendport; /* use PORT cmd for each data connection */ -extern int verbose; /* print messages coming back from server */ -extern int connected; /* connected to server */ -extern int fromatty; /* input is from a terminal */ -extern int interactive; /* interactively prompt on m* cmds */ -extern int debug; /* debugging level */ -extern int bell; /* ring bell on cmd completion */ -extern int doglob; /* glob local file names */ -extern int autologin; /* establish user account on connection */ -extern int proxy; /* proxy server connection active */ -extern int proxflag; /* proxy connection exists */ -extern int sunique; /* store files on server with unique name */ -extern int runique; /* store local files with unique name */ -extern int mcase; /* map upper to lower case for mget names */ -extern int ntflag; /* use ntin ntout tables for name translation */ -extern int mapflag; /* use mapin mapout templates on file names */ -extern int code; /* return/reply code for ftp command */ -extern int crflag; /* if 1, strip car. rets. on ascii gets */ -extern char pasv[64]; /* passive port for proxy data connection */ -extern int passivemode; /* passive mode enabled */ -extern char *altarg; /* argv[1] with no shell-like preprocessing */ -extern char ntin[17]; /* input translation table */ -extern char ntout[17]; /* output translation table */ -extern char mapin[MAXPATHLEN]; /* input map template */ -extern char mapout[MAXPATHLEN]; /* output map template */ -extern char typename[32]; /* name of file transfer type */ -extern int type; /* requested file transfer type */ -extern int curtype; /* current file transfer type */ -extern char structname[32]; /* name of file transfer structure */ -extern int stru; /* file transfer structure */ -extern char formname[32]; /* name of file transfer format */ -extern int form; /* file transfer format */ -extern char modename[32]; /* name of file transfer mode */ -extern int mode; /* file transfer mode */ -extern char bytename[32]; /* local byte size in ascii */ -extern int bytesize; /* local byte size in binary */ - -extern char *hostname; /* name of host connected to */ -extern int unix_server; /* server is unix, can use binary for ascii */ -extern int unix_proxy; /* proxy is unix, can use binary for ascii */ - -extern struct servent *sp; /* service spec for tcp/ftp */ - -extern jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ - -extern char line[200]; /* input line buffer */ -extern char *stringbase; /* current scan point in line buffer */ -extern char argbuf[200]; /* argument storage buffer */ -extern char *argbase; /* current storage point in arg buffer */ -extern int margc; /* count of arguments on input line */ -extern char *margv[20]; /* args parsed from input line */ -extern int cpend; /* flag: if != 0, then pending server reply */ -extern int mflag; /* flag: if != 0, then active multi command */ - -extern int options; /* used during socket creation */ - -/* - * Format of command table. - */ -struct cmd { - char *c_name; /* name of command */ - char *c_help; /* help string */ - char c_bell; /* give bell when command completes */ - char c_conn; /* must be connected to use command */ - char c_proxy; /* proxy server may execute */ - void (*c_handler) __P((int, char **)); /* function to call */ -}; - -struct macel { - char mac_name[9]; /* macro name */ - char *mac_start; /* start of macro in macbuf */ - char *mac_end; /* end of macro in macbuf */ -}; - -extern int macnum; /* number of defined macros */ -extern struct macel macros[16]; -extern char macbuf[4096]; diff --git a/ftp.tproj/h.template b/ftp.tproj/h.template deleted file mode 100644 index f3c1b04..0000000 --- a/ftp.tproj/h.template +++ /dev/null @@ -1,11 +0,0 @@ -$$ -/* $FILENAME$ created by $USERNAME$ on $DATE$ */ - -#import - -@interface $FILENAMESANSEXTENSION$ : NSObject -{ - -} - -@end diff --git a/ftp.tproj/m.template b/ftp.tproj/m.template deleted file mode 100644 index 1216fe5..0000000 --- a/ftp.tproj/m.template +++ /dev/null @@ -1,18 +0,0 @@ -$$ Lines starting with $$ are not inserted into newly created files -$$ The following substitutions are made: -$$ -$$ $FILENAME$ e.g. foo.m -$$ $FILENAMESANSEXTENSION$ e.g. foo -$$ $DIRECTORY$ e.g. /tmp/MyNewApp -$$ $PROJECTNAME$ e.g. MyNewApp -$$ $SUBPROJECTNAME$ e.g. TheGoodPart.subproj -$$ $USERNAME$ e.g. mwagner -$$ $DATE$ e.g. Jan-1-1994 -$$ -/* $FILENAME$ created by $USERNAME$ on $DATE$ */ - -#import "$FILENAMESANSEXTENSION$.h" - -@implementation $FILENAMESANSEXTENSION$ - -@end diff --git a/ftp.tproj/main.c b/ftp.tproj/main.c deleted file mode 100644 index 4ad3ed2..0000000 --- a/ftp.tproj/main.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1989, 1993, 1994 - * 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. - */ - -/* - * FTP User Program -- Command Interface. - */ -/*#include */ -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ftp_var.h" - -int -main(argc, argv) - int argc; - char *argv[]; -{ - int ch, top; - struct passwd *pw = NULL; - char *cp, homedir[MAXPATHLEN]; - - sp = getservbyname("ftp", "tcp"); - if (sp == 0) - errx(1, "ftp/tcp: unknown service"); - doglob = 1; - interactive = 1; - autologin = 1; - - while ((ch = getopt(argc, argv, "dgintv")) != EOF) { - switch (ch) { - case 'd': - options |= SO_DEBUG; - debug++; - break; - - case 'g': - doglob = 0; - break; - - case 'i': - interactive = 0; - break; - - case 'n': - autologin = 0; - break; - - case 't': - trace++; - break; - - case 'v': - verbose++; - break; - - default: - (void)fprintf(stderr, - "usage: ftp [-dgintv] [host [port]]\n"); - exit(1); - } - } - argc -= optind; - argv += optind; - - fromatty = isatty(fileno(stdin)); - if (fromatty) - verbose++; - cpend = 0; /* no pending replies */ - proxy = 0; /* proxy not active */ - passivemode = 0; /* passive mode not active */ - crflag = 1; /* strip c.r. on ascii gets */ - sendport = -1; /* not using ports */ - /* - * Set up the home directory in case we're globbing. - */ - cp = getlogin(); - if (cp != NULL) { - pw = getpwnam(cp); - } - if (pw == NULL) - pw = getpwuid(getuid()); - if (pw != NULL) { - home = homedir; - (void) strcpy(home, pw->pw_dir); - } - if (argc > 0) { - char *xargv[5]; - extern char *__progname; - - if (setjmp(toplevel)) - exit(0); - (void) signal(SIGINT, intr); - (void) signal(SIGPIPE, lostpeer); - xargv[0] = __progname; - xargv[1] = argv[0]; - xargv[2] = argv[1]; - xargv[3] = argv[2]; - xargv[4] = NULL; - setpeer(argc+1, xargv); - } - top = setjmp(toplevel) == 0; - if (top) { - (void) signal(SIGINT, intr); - (void) signal(SIGPIPE, lostpeer); - } - for (;;) { - cmdscanner(top); - top = 1; - } -} - -void -intr() -{ - - longjmp(toplevel, 1); -} - -void -lostpeer() -{ - - if (connected) { - if (cout != NULL) { - (void) shutdown(fileno(cout), 1+1); - (void) fclose(cout); - cout = NULL; - } - if (data >= 0) { - (void) shutdown(data, 1+1); - (void) close(data); - data = -1; - } - connected = 0; - } - pswitch(1); - if (connected) { - if (cout != NULL) { - (void) shutdown(fileno(cout), 1+1); - (void) fclose(cout); - cout = NULL; - } - connected = 0; - } - proxflag = 0; - pswitch(0); -} - -/* -char * -tail(filename) - char *filename; -{ - char *s; - - while (*filename) { - s = strrchr(filename, '/'); - if (s == NULL) - break; - if (s[1]) - return (s + 1); - *s = '\0'; - } - return (filename); -} -*/ - -/* - * Command parser. - */ -void -cmdscanner(top) - int top; -{ - struct cmd *c; - int l; - - if (!top) - (void) putchar('\n'); - for (;;) { - if (fromatty) { - printf("ftp> "); - (void) fflush(stdout); - } - if (fgets(line, sizeof line, stdin) == NULL) - quit(0, 0); - l = strlen(line); - if (l == 0) - break; - if (line[--l] == '\n') { - if (l == 0) - break; - line[l] = '\0'; - } else if (l == sizeof(line) - 2) { - printf("sorry, input line too long\n"); - while ((l = getchar()) != '\n' && l != EOF) - /* void */; - break; - } /* else it was a line without a newline */ - makeargv(); - if (margc == 0) { - continue; - } - c = getcmd(margv[0]); - if (c == (struct cmd *)-1) { - printf("?Ambiguous command\n"); - continue; - } - if (c == 0) { - printf("?Invalid command\n"); - continue; - } - if (c->c_conn && !connected) { - printf("Not connected.\n"); - continue; - } - (*c->c_handler)(margc, margv); - if (bell && c->c_bell) - (void) putchar('\007'); - if (c->c_handler != help) - break; - } - (void) signal(SIGINT, intr); - (void) signal(SIGPIPE, lostpeer); -} - -struct cmd * -getcmd(name) - char *name; -{ - char *p, *q; - struct cmd *c, *found; - int nmatches, longest; - - longest = 0; - nmatches = 0; - found = 0; - for (c = cmdtab; p = c->c_name; c++) { - for (q = name; *q == *p++; q++) - if (*q == 0) /* exact match? */ - return (c); - if (!*q) { /* the name was a prefix */ - if (q - name > longest) { - longest = q - name; - nmatches = 1; - found = c; - } else if (q - name == longest) - nmatches++; - } - } - if (nmatches > 1) - return ((struct cmd *)-1); - return (found); -} - -/* - * Slice a string up into argc/argv. - */ - -int slrflag; - -void -makeargv() -{ - char **argp; - - margc = 0; - argp = margv; - stringbase = line; /* scan from first of buffer */ - argbase = argbuf; /* store from first of buffer */ - slrflag = 0; - while (*argp++ = slurpstring()) - margc++; -} - -/* - * Parse string into argbuf; - * implemented with FSM to - * handle quoting and strings - */ -char * -slurpstring() -{ - int got_one = 0; - char *sb = stringbase; - char *ap = argbase; - char *tmp = argbase; /* will return this if token found */ - - if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ - switch (slrflag) { /* and $ as token for macro invoke */ - case 0: - slrflag++; - stringbase++; - return ((*sb == '!') ? "!" : "$"); - /* NOTREACHED */ - case 1: - slrflag++; - altarg = stringbase; - break; - default: - break; - } - } - -S0: - switch (*sb) { - - case '\0': - goto OUT; - - case ' ': - case '\t': - sb++; goto S0; - - default: - switch (slrflag) { - case 0: - slrflag++; - break; - case 1: - slrflag++; - altarg = sb; - break; - default: - break; - } - goto S1; - } - -S1: - switch (*sb) { - - case ' ': - case '\t': - case '\0': - goto OUT; /* end of token */ - - case '\\': - sb++; goto S2; /* slurp next character */ - - case '"': - sb++; goto S3; /* slurp quoted string */ - - default: - *ap++ = *sb++; /* add character to token */ - got_one = 1; - goto S1; - } - -S2: - switch (*sb) { - - case '\0': - goto OUT; - - default: - *ap++ = *sb++; - got_one = 1; - goto S1; - } - -S3: - switch (*sb) { - - case '\0': - goto OUT; - - case '"': - sb++; goto S1; - - default: - *ap++ = *sb++; - got_one = 1; - goto S3; - } - -OUT: - if (got_one) - *ap++ = '\0'; - argbase = ap; /* update storage pointer */ - stringbase = sb; /* update scan pointer */ - if (got_one) { - return (tmp); - } - switch (slrflag) { - case 0: - slrflag++; - break; - case 1: - slrflag++; - altarg = (char *) 0; - break; - default: - break; - } - return ((char *)0); -} - -#define HELPINDENT ((int) sizeof ("directory")) - -/* - * Help command. - * Call each command handler with argc == 0 and argv[0] == name. - */ -void -help(argc, argv) - int argc; - char *argv[]; -{ - struct cmd *c; - - if (argc == 1) { - int i, j, w, k; - int columns, width = 0, lines; - - printf("Commands may be abbreviated. Commands are:\n\n"); - for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { - int len = strlen(c->c_name); - - if (len > width) - width = len; - } - width = (width + 8) &~ 7; - columns = 80 / width; - if (columns == 0) - columns = 1; - lines = (NCMDS + columns - 1) / columns; - for (i = 0; i < lines; i++) { - for (j = 0; j < columns; j++) { - c = cmdtab + j * lines + i; - if (c->c_name && (!proxy || c->c_proxy)) { - printf("%s", c->c_name); - } - else if (c->c_name) { - for (k=0; k < strlen(c->c_name); k++) { - (void) putchar(' '); - } - } - if (c + lines >= &cmdtab[NCMDS]) { - printf("\n"); - break; - } - w = strlen(c->c_name); - while (w < width) { - w = (w + 8) &~ 7; - (void) putchar('\t'); - } - } - } - return; - } - while (--argc > 0) { - char *arg; - arg = *++argv; - c = getcmd(arg); - if (c == (struct cmd *)-1) - printf("?Ambiguous help command %s\n", arg); - else if (c == (struct cmd *)0) - printf("?Invalid help command %s\n", arg); - else - printf("%-*s\t%s\n", HELPINDENT, - c->c_name, c->c_help); - } -} diff --git a/ftp.tproj/pathnames.h b/ftp.tproj/pathnames.h deleted file mode 100644 index 4403aa8..0000000 --- a/ftp.tproj/pathnames.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 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. - * - * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 - */ - -#include - -#undef _PATH_TMP -#define _PATH_TMP "/tmp/ftpXXXXXX" diff --git a/ftp.tproj/ruserpass.c b/ftp.tproj/ruserpass.c deleted file mode 100644 index ed5a406..0000000 --- a/ftp.tproj/ruserpass.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1993, 1994 - * 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. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "ftp_var.h" - -static int token __P((void)); -static FILE *cfile; - -#define DEFAULT 1 -#define LOGIN 2 -#define PASSWD 3 -#define ACCOUNT 4 -#define MACDEF 5 -#define ID 10 -#define MACH 11 - -static char tokval[100]; - -static struct toktab { - char *tokstr; - int tval; -} toktab[]= { - { "default", DEFAULT }, - { "login", LOGIN }, - { "password", PASSWD }, - { "passwd", PASSWD }, - { "account", ACCOUNT }, - { "machine", MACH }, - { "macdef", MACDEF }, - { NULL, 0 } -}; - -int -ruserpass(host, aname, apass, aacct) - char *host, **aname, **apass, **aacct; -{ - char *hdir, buf[BUFSIZ], *tmp; - char myname[MAXHOSTNAMELEN], *mydomain; - int t, i, c, usedefault = 0; - struct stat stb; - - hdir = getenv("HOME"); - if (hdir == NULL) - hdir = "."; - (void) sprintf(buf, "%s/.netrc", hdir); - cfile = fopen(buf, "r"); - if (cfile == NULL) { - if (errno != ENOENT) - warn("%s", buf); - return (0); - } - if (gethostname(myname, sizeof(myname)) < 0) - myname[0] = '\0'; - if ((mydomain = strchr(myname, '.')) == NULL) - mydomain = ""; -next: - while ((t = token())) switch(t) { - - case DEFAULT: - usedefault = 1; - /* FALL THROUGH */ - - case MACH: - if (!usedefault) { - if (token() != ID) - continue; - /* - * Allow match either for user's input host name - * or official hostname. Also allow match of - * incompletely-specified host in local domain. - */ - if (strcasecmp(host, tokval) == 0) - goto match; - if (strcasecmp(hostname, tokval) == 0) - goto match; - if ((tmp = strchr(hostname, '.')) != NULL && - strcasecmp(tmp, mydomain) == 0 && - strncasecmp(hostname, tokval, tmp-hostname) == 0 && - tokval[tmp - hostname] == '\0') - goto match; - if ((tmp = strchr(host, '.')) != NULL && - strcasecmp(tmp, mydomain) == 0 && - strncasecmp(host, tokval, tmp - host) == 0 && - tokval[tmp - host] == '\0') - goto match; - continue; - } - match: - while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { - - case LOGIN: - if (token()) - if (*aname == 0) { - *aname = malloc((unsigned) strlen(tokval) + 1); - (void) strcpy(*aname, tokval); - } else { - if (strcmp(*aname, tokval)) - goto next; - } - break; - case PASSWD: - if ((*aname == NULL || strcmp(*aname, "anonymous")) && - fstat(fileno(cfile), &stb) >= 0 && - (stb.st_mode & 077) != 0) { - warnx("Error: .netrc file is readable by others."); - warnx("Remove password or make file unreadable by others."); - goto bad; - } - if (token() && *apass == 0) { - *apass = malloc((unsigned) strlen(tokval) + 1); - (void) strcpy(*apass, tokval); - } - break; - case ACCOUNT: - if (fstat(fileno(cfile), &stb) >= 0 - && (stb.st_mode & 077) != 0) { - warnx("Error: .netrc file is readable by others."); - warnx("Remove account or make file unreadable by others."); - goto bad; - } - if (token() && *aacct == 0) { - *aacct = malloc((unsigned) strlen(tokval) + 1); - (void) strcpy(*aacct, tokval); - } - break; - case MACDEF: - if (proxy) { - (void) fclose(cfile); - return (0); - } - while ((c=getc(cfile)) != EOF && c == ' ' || c == '\t'); - if (c == EOF || c == '\n') { - printf("Missing macdef name argument.\n"); - goto bad; - } - if (macnum == 16) { - printf("Limit of 16 macros have already been defined\n"); - goto bad; - } - tmp = macros[macnum].mac_name; - *tmp++ = c; - for (i=0; i < 8 && (c=getc(cfile)) != EOF && - !isspace(c); ++i) { - *tmp++ = c; - } - if (c == EOF) { - printf("Macro definition missing null line terminator.\n"); - goto bad; - } - *tmp = '\0'; - if (c != '\n') { - while ((c=getc(cfile)) != EOF && c != '\n'); - } - if (c == EOF) { - printf("Macro definition missing null line terminator.\n"); - goto bad; - } - if (macnum == 0) { - macros[macnum].mac_start = macbuf; - } - else { - macros[macnum].mac_start = macros[macnum-1].mac_end + 1; - } - tmp = macros[macnum].mac_start; - while (tmp != macbuf + 4096) { - if ((c=getc(cfile)) == EOF) { - printf("Macro definition missing null line terminator.\n"); - goto bad; - } - *tmp = c; - if (*tmp == '\n') { - if (*(tmp-1) == '\0') { - macros[macnum++].mac_end = tmp - 1; - break; - } - *tmp = '\0'; - } - tmp++; - } - if (tmp == macbuf + 4096) { - printf("4K macro buffer exceeded\n"); - goto bad; - } - break; - default: - warnx("Unknown .netrc keyword %s", tokval); - break; - } - goto done; - } -done: - (void) fclose(cfile); - return (0); -bad: - (void) fclose(cfile); - return (-1); -} - -static int -token() -{ - char *cp; - int c; - struct toktab *t; - - if (feof(cfile) || ferror(cfile)) - return (0); - while ((c = getc(cfile)) != EOF && - (c == '\n' || c == '\t' || c == ' ' || c == ',')) - continue; - if (c == EOF) - return (0); - cp = tokval; - if (c == '"') { - while ((c = getc(cfile)) != EOF && c != '"') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } - } else { - *cp++ = c; - while ((c = getc(cfile)) != EOF - && c != '\n' && c != '\t' && c != ' ' && c != ',') { - if (c == '\\') - c = getc(cfile); - *cp++ = c; - } - } - *cp = 0; - if (tokval[0] == 0) - return (0); - for (t = toktab; t->tokstr; t++) - if (!strcmp(t->tokstr, tokval)) - return (t->tval); - return (ID); -} diff --git a/ftpd.tproj/Makefile.postamble b/ftpd.tproj/Makefile.postamble deleted file mode 100644 index 7ede358..0000000 --- a/ftpd.tproj/Makefile.postamble +++ /dev/null @@ -1,111 +0,0 @@ -############################################################################### -# NeXT Makefile.postamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. Additional -# rules (e.g., after_install) that are defined by the developer should be -# defined in this file. -# -############################################################################### -# -# Here are the variables exported by the common "app" makefiles that can be -# used in any customizations you make to the template below: -# -# PRODUCT_ROOT - Name of the directory to which resources are copied. -# OFILE_DIR - Directory into which .o object files are generated. -# (Note that this name is calculated based on the target -# architectures specified in Project Builder). -# DERIVED_SRC_DIR - Directory used for all other derived files -# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations -# -# NAME - name of application, bundle, subproject, palette, etc. -# LANGUAGE - langage in which the project is written (default "English") -# ENGLISH - boolean flag set iff $(LANGUAGE) = "English" -# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese" -# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project -# GLOBAL_RESOURCES - non-localized resources of project -# PROJECTVERSION - version of ProjectBuilder that output Makefile -# APPICON - application icon file -# DOCICONS - dock icon files -# ICONSECTIONS - Specifies icon sections when linking executable -# -# CLASSES - Class implementation files in project. -# HFILES - Header files in project. -# MFILES - Other Objective-C source files in project. -# CFILES - Other C source files in project. -# PSWFILES - .psw files in the project -# PSWMFILES - .pswm files in the project -# SUBPROJECTS - Subprojects of this project -# BUNDLES - Bundle subprojects of this project -# OTHERSRCS - Other miscellaneous sources of this project -# OTHERLINKED - Source files not matching a standard source extention -# -# LIBS - Libraries to link with when making app target -# DEBUG_LIBS - Libraries to link with when making debug target -# PROF_LIBS - Libraries to link with when making profile target -# OTHERLINKEDOFILES - Other relocatable files to (always) link in. -# -# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles -# MAKEFILEDIR - Directory in which to find $(MAKEFILE) -# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make) -# INSTALLDIR - Directory app will be installed into by 'install' target -# -############################################################################### - - -# Change defaults assumed by the standard makefiles here. Edit the -# following default values as appropriate. (Note that if no Makefile.postamble -# exists, these values will have defaults set in common.make). - -# Versioning of frameworks, libraries, bundles, and palettes: -#CURRENTLY_ACTIVE_VERSION = YES # Set to "NO" to produce a compatibility binary -#DEPLOY_WITH_VERSION_NAME = A -#COMPATIBILITY_PROJECT_VERSION = 1 - -# Some compiler flags can be easily overridden here, but onlytake effect at -# the top-level: -#OPTIMIZATION_CFLAG = -O -#DEBUG_SYMBOLS_CFLAG = -g -#WARNING_CFLAGS = -Wall -#DEBUG_BUILD_CFLAGS = -DDEBUG -#PROFILE_BUILD_CFLAGS = -pg -DPROFILE - -# Flags passed to yacc -#YFLAGS = -d - -# Library and Framework projects only: -# 1. If you want something other than the default .dylib name, override it here -#DYLIB_INSTALL_NAME = lib$(NAME).dylib - -# 2. If you want to change the -install_name flag from the absolute path to the development area, change it here. One good choice is the installation directory. Another one might be none at all. -#DYLIB_INSTALL_DIR = $(INSTALLDIR) - -# Ownership and permissions of files installed by 'install' target -#INSTALL_AS_USER = root # User/group ownership -#INSTALL_AS_GROUP = wheel # (probably want to set both of these) -#INSTALL_PERMISSIONS = # If set, 'install' chmod's executable to this - -# Options to strip for various project types. Note: -S strips debugging symbols -# (executables can be stripped down further with -x or, if they load no bundles, with no -# options at all). -#APP_STRIP_OPTS = -S -#TOOL_STRIP_OPTS = -S -#LIBRARY_STRIP_OPTS = -S # for .a archives -#DYNAMIC_STRIP_OPTS = -S # for bundles and shared libraries -STRIPFLAGS = - -######################################################################### -# Put rules to extend the behavior of the standard Makefiles here. "Official" -# user-defined rules are: -# * before_install -# * after_install -# * after_installhdrs -# You should avoid redefining things like "install" or "app", as they are -# owned by the top-level Makefile API and no context has been set up for where -# derived files should go. - diff --git a/ftpd.tproj/Makefile.preamble b/ftpd.tproj/Makefile.preamble deleted file mode 100644 index 3ae0517..0000000 --- a/ftpd.tproj/Makefile.preamble +++ /dev/null @@ -1,119 +0,0 @@ -############################################################################### -# NeXT Makefile.preamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project. Each node in a project -# tree of sub-projects, tools, etc. should have its own Makefile.preamble and -# Makefile.postamble. -# -############################################################################### -## Configure the flags passed to $(CC) here. These flags will also be -## inherited by all nested sub-projects and bundles. Put your -I, -D, -U, and -## -L flags in ProjectBuilder's Build Options inspector if at all possible. -## To change the default flags that get passed to ${CC} -## (e.g. change -O to -O2), see Makefile.postamble. - -# Flags passed to compiler (in addition to -g, -O, etc) -OTHER_CFLAGS = -Dmain=ls_main -# Flags passed to ld (in addition to -ObjC, etc.) -OTHER_LDFLAGS = -# Flags passed to libtool when building libraries -OTHER_LIBTOOL_FLAGS = -# For ordering named sections on NEXTSTEP (see ld(1)) -SECTORDER_FLAGS = - -# Stuff related to exporting headers from this project that isn't already -# handled by PB. -OTHER_PUBLIC_HEADERS = -OTHER_PROJECT_HEADERS = -OTHER_PRIVATE_HEADERS = - -# Set all three of these if you want a precomp to be built as part of -# installation. The cc -precomp will be run in the specified dir on the -# specified public header files with the specified additional flags. Don't put -# $(DSTROOT) in PUBLIC_HEADER_DIR; this is done for you. -PUBLIC_HEADER_DIR = -PUBLIC_PRECOMPILED_HEADERS = -PUBLIC_PRECOMPILED_HEADERS_CFLAGS = - -PRIVATE_HEADER_DIR = - -# If, in a subproject, you want to append to the parent's PUBLIC_HEADER_DIR# -# (say, to add a subdirectory like "/sys"), you can use: -PUBLIC_HEADER_DIR_SUFFIX = -PRIVATE_HEADER_DIR_SUFFIX = - -# Additional (non-localized) resources for this project, which can be generated -OTHER_RESOURCES = - -# Set this to YES if you don't want a final libtool call for a library/framework. -BUILD_OFILES_LIST_ONLY = - -# Additional relocatables to be linked into this project -OTHER_OFILES = -# Additional libraries to link against -OTHER_LIBS = -# To include a version string, project source must exist in a directory named -# $(NAME).%d[.%d][.%d] and the following line must be uncommented. -OTHER_GENERATED_OFILES = $(VERS_OFILE) - -## Configure how things get built here. Additional dependencies, source files, -## derived files, and build order should be specified here. - -# Other dependencies of this project -OTHER_PRODUCT_DEPENDS = -# Built *before* building subprojects/bundles -OTHER_INITIAL_TARGETS = -# Other source files maintained by .pre/postamble -OTHER_SOURCEFILES = -# Additional files to be removed by `make clean' -OTHER_GARBAGE = - -# Targets to build before installation -OTHER_INSTALL_DEPENDS = - -# A virtual root directory (other than /) to be prepended to the $(INSTALLDIR) -# passed from ProjectBuilder. -DSTROOT = - -# More obscure flags you might want to set for pswrap, yacc, lex, etc. -PSWFLAGS = -YFLAGS = -LFLAGS = - -## Delete this line if you want fast and loose cleans that will not remove -## things like precomps and user-defined OTHER_GARBAGE in subprojects. -CLEAN_ALL_SUBPROJECTS = YES - -## Add more obscure source files here to cause them to be automatically -## processed by the appropriate tool. Note that these files should also be -## added to "Supporting Files" in ProjectBuilder. The desired .o files that -## result from these files should also be added to OTHER_OFILES above so they -## will be linked in. - -# .msg files that should have msgwrap run on them -MSGFILES = -# .defs files that should have mig run on them -DEFSFILES = -# .mig files (no .defs files) that should have mig run on them -MIGFILES = - -## Add additional Help directories here (add them to the project as "Other -## Resources" in Project Builder) so that they will be compressed into .store -## files and copied into the app wrapper. If the help directories themselves -## need to also be in the app wrapper, then a cp command will need to be added -## in an after_install target. -OTHER_HELP_DIRS = - -# After you have saved your project using the 4.0 PB, you will automatically -# start using the makefiles in $(SYSTEM_DEVELOPER_DIR)/Makefiles/project. If you should -# need to revert back to the old 3.3 Makefile behavior, override MAKEFILEDIR to -# be $(SYSTEM_DEVELOPER_DIR)/Makefiles/app. - -# Don't add more rules here unless you want the first one to be the default -# target for make! Put all your targets in Makefile.postamble. - --include ../Makefile.include diff --git a/ftpd.tproj/PB.project b/ftpd.tproj/PB.project deleted file mode 100644 index 8739e8c..0000000 --- a/ftpd.tproj/PB.project +++ /dev/null @@ -1,40 +0,0 @@ -{ - FILESTABLE = { - C_FILES = (); - H_FILES = (ls.h, ls_extern.h, extern.h, pathnames.h); - M_FILES = (); - OTHER_LIBS = (); - OTHER_LINKED = (ftpcmd.y, ftpd.c, logwtmp.c, popen.c, vers.c, ls.c, cmp.c, util.c, print.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, ftpd.8); - PRECOMPILED_HEADERS = (); - PROJECT_HEADERS = (); - PUBLIC_HEADERS = (); - SUBPROJECTS = (); - }; - LANGUAGE = English; - LOCALIZABLE_FILES = {}; - NEXTSTEP_BUILDDIR = ""; - NEXTSTEP_BUILDTOOL = /bin/make; - NEXTSTEP_COMPILEROPTIONS = ""; - NEXTSTEP_INSTALLDIR = /usr/libexec; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_LINKEROPTIONS = ""; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; - PDO_UNIX_INSTALLDIR = /usr/libexec; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; - PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = ftpd; - PROJECTTYPE = Tool; - PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; - WINDOWS_INSTALLDIR = /usr/libexec; - WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; - WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; -} diff --git a/ftpd.tproj/cmp.c b/ftpd.tproj/cmp.c deleted file mode 100644 index 8b1c866..0000000 --- a/ftpd.tproj/cmp.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Michael Fischbein. - * - * 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. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)cmp.c 8.1 (Berkeley) 5/31/93"; -#else -static const char rcsid[] = - "$FreeBSD: src/bin/ls/cmp.c,v 1.9 1999/08/27 23:14:31 peter Exp $"; -#endif -#endif /* not lint */ - -#include -#include - -#include -#include - -#include "ls.h" -#include "ls_extern.h" - -int -namecmp(a, b) - const FTSENT *a, *b; -{ - return (strcoll(a->fts_name, b->fts_name)); -} - -int -revnamecmp(a, b) - const FTSENT *a, *b; -{ - return (strcoll(b->fts_name, a->fts_name)); -} - -int -modcmp(a, b) - const FTSENT *a, *b; -{ - return (b->fts_statp->st_mtime - a->fts_statp->st_mtime); -} - -int -revmodcmp(a, b) - const FTSENT *a, *b; -{ - return (a->fts_statp->st_mtime - b->fts_statp->st_mtime); -} - -int -acccmp(a, b) - const FTSENT *a, *b; -{ - return (b->fts_statp->st_atime - a->fts_statp->st_atime); -} - -int -revacccmp(a, b) - const FTSENT *a, *b; -{ - return (a->fts_statp->st_atime - b->fts_statp->st_atime); -} - -int -statcmp(a, b) - const FTSENT *a, *b; -{ - return (b->fts_statp->st_ctime - a->fts_statp->st_ctime); -} - -int -revstatcmp(a, b) - const FTSENT *a, *b; -{ - return (a->fts_statp->st_ctime - b->fts_statp->st_ctime); -} diff --git a/ftpd.tproj/extern.h b/ftpd.tproj/extern.h deleted file mode 100644 index d5f69d9..0000000 --- a/ftpd.tproj/extern.h +++ /dev/null @@ -1,89 +0,0 @@ -/*- - * Copyright (c) 1992, 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. - * - * @(#)extern.h 8.2 (Berkeley) 4/4/94 - * $FreeBSD: src/libexec/ftpd/extern.h,v 1.14 2000/01/27 09:28:19 shin Exp $ - */ - -void blkfree __P((char **)); -char **copyblk __P((char **)); -void cwd __P((char *)); -void delete __P((char *)); -void dologout __P((int)); -void fatal __P((char *)); -void ftpd_logwtmp __P((char *, char *, char *)); -int ftpd_pclose __P((FILE *)); -FILE *ftpd_popen __P((char *, char *)); -char *getline __P((char *, int, FILE *)); -void lreply __P((int, const char *, ...)); -void makedir __P((char *)); -void nack __P((char *)); -void pass __P((char *)); -void passive __P((void)); -void long_passive __P((char *, int)); -void perror_reply __P((int, char *)); -void pwd __P((void)); -void removedir __P((char *)); -void renamecmd __P((char *, char *)); -char *renamefrom __P((char *)); -void reply __P((int, const char *, ...)); -void retrieve __P((char *, char *)); -void send_file_list __P((char *)); -#ifdef OLD_SETPROCTITLE -void setproctitle __P((const char *, ...)); -#endif -void statcmd __P((void)); -void statfilecmd __P((char *)); -void store __P((char *, char *, int)); -void upper __P((char *)); -void user __P((char *)); -void yyerror __P((char *)); -int yyparse __P((void)); -#if defined(SKEY) && defined(_PWD_H_) /* XXX evil */ -char *skey_challenge __P((char *, struct passwd *, int)); -#endif -int ls_main __P((int, char **)); - -struct sockaddr_in; -struct sockaddr_in6; -union sockunion { - struct sockinet { - u_char si_len; - u_char si_family; - u_short si_port; - } su_si; - struct sockaddr_in su_sin; - struct sockaddr_in6 su_sin6; -}; -#define su_len su_si.si_len -#define su_family su_si.si_family -#define su_port su_si.si_port diff --git a/ftpd.tproj/ftpcmd.y b/ftpd.tproj/ftpcmd.y deleted file mode 100644 index 2ab1638..0000000 --- a/ftpd.tproj/ftpcmd.y +++ /dev/null @@ -1,1689 +0,0 @@ -/* - * Copyright (c) 1985, 1988, 1993, 1994 - * 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. - * - * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94 - */ - -/* - * Grammar for FTP commands. - * See RFC 959. - */ - -%{ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94"; -#endif -static const char rcsid[] = - "$FreeBSD: src/libexec/ftpd/ftpcmd.y,v 1.21 2001/02/19 21:51:26 des Exp $"; -#endif /* not lint */ - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include - -#include "extern.h" - -extern union sockunion data_dest, his_addr; -extern int logged_in; -extern struct passwd *pw; -extern int guest; -extern int paranoid; -extern int logging; -extern int type; -extern int form; -extern int debug; -extern int timeout; -extern int maxtimeout; -extern int pdata; -extern char *hostname; -extern char remotehost[]; -extern char proctitle[]; -extern int usedefault; -extern int transflag; -extern char tmpline[]; -extern int readonly; -extern int noepsv; - -off_t restart_point; - -static int cmd_type; -static int cmd_form; -static int cmd_bytesz; -char cbuf[512]; -char *fromname; - -#if defined(VIRTUAL_HOSTING) -extern int epsvall; -#endif - -%} - -%union { - int i; - char *s; -} - -%token - A B C E F I - L N P R S T - ALL - - SP CRLF COMMA - - USER PASS ACCT REIN QUIT PORT - PASV TYPE STRU MODE RETR STOR - APPE MLFL MAIL MSND MSOM MSAM - MRSQ MRCP ALLO REST RNFR RNTO - ABOR DELE CWD LIST NLST SITE - STAT HELP NOOP MKD RMD PWD - CDUP STOU SMNT SYST SIZE MDTM - LPRT LPSV EPRT EPSV - - UMASK IDLE CHMOD - - LEXERR - -%token STRING -%token NUMBER - -%type check_login octal_number byte_size -%type check_login_ro octal_number byte_size -%type check_login_epsv octal_number byte_size -%type struct_code mode_code type_code form_code -%type pathstring pathname password username ext_arg -%type ALL - -%start cmd_list - -%% - -cmd_list - : /* empty */ - | cmd_list cmd - { - fromname = (char *) 0; - restart_point = (off_t) 0; - } - | cmd_list rcmd - ; - -cmd - : USER SP username CRLF - { - user($3); - free($3); - } - | PASS SP password CRLF - { - pass($3); - free($3); - } - | PORT check_login SP host_port CRLF - { -#if defined(VIRTUAL_HOSTING) - if (epsvall) { - reply(501, "no PORT allowed after EPSV ALL"); - goto port_done; - } -#endif - if (!$2) - goto port_done; - if (port_check("PORT") == 1) - goto port_done; -#ifdef INET6 - if ((his_addr.su_family != AF_INET6 || - !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { - /* shoud never happen */ - usedefault = 1; - reply(500, "Invalid address rejected."); - goto port_done; - } - port_check_v6("pcmd"); -#endif - port_done: - } - | LPRT check_login SP host_long_port CRLF - { -#if defined(VIRTUAL_HOSTING) - if (epsvall) { - reply(501, "no LPRT allowed after EPSV ALL"); - goto lprt_done; - } -#endif - if (!$2) - goto lprt_done; - if (port_check("LPRT") == 1) - goto lprt_done; -#ifdef INET6 - if (his_addr.su_family != AF_INET6) { - usedefault = 1; - reply(500, "Invalid address rejected."); - goto lprt_done; - } - if (port_check_v6("LPRT") == 1) - goto lprt_done; -#endif - lprt_done: - } - | EPRT check_login SP STRING CRLF - { - char delim; - char *tmp = NULL; - char *p, *q; - char *result[3]; - struct addrinfo hints; - struct addrinfo *res; - int i; - -#if defined(VIRTUAL_HOSTING) - if (epsvall) { - reply(501, "no EPRT allowed after EPSV ALL"); - goto eprt_done; - } -#endif - if (!$2) - goto eprt_done; - - memset(&data_dest, 0, sizeof(data_dest)); - tmp = strdup($4); - if (debug) - syslog(LOG_DEBUG, "%s", tmp); - if (!tmp) { - fatal("not enough core"); - /*NOTREACHED*/ - } - p = tmp; - delim = p[0]; - p++; - memset(result, 0, sizeof(result)); - for (i = 0; i < 3; i++) { - q = strchr(p, delim); - if (!q || *q != delim) { - parsefail: - reply(500, - "Invalid argument, rejected."); - if (tmp) - free(tmp); - usedefault = 1; - goto eprt_done; - } - *q++ = '\0'; - result[i] = p; - if (debug) - syslog(LOG_DEBUG, "%d: %s", i, p); - p = q; - } - - /* some more sanity check */ - p = result[0]; - while (*p) { - if (!isdigit(*p)) - goto parsefail; - p++; - } - p = result[2]; - while (*p) { - if (!isdigit(*p)) - goto parsefail; - p++; - } - - /* grab address */ - memset(&hints, 0, sizeof(hints)); - if (atoi(result[0]) == 1) - hints.ai_family = PF_INET; -#ifdef INET6 - else if (atoi(result[0]) == 2) - hints.ai_family = PF_INET6; -#endif - else - hints.ai_family = PF_UNSPEC; /*XXX*/ - hints.ai_socktype = SOCK_STREAM; - i = getaddrinfo(result[1], result[2], &hints, &res); - if (i) - goto parsefail; - memcpy(&data_dest, res->ai_addr, res->ai_addrlen); -#ifdef INET6 - if (his_addr.su_family == AF_INET6 - && data_dest.su_family == AF_INET6) { - /* XXX more sanity checks! */ - data_dest.su_sin6.sin6_scope_id = - his_addr.su_sin6.sin6_scope_id; - } -#endif - free(tmp); - tmp = NULL; - - if (port_check("EPRT") == 1) - goto eprt_done; -#ifdef INET6 - if (his_addr.su_family != AF_INET6) { - usedefault = 1; - reply(500, "Invalid address rejected."); - goto eprt_done; - } - if (port_check_v6("EPRT") == 1) - goto eprt_done; -#endif - eprt_done:; - } - | PASV check_login CRLF - { -#if defined(VIRTUAL_HOSTING) - if (epsvall) - reply(501, "no PASV allowed after EPSV ALL"); - else -#endif - if ($2) - passive(); - } - | LPSV check_login CRLF - { -#if defined(VIRTUAL_HOSTING) - if (epsvall) - reply(501, "no LPSV allowed after EPSV ALL"); - else -#endif - if ($2) - long_passive("LPSV", PF_UNSPEC); - } - | EPSV check_login_epsv SP NUMBER CRLF - { - if ($2) { - int pf; - switch ($4) { - case 1: - pf = PF_INET; - break; -#ifdef INET6 - case 2: - pf = PF_INET6; - break; -#endif - default: - pf = -1; /*junk value*/ - break; - } - long_passive("EPSV", pf); - } - } - | EPSV check_login_epsv SP ALL CRLF - { - if ($2) { - reply(200, - "EPSV ALL command successful."); -#if defined(VIRTUAL_HOSTING) - epsvall++; -#endif - } - } - | EPSV check_login_epsv CRLF - { - if ($2) - long_passive("EPSV", PF_UNSPEC); - } - | TYPE check_login SP type_code CRLF - { - if ($2) { - switch (cmd_type) { - - case TYPE_A: - if (cmd_form == FORM_N) { - reply(200, "Type set to A."); - type = cmd_type; - form = cmd_form; - } else - reply(504, "Form must be N."); - break; - - case TYPE_E: - reply(504, "Type E not implemented."); - break; - - case TYPE_I: - reply(200, "Type set to I."); - type = cmd_type; - break; - - case TYPE_L: -#if NBBY == 8 - if (cmd_bytesz == 8) { - reply(200, - "Type set to L (byte size 8)."); - type = cmd_type; - } else - reply(504, "Byte size must be 8."); -#else /* NBBY == 8 */ - UNIMPLEMENTED for NBBY != 8 -#endif /* NBBY == 8 */ - } - } - } - | STRU check_login SP struct_code CRLF - { - if ($2) { - switch ($4) { - - case STRU_F: - reply(200, "STRU F ok."); - break; - - default: - reply(504, "Unimplemented STRU type."); - } - } - } - | MODE check_login SP mode_code CRLF - { - if ($2) { - switch ($4) { - - case MODE_S: - reply(200, "MODE S ok."); - break; - - default: - reply(502, "Unimplemented MODE type."); - } - } - } - | ALLO check_login SP NUMBER CRLF - { - if ($2) { - reply(202, "ALLO command ignored."); - } - } - | ALLO check_login SP NUMBER SP R SP NUMBER CRLF - { - if ($2) { - reply(202, "ALLO command ignored."); - } - } - | RETR check_login SP pathname CRLF - { - if ($2 && $4 != NULL) - retrieve((char *) 0, $4); - if ($4 != NULL) - free($4); - } - | STOR check_login_ro SP pathname CRLF - { - if ($2 && $4 != NULL) - store($4, "w", 0); - if ($4 != NULL) - free($4); - } - | APPE check_login_ro SP pathname CRLF - { - if ($2 && $4 != NULL) - store($4, "a", 0); - if ($4 != NULL) - free($4); - } - | NLST check_login CRLF - { - if ($2) - send_file_list("."); - } - | NLST check_login SP STRING CRLF - { - if ($2 && $4 != NULL) - send_file_list($4); - if ($4 != NULL) - free($4); - } - | LIST check_login CRLF - { - if ($2) - retrieve("/bin/ls -lgA", ""); - } - | LIST check_login SP pathname CRLF - { - if ($2 && $4 != NULL) - retrieve("/bin/ls -lgA %s", $4); - if ($4 != NULL) - free($4); - } - | STAT check_login SP pathname CRLF - { - if ($2 && $4 != NULL) - statfilecmd($4); - if ($4 != NULL) - free($4); - } - | STAT check_login CRLF - { - if ($2) { - statcmd(); - } - } - | DELE check_login_ro SP pathname CRLF - { - if ($2 && $4 != NULL) - delete($4); - if ($4 != NULL) - free($4); - } - | RNTO check_login_ro SP pathname CRLF - { - if ($2) { - if (fromname) { - renamecmd(fromname, $4); - free(fromname); - fromname = (char *) 0; - } else { - reply(503, "Bad sequence of commands."); - } - } - free($4); - } - | ABOR check_login CRLF - { - if ($2) - reply(225, "ABOR command successful."); - } - | CWD check_login CRLF - { - if ($2) { - if (guest) - cwd("/"); - else - cwd(pw->pw_dir); - } - } - | CWD check_login SP pathname CRLF - { - if ($2 && $4 != NULL) - cwd($4); - if ($4 != NULL) - free($4); - } - | HELP CRLF - { - help(cmdtab, (char *) 0); - } - | HELP SP STRING CRLF - { - char *cp = $3; - - if (strncasecmp(cp, "SITE", 4) == 0) { - cp = $3 + 4; - if (*cp == ' ') - cp++; - if (*cp) - help(sitetab, cp); - else - help(sitetab, (char *) 0); - } else - help(cmdtab, $3); - } - | NOOP CRLF - { - reply(200, "NOOP command successful."); - } - | MKD check_login_ro SP pathname CRLF - { - if ($2 && $4 != NULL) - makedir($4); - if ($4 != NULL) - free($4); - } - | RMD check_login_ro SP pathname CRLF - { - if ($2 && $4 != NULL) - removedir($4); - if ($4 != NULL) - free($4); - } - | PWD check_login CRLF - { - if ($2) - pwd(); - } - | CDUP check_login CRLF - { - if ($2) - cwd(".."); - } - | SITE SP HELP CRLF - { - help(sitetab, (char *) 0); - } - | SITE SP HELP SP STRING CRLF - { - help(sitetab, $5); - } - | SITE SP UMASK check_login CRLF - { - int oldmask; - - if ($4) { - oldmask = umask(0); - (void) umask(oldmask); - reply(200, "Current UMASK is %03o", oldmask); - } - } - | SITE SP UMASK check_login SP octal_number CRLF - { - int oldmask; - - if ($4) { - if (($6 == -1) || ($6 > 0777)) { - reply(501, "Bad UMASK value"); - } else { - oldmask = umask($6); - reply(200, - "UMASK set to %03o (was %03o)", - $6, oldmask); - } - } - } - | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF - { - if ($4 && ($8 != NULL)) { - if ($6 > 0777) - reply(501, - "CHMOD: Mode value must be between 0 and 0777"); - else if (chmod($8, $6) < 0) - perror_reply(550, $8); - else - reply(200, "CHMOD command successful."); - } - if ($8 != NULL) - free($8); - } - | SITE SP check_login IDLE CRLF - { - if ($3) - reply(200, - "Current IDLE time limit is %d seconds; max %d", - timeout, maxtimeout); - } - | SITE SP check_login IDLE SP NUMBER CRLF - { - if ($3) { - if ($6 < 30 || $6 > maxtimeout) { - reply(501, - "Maximum IDLE time must be between 30 and %d seconds", - maxtimeout); - } else { - timeout = $6; - (void) alarm((unsigned) timeout); - reply(200, - "Maximum IDLE time set to %d seconds", - timeout); - } - } - } - | STOU check_login_ro SP pathname CRLF - { - if ($2 && $4 != NULL) - store($4, "w", 1); - if ($4 != NULL) - free($4); - } - | SYST check_login CRLF - { - if ($2) -#if defined(unix) || defined(__APPLE__) -#ifdef BSD - reply(215, "UNIX Type: L%d Version: BSD-%d", - NBBY, BSD); -#else /* BSD */ - reply(215, "UNIX Type: L%d", NBBY); -#endif /* BSD */ -#else /* unix */ - reply(215, "UNKNOWN Type: L%d", NBBY); -#endif /* unix */ - } - - /* - * SIZE is not in RFC959, but Postel has blessed it and - * it will be in the updated RFC. - * - * Return size of file in a format suitable for - * using with RESTART (we just count bytes). - */ - | SIZE check_login SP pathname CRLF - { - if ($2 && $4 != NULL) - sizecmd($4); - if ($4 != NULL) - free($4); - } - - /* - * MDTM is not in RFC959, but Postel has blessed it and - * it will be in the updated RFC. - * - * Return modification time of file as an ISO 3307 - * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx - * where xxx is the fractional second (of any precision, - * not necessarily 3 digits) - */ - | MDTM check_login SP pathname CRLF - { - if ($2 && $4 != NULL) { - struct stat stbuf; - if (stat($4, &stbuf) < 0) - reply(550, "%s: %s", - $4, strerror(errno)); - else if (!S_ISREG(stbuf.st_mode)) { - reply(550, "%s: not a plain file.", $4); - } else { - struct tm *t; - t = gmtime(&stbuf.st_mtime); - reply(213, - "%04d%02d%02d%02d%02d%02d", - 1900 + t->tm_year, - t->tm_mon+1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); - } - } - if ($4 != NULL) - free($4); - } - | QUIT CRLF - { - reply(221, "Goodbye."); - dologout(0); - } - | error CRLF - { - yyerrok; - } - ; -rcmd - : RNFR check_login_ro SP pathname CRLF - { - char *renamefrom(); - - restart_point = (off_t) 0; - if ($2 && $4) { - fromname = renamefrom($4); - if (fromname == (char *) 0 && $4) { - free($4); - } - } - } - | REST check_login SP byte_size CRLF - { - if ($2) { - fromname = (char *) 0; - restart_point = $4; /* XXX $4 is only "int" */ - reply(350, "Restarting at %qd. %s", - restart_point, - "Send STORE or RETRIEVE to initiate transfer."); - } - } - ; - -username - : STRING - ; - -password - : /* empty */ - { - $$ = (char *)calloc(1, sizeof(char)); - } - | STRING - ; - -byte_size - : NUMBER - ; - -host_port - : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER COMMA NUMBER - { - char *a, *p; - - data_dest.su_len = sizeof(struct sockaddr_in); - data_dest.su_family = AF_INET; - p = (char *)&data_dest.su_sin.sin_port; - p[0] = $9; p[1] = $11; - a = (char *)&data_dest.su_sin.sin_addr; - a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; - } - ; - -host_long_port - : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER - { - char *a, *p; - - memset(&data_dest, 0, sizeof(data_dest)); - data_dest.su_len = sizeof(struct sockaddr_in6); - data_dest.su_family = AF_INET6; - p = (char *)&data_dest.su_port; - p[0] = $39; p[1] = $41; - a = (char *)&data_dest.su_sin6.sin6_addr; - a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11; - a[4] = $13; a[5] = $15; a[6] = $17; a[7] = $19; - a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27; - a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35; - if (his_addr.su_family == AF_INET6) { - /* XXX more sanity checks! */ - data_dest.su_sin6.sin6_scope_id = - his_addr.su_sin6.sin6_scope_id; - } - if ($1 != 6 || $3 != 16 || $37 != 2) - memset(&data_dest, 0, sizeof(data_dest)); - } - | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA - NUMBER - { - char *a, *p; - - memset(&data_dest, 0, sizeof(data_dest)); - data_dest.su_sin.sin_len = sizeof(struct sockaddr_in); - data_dest.su_family = AF_INET; - p = (char *)&data_dest.su_port; - p[0] = $15; p[1] = $17; - a = (char *)&data_dest.su_sin.sin_addr; - a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11; - if ($1 != 4 || $3 != 4 || $13 != 2) - memset(&data_dest, 0, sizeof(data_dest)); - } - ; - -form_code - : N - { - $$ = FORM_N; - } - | T - { - $$ = FORM_T; - } - | C - { - $$ = FORM_C; - } - ; - -type_code - : A - { - cmd_type = TYPE_A; - cmd_form = FORM_N; - } - | A SP form_code - { - cmd_type = TYPE_A; - cmd_form = $3; - } - | E - { - cmd_type = TYPE_E; - cmd_form = FORM_N; - } - | E SP form_code - { - cmd_type = TYPE_E; - cmd_form = $3; - } - | I - { - cmd_type = TYPE_I; - } - | L - { - cmd_type = TYPE_L; - cmd_bytesz = NBBY; - } - | L SP byte_size - { - cmd_type = TYPE_L; - cmd_bytesz = $3; - } - /* this is for a bug in the BBN ftp */ - | L byte_size - { - cmd_type = TYPE_L; - cmd_bytesz = $2; - } - ; - -struct_code - : F - { - $$ = STRU_F; - } - | R - { - $$ = STRU_R; - } - | P - { - $$ = STRU_P; - } - ; - -mode_code - : S - { - $$ = MODE_S; - } - | B - { - $$ = MODE_B; - } - | C - { - $$ = MODE_C; - } - ; - -pathname - : pathstring - { - /* - * Problem: this production is used for all pathname - * processing, but only gives a 550 error reply. - * This is a valid reply in some cases but not in others. - */ - if (logged_in && $1 && *$1 == '~') { - glob_t gl; - int flags = - GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - - memset(&gl, 0, sizeof(gl)); - if (glob($1, flags, NULL, &gl) || - gl.gl_pathc == 0) { - reply(550, "not found"); - $$ = NULL; - } else { - $$ = strdup(gl.gl_pathv[0]); - } - globfree(&gl); - free($1); - } else - $$ = $1; - } - ; - -pathstring - : STRING - ; - -octal_number - : NUMBER - { - int ret, dec, multby, digit; - - /* - * Convert a number that was read as decimal number - * to what it would be if it had been read as octal. - */ - dec = $1; - multby = 1; - ret = 0; - while (dec) { - digit = dec%10; - if (digit > 7) { - ret = -1; - break; - } - ret += digit * multby; - multby *= 8; - dec /= 10; - } - $$ = ret; - } - ; - - -check_login - : /* empty */ - { - $$ = check_login1(); - } - ; - -check_login_epsv - : /* empty */ - { - if (noepsv) { - reply(500, "EPSV command disabled"); - $$ = 0; - } - else - $$ = check_login1(); - } - ; - -check_login_ro - : /* empty */ - { - if (readonly) { - reply(550, "Permission denied."); - $$ = 0; - } - else - $$ = check_login1(); - } - ; - -%% - -extern jmp_buf errcatch; - -#define CMD 0 /* beginning of command */ -#define ARGS 1 /* expect miscellaneous arguments */ -#define STR1 2 /* expect SP followed by STRING */ -#define STR2 3 /* expect STRING */ -#define OSTR 4 /* optional SP then STRING */ -#define ZSTR1 5 /* SP then optional STRING */ -#define ZSTR2 6 /* optional STRING after SP */ -#define SITECMD 7 /* SITE command */ -#define NSTR 8 /* Number followed by a string */ - -struct tab { - char *name; - short token; - short state; - short implemented; /* 1 if command is implemented */ - char *help; -}; - -struct tab cmdtab[] = { /* In order defined in RFC 765 */ - { "USER", USER, STR1, 1, " username" }, - { "PASS", PASS, ZSTR1, 1, " password" }, - { "ACCT", ACCT, STR1, 0, "(specify account)" }, - { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, - { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, - { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, - { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4" }, - { "LPRT", LPRT, ARGS, 1, " af, hal, h1, h2, h3,..., pal, p1, p2..." }, - { "EPRT", EPRT, STR1, 1, " |af|addr|port|" }, - { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, - { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, - { "EPSV", EPSV, ARGS, 1, "[ af|ALL]" }, - { "TYPE", TYPE, ARGS, 1, " [ A | E | I | L ]" }, - { "STRU", STRU, ARGS, 1, "(specify file structure)" }, - { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, - { "RETR", RETR, STR1, 1, " file-name" }, - { "STOR", STOR, STR1, 1, " file-name" }, - { "APPE", APPE, STR1, 1, " file-name" }, - { "MLFL", MLFL, OSTR, 0, "(mail file)" }, - { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, - { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, - { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, - { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, - { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, - { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, - { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, - { "REST", REST, ARGS, 1, " offset (restart command)" }, - { "RNFR", RNFR, STR1, 1, " file-name" }, - { "RNTO", RNTO, STR1, 1, " file-name" }, - { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, - { "DELE", DELE, STR1, 1, " file-name" }, - { "CWD", CWD, OSTR, 1, "[ directory-name ]" }, - { "XCWD", CWD, OSTR, 1, "[ directory-name ]" }, - { "LIST", LIST, OSTR, 1, "[ path-name ]" }, - { "NLST", NLST, OSTR, 1, "[ path-name ]" }, - { "SITE", SITE, SITECMD, 1, "site-cmd [ arguments ]" }, - { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, - { "STAT", STAT, OSTR, 1, "[ path-name ]" }, - { "HELP", HELP, OSTR, 1, "[ ]" }, - { "NOOP", NOOP, ARGS, 1, "" }, - { "MKD", MKD, STR1, 1, " path-name" }, - { "XMKD", MKD, STR1, 1, " path-name" }, - { "RMD", RMD, STR1, 1, " path-name" }, - { "XRMD", RMD, STR1, 1, " path-name" }, - { "PWD", PWD, ARGS, 1, "(return current directory)" }, - { "XPWD", PWD, ARGS, 1, "(return current directory)" }, - { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, - { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, - { "STOU", STOU, STR1, 1, " file-name" }, - { "SIZE", SIZE, OSTR, 1, " path-name" }, - { "MDTM", MDTM, OSTR, 1, " path-name" }, - { NULL, 0, 0, 0, 0 } -}; - -struct tab sitetab[] = { - { "UMASK", UMASK, ARGS, 1, "[ umask ]" }, - { "IDLE", IDLE, ARGS, 1, "[ maximum-idle-time ]" }, - { "CHMOD", CHMOD, NSTR, 1, " mode file-name" }, - { "HELP", HELP, OSTR, 1, "[ ]" }, - { NULL, 0, 0, 0, 0 } -}; - -static char *copy __P((char *)); -static void help __P((struct tab *, char *)); -static struct tab * - lookup __P((struct tab *, char *)); -static int port_check __P((const char *)); -static int port_check_v6 __P((const char *)); -static void sizecmd __P((char *)); -static void toolong __P((int)); -static void v4map_data_dest __P((void)); -static int yylex __P((void)); - -static struct tab * -lookup(p, cmd) - struct tab *p; - char *cmd; -{ - - for (; p->name != NULL; p++) - if (strcmp(cmd, p->name) == 0) - return (p); - return (0); -} - -#include - -/* - * getline - a hacked up version of fgets to ignore TELNET escape codes. - */ -char * -getline(s, n, iop) - char *s; - int n; - FILE *iop; -{ - int c; - register char *cs; - - cs = s; -/* tmpline may contain saved command from urgent mode interruption */ - for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { - *cs++ = tmpline[c]; - if (tmpline[c] == '\n') { - *cs++ = '\0'; - if (debug) - syslog(LOG_DEBUG, "command: %s", s); - tmpline[0] = '\0'; - return(s); - } - if (c == 0) - tmpline[0] = '\0'; - } - while ((c = getc(iop)) != EOF) { - c &= 0377; - if (c == IAC) { - if ((c = getc(iop)) != EOF) { - c &= 0377; - switch (c) { - case WILL: - case WONT: - c = getc(iop); - printf("%c%c%c", IAC, DONT, 0377&c); - (void) fflush(stdout); - continue; - case DO: - case DONT: - c = getc(iop); - printf("%c%c%c", IAC, WONT, 0377&c); - (void) fflush(stdout); - continue; - case IAC: - break; - default: - continue; /* ignore command */ - } - } - } - *cs++ = c; - if (--n <= 0 || c == '\n') - break; - } - if (c == EOF && cs == s) - return (NULL); - *cs++ = '\0'; - if (debug) { - if (!guest && strncasecmp("pass ", s, 5) == 0) { - /* Don't syslog passwords */ - syslog(LOG_DEBUG, "command: %.5s ???", s); - } else { - register char *cp; - register int len; - - /* Don't syslog trailing CR-LF */ - len = strlen(s); - cp = s + len - 1; - while (cp >= s && (*cp == '\n' || *cp == '\r')) { - --cp; - --len; - } - syslog(LOG_DEBUG, "command: %.*s", len, s); - } - } - return (s); -} - -static void -toolong(signo) - int signo; -{ - - reply(421, - "Timeout (%d seconds): closing control connection.", timeout); - if (logging) - syslog(LOG_INFO, "User %s timed out after %d seconds", - (pw ? pw -> pw_name : "unknown"), timeout); - dologout(1); -} - -static int -yylex() -{ - static int cpos, state; - char *cp, *cp2; - struct tab *p; - int n; - char c; - - for (;;) { - switch (state) { - - case CMD: - (void) signal(SIGALRM, toolong); - (void) alarm((unsigned) timeout); - if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { - reply(221, "You could at least say goodbye."); - dologout(0); - } - (void) alarm(0); -#ifdef SETPROCTITLE - if (strncasecmp(cbuf, "PASS", 4) != 0) - setproctitle("%s: %s", proctitle, cbuf); -#endif /* SETPROCTITLE */ - if ((cp = strchr(cbuf, '\r'))) { - *cp++ = '\n'; - *cp = '\0'; - } - if ((cp = strpbrk(cbuf, " \n"))) - cpos = cp - cbuf; - if (cpos == 0) - cpos = 4; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - upper(cbuf); - p = lookup(cmdtab, cbuf); - cbuf[cpos] = c; - if (p != 0) { - if (p->implemented == 0) { - nack(p->name); - longjmp(errcatch,0); - /* NOTREACHED */ - } - state = p->state; - yylval.s = p->name; - return (p->token); - } - break; - - case SITECMD: - if (cbuf[cpos] == ' ') { - cpos++; - return (SP); - } - cp = &cbuf[cpos]; - if ((cp2 = strpbrk(cp, " \n"))) - cpos = cp2 - cbuf; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - upper(cp); - p = lookup(sitetab, cp); - cbuf[cpos] = c; - if (guest == 0 && p != 0) { - if (p->implemented == 0) { - state = CMD; - nack(p->name); - longjmp(errcatch,0); - /* NOTREACHED */ - } - state = p->state; - yylval.s = p->name; - return (p->token); - } - state = CMD; - break; - - case OSTR: - if (cbuf[cpos] == '\n') { - state = CMD; - return (CRLF); - } - /* FALLTHROUGH */ - - case STR1: - case ZSTR1: - dostr1: - if (cbuf[cpos] == ' ') { - cpos++; - state = state == OSTR ? STR2 : state+1; - return (SP); - } - break; - - case ZSTR2: - if (cbuf[cpos] == '\n') { - state = CMD; - return (CRLF); - } - /* FALLTHROUGH */ - - case STR2: - cp = &cbuf[cpos]; - n = strlen(cp); - cpos += n - 1; - /* - * Make sure the string is nonempty and \n terminated. - */ - if (n > 1 && cbuf[cpos] == '\n') { - cbuf[cpos] = '\0'; - yylval.s = copy(cp); - cbuf[cpos] = '\n'; - state = ARGS; - return (STRING); - } - break; - - case NSTR: - if (cbuf[cpos] == ' ') { - cpos++; - return (SP); - } - if (isdigit(cbuf[cpos])) { - cp = &cbuf[cpos]; - while (isdigit(cbuf[++cpos])) - ; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - yylval.i = atoi(cp); - cbuf[cpos] = c; - state = STR1; - return (NUMBER); - } - state = STR1; - goto dostr1; - - case ARGS: - if (isdigit(cbuf[cpos])) { - cp = &cbuf[cpos]; - while (isdigit(cbuf[++cpos])) - ; - c = cbuf[cpos]; - cbuf[cpos] = '\0'; - yylval.i = atoi(cp); - cbuf[cpos] = c; - return (NUMBER); - } - if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 - && !isalnum(cbuf[cpos + 3])) { - cpos += 3; - return ALL; - } - switch (cbuf[cpos++]) { - - case '\n': - state = CMD; - return (CRLF); - - case ' ': - return (SP); - - case ',': - return (COMMA); - - case 'A': - case 'a': - return (A); - - case 'B': - case 'b': - return (B); - - case 'C': - case 'c': - return (C); - - case 'E': - case 'e': - return (E); - - case 'F': - case 'f': - return (F); - - case 'I': - case 'i': - return (I); - - case 'L': - case 'l': - return (L); - - case 'N': - case 'n': - return (N); - - case 'P': - case 'p': - return (P); - - case 'R': - case 'r': - return (R); - - case 'S': - case 's': - return (S); - - case 'T': - case 't': - return (T); - - } - break; - - default: - fatal("Unknown state in scanner."); - } - yyerror((char *) 0); - state = CMD; - longjmp(errcatch,0); - } -} - -void -upper(s) - char *s; -{ - while (*s != '\0') { - if (islower(*s)) - *s = toupper(*s); - s++; - } -} - -static char * -copy(s) - char *s; -{ - char *p; - - p = malloc((unsigned) strlen(s) + 1); - if (p == NULL) - fatal("Ran out of memory."); - (void) strcpy(p, s); - return (p); -} - -static void -help(ctab, s) - struct tab *ctab; - char *s; -{ - struct tab *c; - int width, NCMDS; - char *type; - - if (ctab == sitetab) - type = "SITE "; - else - type = ""; - width = 0, NCMDS = 0; - for (c = ctab; c->name != NULL; c++) { - int len = strlen(c->name); - - if (len > width) - width = len; - NCMDS++; - } - width = (width + 8) &~ 7; - if (s == 0) { - int i, j, w; - int columns, lines; - - lreply(214, "The following %scommands are recognized %s.", - type, "(* =>'s unimplemented)"); - columns = 76 / width; - if (columns == 0) - columns = 1; - lines = (NCMDS + columns - 1) / columns; - for (i = 0; i < lines; i++) { - printf(" "); - for (j = 0; j < columns; j++) { - c = ctab + j * lines + i; - printf("%s%c", c->name, - c->implemented ? ' ' : '*'); - if (c + lines >= &ctab[NCMDS]) - break; - w = strlen(c->name) + 1; - while (w < width) { - putchar(' '); - w++; - } - } - printf("\r\n"); - } - (void) fflush(stdout); - reply(214, "Direct comments to ftp-bugs@%s.", hostname); - return; - } - upper(s); - c = lookup(ctab, s); - if (c == (struct tab *)0) { - reply(502, "Unknown command %s.", s); - return; - } - if (c->implemented) - reply(214, "Syntax: %s%s %s", type, c->name, c->help); - else - reply(214, "%s%-*s\t%s; unimplemented.", type, width, - c->name, c->help); -} - -static void -sizecmd(filename) - char *filename; -{ - switch (type) { - case TYPE_L: - case TYPE_I: { - struct stat stbuf; - if (stat(filename, &stbuf) < 0) - perror_reply(550, filename); - else if (!S_ISREG(stbuf.st_mode)) - reply(550, "%s: not a plain file.", filename); - else - reply(213, "%qu", stbuf.st_size); - break; } - case TYPE_A: { - FILE *fin; - int c; - off_t count; - struct stat stbuf; - fin = fopen(filename, "r"); - if (fin == NULL) { - perror_reply(550, filename); - return; - } - if (fstat(fileno(fin), &stbuf) < 0) { - perror_reply(550, filename); - (void) fclose(fin); - return; - } else if (!S_ISREG(stbuf.st_mode)) { - reply(550, "%s: not a plain file.", filename); - (void) fclose(fin); - return; - } - - count = 0; - while((c=getc(fin)) != EOF) { - if (c == '\n') /* will get expanded to \r\n */ - count++; - count++; - } - (void) fclose(fin); - - reply(213, "%qd", count); - break; } - default: - reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); - } -} - -/* Return 1, if port check is done. Return 0, if not yet. */ -static int -port_check(pcmd) - const char *pcmd; -{ - if (his_addr.su_family == AF_INET) { - if (data_dest.su_family != AF_INET) { - usedefault = 1; - reply(500, "Invalid address rejected."); - return 1; - } - if (paranoid && - ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || - memcmp(&data_dest.su_sin.sin_addr, - &his_addr.su_sin.sin_addr, - sizeof(data_dest.su_sin.sin_addr)))) { - usedefault = 1; - reply(500, "Illegal PORT range rejected."); - } else { - usedefault = 0; - if (pdata >= 0) { - (void) close(pdata); - pdata = -1; - } - reply(200, "%s command successful.", pcmd); - } - return 1; - } - return 0; -} - -static int -check_login1() -{ - if (logged_in) - return 1; - else { - reply(530, "Please login with USER and PASS."); - return 0; - } -} - -#ifdef INET6 -/* Return 1, if port check is done. Return 0, if not yet. */ -static int -port_check_v6(pcmd) - const char *pcmd; -{ - if (his_addr.su_family == AF_INET6) { - if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) - /* Convert data_dest into v4 mapped sockaddr.*/ - v4map_data_dest(); - if (data_dest.su_family != AF_INET6) { - usedefault = 1; - reply(500, "Invalid address rejected."); - return 1; - } - if (paranoid && - ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || - memcmp(&data_dest.su_sin6.sin6_addr, - &his_addr.su_sin6.sin6_addr, - sizeof(data_dest.su_sin6.sin6_addr)))) { - usedefault = 1; - reply(500, "Illegal PORT range rejected."); - } else { - usedefault = 0; - if (pdata >= 0) { - (void) close(pdata); - pdata = -1; - } - reply(200, "%s command successful.", pcmd); - } - return 1; - } - return 0; -} - -static void -v4map_data_dest() -{ - struct in_addr savedaddr; - int savedport; - - if (data_dest.su_family != AF_INET) { - usedefault = 1; - reply(500, "Invalid address rejected."); - return; - } - - savedaddr = data_dest.su_sin.sin_addr; - savedport = data_dest.su_port; - - memset(&data_dest, 0, sizeof(data_dest)); - data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); - data_dest.su_sin6.sin6_family = AF_INET6; - data_dest.su_sin6.sin6_port = savedport; - memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); - memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], - (caddr_t)&savedaddr, sizeof(savedaddr)); -} -#endif diff --git a/ftpd.tproj/ftpd.8 b/ftpd.tproj/ftpd.8 deleted file mode 100644 index f5bc1cc..0000000 --- a/ftpd.tproj/ftpd.8 +++ /dev/null @@ -1,481 +0,0 @@ -.\" Copyright (c) 1985, 1988, 1991, 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. -.\" -.\" @(#)ftpd.8 8.2 (Berkeley) 4/19/94 -.\" $FreeBSD: src/libexec/ftpd/ftpd.8,v 1.36 2000/12/18 08:33:25 ru Exp $ -.\" -.Dd January 27, 2000 -.Dt FTPD 8 -.Os BSD 4.2 -.Sh NAME -.Nm ftpd -.Nd -Internet File Transfer Protocol server -.Sh SYNOPSIS -.Nm -.Op Fl 4 -.Op Fl 6 -.Op Fl d -.Op Fl l Op Fl l -.Op Fl A -.Op Fl D -.Op Fl R -.Op Fl S -.Op Fl U -.Op Fl r -.Op Fl E -.Op Fl T Ar maxtimeout -.Op Fl t Ar timeout -.Op Fl a Ar address -.Op Fl p Ar file -.Sh DESCRIPTION -.Nm Ftpd -is the -Internet File Transfer Protocol -server process. The server uses the -.Tn TCP -protocol -and listens at the port specified in the -.Dq ftp -service specification; see -.Xr services 5 . -.Pp -Available options: -.Bl -tag -width indent -.It Fl d -Debugging information is written to the syslog using LOG_FTP. -.It Fl l -Each successful and failed -.Xr ftp 1 -session is logged using syslog with a facility of LOG_FTP. -If this option is specified twice, the retrieve (get), store (put), append, -delete, make directory, remove directory and rename operations and -their filename arguments are also logged. Note: LOG_FTP messages -are not displayed by -.Xr syslogd 8 -by default, and may have to be enabled in -.Xr syslogd 8 Ns 's -configuration file. -.It Fl D -With this option set, -.Nm -will detach and become a daemon, accepting connections on the FTP port and -forking children processes to handle them. -This is lower overhead than starting -.Nm -from -.Xr inetd 8 -and is thus useful on busy servers to reduce load. -.It Fl R -With this option set, -.Nm -will revert to historical behavior with regard to security checks on -user operations and restrictions on PORT requests. -Currently, -.Nm -will only honor PORT commands directed to unprivileged ports on the -remote user's host (which violates the FTP protocol specification but -closes some security holes). -.It Fl S -With this option set, -.Nm -logs all anonymous file downloads to the file -.Pa /var/log/ftpd -when this file exists. -.It Fl U -In previous versions of -.Nm , -when a passive mode client requested a data connection to the server, -the server would use data ports in the range 1024..4999. Now, by default, -the server will use data ports in the range 49152..65535. Specifying this -option will revert to the old behavior. -.It Fl T -A client may also request a different timeout period; -the maximum period allowed may be set to -.Ar timeout -seconds with the -.Fl T -option. -The default limit is 2 hours. -.It Fl t -The inactivity timeout period is set to -.Ar timeout -seconds (the default is 15 minutes). -.It Fl a -When -.Fl D -is specified, accept connections only on the specified -.Ar address . -.It Fl p -When -.Fl D -is specified, write the daemon's process ID to -.Ar file . -.It Fl 6 -When -.Fl D -is specified, accept connections via AF_INET6 socket. -.It Fl 4 -When -.Fl D -is specified, accept IPv4 connections. -When -.Fl 6 -is also specified, accept IPv4 connection via AF_INET6 socket. -When -.Fl 6 -is not specified, accept IPv4 connection via AF_INET socket. -.It Fl A -Allow only anonymous ftp access. -.It Fl r -Put server in read-only mode. -All commands which may modify the local filesystem are disabled. -.It Fl E -Disable the EPSV command. -This is useful for servers behind older firewalls. -.El -.Pp -The file -.Pa /var/run/nologin -can be used to disable ftp access. -If the file exists, -.Nm -displays it and exits. -If the file -.Pa /etc/ftpwelcome -exists, -.Nm -prints it before issuing the -.Dq ready -message. -If the file -.Pa /etc/ftpmotd -exists, -.Nm -prints it after a successful login. Note the motd file used is the one -relative to the login environment. This means the one in -.Pa ~ftp/etc -in the anonymous user's case. -.Pp -The ftp server currently supports the following ftp requests. -The case of the requests is ignored. Requests marked [RW] are -disabled if -.Fl r -is specified. -.Bl -column "Request" -offset indent -.It Sy Request Ta Sy "Description" -.It ABOR Ta "abort previous command" -.It ACCT Ta "specify account (ignored)" -.It ALLO Ta "allocate storage (vacuously)" -.It APPE Ta "append to a file [RW]" -.It CDUP Ta "change to parent of current working directory" -.It CWD Ta "change working directory" -.It DELE Ta "delete a file [RW]" -.It EPRT Ta "specify data connection port, multiprotocol" -.It EPSV Ta "prepare for server-to-server transfer, multiprotocol" -.It HELP Ta "give help information" -.It LIST Ta "give list files in a directory" Pq Dq Li "ls -lgA" -.It LPRT Ta "specify data connection port, multiprotocol" -.It LPSV Ta "prepare for server-to-server transfer, multiprotocol" -.It MDTM Ta "show last modification time of file" -.It MKD Ta "make a directory [RW]" -.It MODE Ta "specify data transfer" Em mode -.It NLST Ta "give name list of files in directory" -.It NOOP Ta "do nothing" -.It PASS Ta "specify password" -.It PASV Ta "prepare for server-to-server transfer" -.It PORT Ta "specify data connection port" -.It PWD Ta "print the current working directory" -.It QUIT Ta "terminate session" -.It REST Ta "restart incomplete transfer" -.It RETR Ta "retrieve a file" -.It RMD Ta "remove a directory [RW]" -.It RNFR Ta "specify rename-from file name [RW]" -.It RNTO Ta "specify rename-to file name [RW]" -.It SITE Ta "non-standard commands (see next section)" -.It SIZE Ta "return size of file" -.It STAT Ta "return status of server" -.It STOR Ta "store a file [RW]" -.It STOU Ta "store a file with a unique name [RW]" -.It STRU Ta "specify data transfer" Em structure -.It SYST Ta "show operating system type of server system" -.It TYPE Ta "specify data transfer" Em type -.It USER Ta "specify user name" -.It XCUP Ta "change to parent of current working directory (deprecated)" -.It XCWD Ta "change working directory (deprecated)" -.It XMKD Ta "make a directory (deprecated) [RW]" -.It XPWD Ta "print the current working directory (deprecated)" -.It XRMD Ta "remove a directory (deprecated) [RW]" -.El -.Pp -The following non-standard or -.Tn UNIX -specific commands are supported -by the -SITE request. -.Pp -.Bl -column Request -offset indent -.It Sy Request Ta Sy Description -.It UMASK Ta change umask, e.g. ``SITE UMASK 002'' -.It IDLE Ta set idle-timer, e.g. ``SITE IDLE 60'' -.It CHMOD Ta "change mode of a file [RW], e.g. ``SITE CHMOD 755 filename''" -.It HELP Ta give help information -.El -.Pp -The remaining ftp requests specified in Internet RFC 959 -are -recognized, but not implemented. -MDTM and SIZE are not specified in RFC 959, but will appear in the -next updated FTP RFC. -.Pp -The ftp server will abort an active file transfer only when the -ABOR -command is preceded by a Telnet "Interrupt Process" (IP) -signal and a Telnet "Synch" signal in the command Telnet stream, -as described in Internet RFC 959. -If a -STAT -command is received during a data transfer, preceded by a Telnet IP -and Synch, transfer status will be returned. -.Pp -.Nm Ftpd -interprets file names according to the -.Dq globbing -conventions used by -.Xr csh 1 . -This allows users to utilize the metacharacters -.Dq Li \&*?[]{}~ . -.Pp -.Nm Ftpd -authenticates users according to six rules. -.Pp -.Bl -enum -offset indent -.It -The login name must be in the password data base -and not have a null password. -In this case a password must be provided by the client before any -file operations may be performed. -If the user has an S/Key key, the response from a successful USER -command will include an S/Key challenge. -The client may choose to respond with a PASS command giving either -a standard password or an S/Key one-time password. -The server will automatically determine which type of -password it has been given and attempt to authenticate accordingly. -See -.Xr key 1 -for more information on S/Key authentication. -S/Key is a Trademark of Bellcore. -.It -The login name must not appear in the file -.Pa /etc/ftpusers . -.It -The login name must not be a member of a group specified in the file -.Pa /etc/ftpusers . -Entries in this file interpreted as group names are prefixed by an "at" -.Ql \&@ -sign. -.It -The user must have a standard shell returned by -.Xr getusershell 3 . -.It -If the user name appears in the file -.Pa /etc/ftpchroot , -or the user is a member of a group with a group entry in this file, -i.e. one prefixed with -.Ql \&@ , -the session's root will be changed to the user's login directory by -.Xr chroot 2 -as for an -.Dq anonymous -or -.Dq ftp -account (see next item). -This facility may also be triggered by enabling the boolean "ftp-chroot" -capability in -.Xr login.conf 5 . -However, the user must still supply a password. -This feature is intended as a compromise between a fully anonymous -account and a fully privileged account. -The account should also be set up as for an anonymous account. -.It -If the user name is -.Dq anonymous -or -.Dq ftp , -an -anonymous ftp account must be present in the password -file (user -.Dq ftp ) . -In this case the user is allowed -to log in by specifying any password (by convention an email address for -the user should be used as the password). -When the -.Fl S -option is set, all transfers are logged as well. -.El -.Pp -In the last case, -.Nm -takes special measures to restrict the client's access privileges. -The server performs a -.Xr chroot 2 -to the home directory of the -.Dq ftp -user. -In order that system security is not breached, it is recommended -that the -.Dq ftp -subtree be constructed with care, following these rules: -.Bl -tag -width "~ftp/pub" -offset indent -.It Pa ~ftp -Make the home directory owned by -.Dq root -and unwritable by anyone. -.It Pa ~ftp/etc -Make this directory owned by -.Dq root -and unwritable by anyone (mode 555). -The files pwd.db (see -.Xr passwd 5 ) -and -.Xr group 5 -must be present for the -.Xr ls -command to be able to produce owner names rather than numbers. -The password field in -.Xr passwd -is not used, and should not contain real passwords. -The file -.Pa ftpmotd , -if present, will be printed after a successful login. -These files should be mode 444. -.It Pa ~ftp/pub -Make this directory mode 777 and owned by -.Dq ftp . -Guests -can then place files which are to be accessible via the anonymous -account in this directory. -.El -.Pp -If the system has multiple IP addresses, -.Nm -supports the idea of virtual hosts, which provides the ability to -define multiple anonymous ftp areas, each one allocated to a different -internet address. -The file -.Pa /etc/ftphosts -contains information pertaining to each of the virtual hosts. -Each host is defined on its own line which contains a number of -fields separated by whitespace: -.Bl -tag -offset indent -width hostname -.It hostname -Contains the hostname or IP address of the virtual host. -.It user -Contains a user record in the system password file. -As with normal anonymous ftp, this user's access uid, gid and group -memberships determine file access to the anonymous ftp area. -The anonymous ftp area (to which any user is chrooted on login) -is determined by the home directory defined for the account. -User id and group for any ftp account may be the same as for the -standard ftp user. -.It statfile -File to which all file transfers are logged, which -defaults to -.Pa /var/log/ftpd . -.It welcome -This file is the welcome message displayed before the server ready -prompt. -It defaults to -.Pa /etc/ftpwelcome . -.It motd -This file is displayed after the user logs in. -It defaults to -.Pa /etc/ftpmotd . -.El -.Pp -Lines beginning with a '#' are ignored and can be used to include -comments. -.Pp -Defining a virtual host for the primary IP address or hostname -changes the default for ftp logins to that address. -The 'user', 'statfile', 'welcome' and 'motd' fields may be left -blank, or a single hypen '-' used to indicate that the default -value is to be used. -.Pp -As with any anonymous login configuration, due care must be given -to setup and maintenance to guard against security related problems. -.Pp -.Nm -has internal support for handling remote requests to list -files, and will not execute -.Pa /bin/ls -in either a chrooted or non-chrooted environment. The -.Pa ~/bin/ls -executable need not be placed into the chrooted tree, nor need the -.Pa ~/bin -directory exist. -.Sh FILES -.Bl -tag -width /etc/ftpwelcome -compact -.It Pa /etc/ftpusers -List of unwelcome/restricted users. -.It Pa /etc/ftpchroot -List of normal users who should be chroot'd. -.It Pa /etc/ftphosts -Virtual hosting configuration file. -.It Pa /etc/ftpwelcome -Welcome notice. -.It Pa /etc/ftpmotd -Welcome notice after login. -.It Pa /var/run/nologin -Displayed and access refused. -.It Pa /var/log/ftpd -Log file for anonymous transfers. -.El -.Sh SEE ALSO -.Xr ftp 1 , -.Xr key 1 , -.Xr getusershell 3 , -.Xr login.conf 5 , -.Xr inetd 8 , -.Xr syslogd 8 -.Sh BUGS -The server must run as the super-user -to create sockets with privileged port numbers. It maintains -an effective user id of the logged in user, reverting to -the super-user only when binding addresses to sockets. The -possible security holes have been extensively -scrutinized, but are possibly incomplete. -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.2 . -IPv6 support was added in WIDE Hydrangea IPv6 stack kit. diff --git a/ftpd.tproj/ftpd.c b/ftpd.tproj/ftpd.c deleted file mode 100644 index 0a32ddf..0000000 --- a/ftpd.tproj/ftpd.c +++ /dev/null @@ -1,2923 +0,0 @@ -/* - * Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994 - * 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 0 -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1985, 1988, 1990, 1992, 1993, 1994\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ -#endif - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)ftpd.c 8.4 (Berkeley) 4/16/94"; -#endif -static const char rcsid[] = - "$FreeBSD: src/libexec/ftpd/ftpd.c,v 1.75 2001/03/27 19:40:50 markm Exp $"; -#endif /* not lint */ - -/* - * FTP server. - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define FTP_NAMES -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// #include -#ifdef LOGIN_CAP -#include -#endif - -#ifdef SKEY -#include -#endif - -#ifdef USE_PAM -#include -#endif - -#include "pathnames.h" -#include "extern.h" - -#if __STDC__ -#include -#else -#include -#endif - -static char version[] = "Version 6.00LS"; -#undef main - -/* wrapper for KAME-special getnameinfo() */ -#ifndef NI_WITHSCOPEID -#define NI_WITHSCOPEID 0 -#endif - -extern off_t restart_point; -extern char cbuf[]; - -union sockunion server_addr; -union sockunion ctrl_addr; -union sockunion data_source; -union sockunion data_dest; -union sockunion his_addr; -union sockunion pasv_addr; - -int daemon_mode; -int data; -jmp_buf errcatch, urgcatch; -int logged_in; -struct passwd *pw; -int debug; -int timeout = 900; /* timeout after 15 minutes of inactivity */ -int maxtimeout = 7200;/* don't allow idle time to be set beyond 2 hours */ -int logging; -int restricted_data_ports = 1; -int paranoid = 1; /* be extra careful about security */ -int anon_only = 0; /* Only anonymous ftp allowed */ -int guest; -int dochroot; -int stats; -int statfd = -1; -int type; -int form; -int stru; /* avoid C keyword */ -int mode; -int usedefault = 1; /* for data transfers */ -int pdata = -1; /* for passive mode */ -int readonly=0; /* Server is in readonly mode. */ -int noepsv=0; /* EPSV command is disabled. */ -sig_atomic_t transflag; -off_t file_size; -off_t byte_count; -#if !defined(CMASK) || CMASK == 0 -#undef CMASK -#define CMASK 027 -#endif -int defumask = CMASK; /* default umask value */ -char tmpline[7]; -char *hostname; -#ifdef VIRTUAL_HOSTING -char *ftpuser; - -int epsvall = 0; - -static struct ftphost { - struct ftphost *next; - struct addrinfo *hostinfo; - char *hostname; - char *anonuser; - char *statfile; - char *welcome; - char *loginmsg; -} *thishost, *firsthost; - -#endif -char remotehost[MAXHOSTNAMELEN]; -char *ident = NULL; - -static char ttyline[20]; -char *tty = ttyline; /* for klogin */ - -#ifdef USE_PAM -static int auth_pam __P((struct passwd**, const char*)); -pam_handle_t *pamh = NULL; -#endif - -char *pid_file = NULL; - -/* - * Limit number of pathnames that glob can return. - * A limit of 0 indicates the number of pathnames is unlimited. - */ -#define MAXGLOBARGS 16384 -# - -/* - * Timeout intervals for retrying connections - * to hosts that don't accept PORT cmds. This - * is a kludge, but given the problems with TCP... - */ -#define SWAITMAX 90 /* wait at most 90 seconds */ -#define SWAITINT 5 /* interval between retries */ - -int swaitmax = SWAITMAX; -int swaitint = SWAITINT; - -#ifdef SETPROCTITLE -#ifdef OLD_SETPROCTITLE -char **Argv = NULL; /* pointer to argument vector */ -char *LastArgv = NULL; /* end of argv */ -#endif /* OLD_SETPROCTITLE */ -char proctitle[LINE_MAX]; /* initial part of title */ -#endif /* SETPROCTITLE */ - -#ifdef SKEY -int pwok = 0; -#endif - -#define LOGCMD(cmd, file) \ - if (logging > 1) \ - syslog(LOG_INFO,"%s %s%s", cmd, \ - *(file) == '/' ? "" : curdir(), file); -#define LOGCMD2(cmd, file1, file2) \ - if (logging > 1) \ - syslog(LOG_INFO,"%s %s%s %s%s", cmd, \ - *(file1) == '/' ? "" : curdir(), file1, \ - *(file2) == '/' ? "" : curdir(), file2); -#define LOGBYTES(cmd, file, cnt) \ - if (logging > 1) { \ - if (cnt == (off_t)-1) \ - syslog(LOG_INFO,"%s %s%s", cmd, \ - *(file) == '/' ? "" : curdir(), file); \ - else \ - syslog(LOG_INFO, "%s %s%s = %qd bytes", \ - cmd, (*(file) == '/') ? "" : curdir(), file, cnt); \ - } - -#ifdef VIRTUAL_HOSTING -static void inithosts __P((void)); -static void selecthost __P((union sockunion *)); -#endif -static void ack __P((char *)); -static void myoob __P((int)); -static int checkuser __P((char *, char *, int)); -static FILE *dataconn __P((char *, off_t, char *)); -static void dolog __P((struct sockaddr *)); -static char *curdir __P((void)); -static void end_login __P((void)); -static FILE *getdatasock __P((char *)); -static char *gunique __P((char *)); -static void lostconn __P((int)); -static int receive_data __P((FILE *, FILE *)); -static void send_data __P((FILE *, FILE *, off_t, off_t, int)); -static struct passwd * - sgetpwnam __P((char *)); -static char *sgetsave __P((char *)); -static void reapchild __P((int)); -static void logxfer __P((char *, long, long)); - -static char * -curdir() -{ - static char path[MAXPATHLEN+1+1]; /* path + '/' + '\0' */ - - if (getcwd(path, sizeof(path)-2) == NULL) - return (""); - if (path[1] != '\0') /* special case for root dir. */ - strcat(path, "/"); - /* For guest account, skip / since it's chrooted */ - return (guest ? path+1 : path); -} - -int -main(argc, argv, envp) - int argc; - char *argv[]; - char **envp; -{ - int addrlen, ch, on = 1, tos; - char *cp, line[LINE_MAX]; - FILE *fd; - int error; - char *bindname = NULL; - int family = AF_UNSPEC; - int enable_v4 = 0; - - tzset(); /* in case no timezone database in ~ftp */ - -#ifdef OLD_SETPROCTITLE - /* - * Save start and extent of argv for setproctitle. - */ - Argv = argv; - while (*envp) - envp++; - LastArgv = envp[-1] + strlen(envp[-1]); -#endif /* OLD_SETPROCTITLE */ - - - while ((ch = getopt(argc, argv, "AdlDESURrt:T:u:va:p:46")) != -1) { - switch (ch) { - case 'D': - daemon_mode++; - break; - - case 'd': - debug++; - break; - - case 'E': - noepsv = 1; - break; - - case 'l': - logging++; /* > 1 == extra logging */ - break; - - case 'r': - readonly = 1; - break; - - case 'R': - paranoid = 0; - break; - - case 'S': - stats++; - break; - - case 'T': - maxtimeout = atoi(optarg); - if (timeout > maxtimeout) - timeout = maxtimeout; - break; - - case 't': - timeout = atoi(optarg); - if (maxtimeout < timeout) - maxtimeout = timeout; - break; - - case 'U': - restricted_data_ports = 0; - break; - - case 'a': - bindname = optarg; - break; - - case 'p': - pid_file = optarg; - break; - - case 'u': - { - long val = 0; - - val = strtol(optarg, &optarg, 8); - if (*optarg != '\0' || val < 0) - warnx("bad value for -u"); - else - defumask = val; - break; - } - case 'A': - anon_only = 1; - break; - - case 'v': - debug = 1; - break; - - case '4': - enable_v4 = 1; - if (family == AF_UNSPEC) - family = AF_INET; - break; - - case '6': - family = AF_INET6; - break; - - default: - warnx("unknown flag -%c ignored", optopt); - break; - } - } - -#ifdef VIRTUAL_HOSTING - inithosts(); -#endif - (void) freopen(_PATH_DEVNULL, "w", stderr); - - /* - * LOG_NDELAY sets up the logging connection immediately, - * necessary for anonymous ftp's that chroot and can't do it later. - */ - openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); - - if (daemon_mode) { - int ctl_sock, fd; - struct addrinfo hints, *res; - - /* - * Detach from parent. - */ - if (daemon(1, 1) < 0) { - syslog(LOG_ERR, "failed to become a daemon"); - exit(1); - } - (void) signal(SIGCHLD, reapchild); - /* init bind_sa */ - memset(&hints, 0, sizeof(hints)); - - hints.ai_family = family == AF_UNSPEC ? AF_INET : family; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - hints.ai_flags = AI_PASSIVE; - error = getaddrinfo(bindname, "ftp", &hints, &res); - if (error) { - if (family == AF_UNSPEC) { - hints.ai_family = AF_UNSPEC; - error = getaddrinfo(bindname, "ftp", &hints, - &res); - } - } - if (error) { - syslog(LOG_ERR, "%s", gai_strerror(error)); - if (error == EAI_SYSTEM) - syslog(LOG_ERR, "%s", strerror(errno)); - exit(1); - } - if (res->ai_addr == NULL) { - syslog(LOG_ERR, "-a %s: getaddrinfo failed", hostname); - exit(1); - } else - family = res->ai_addr->sa_family; - /* - * Open a socket, bind it to the FTP port, and start - * listening. - */ - ctl_sock = socket(family, SOCK_STREAM, 0); - if (ctl_sock < 0) { - syslog(LOG_ERR, "control socket: %m"); - exit(1); - } - if (setsockopt(ctl_sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "control setsockopt: %m"); -#ifdef IPV6_BINDV6ONLY - if (family == AF_INET6 && enable_v4 == 0) { - if (setsockopt(ctl_sock, IPPROTO_IPV6, IPV6_BINDV6ONLY, - (char *)&on, sizeof (on)) < 0) - syslog(LOG_ERR, - "control setsockopt(IPV6_BINDV6ONLY): %m"); - } -#endif /* IPV6_BINDV6ONLY */ - memcpy(&server_addr, res->ai_addr, res->ai_addr->sa_len); - if (bind(ctl_sock, (struct sockaddr *)&server_addr, - server_addr.su_len) < 0) { - syslog(LOG_ERR, "control bind: %m"); - exit(1); - } - if (listen(ctl_sock, 32) < 0) { - syslog(LOG_ERR, "control listen: %m"); - exit(1); - } - /* - * Atomically write process ID - */ - if (pid_file) - { - int fd; - char buf[20]; - - fd = open(pid_file, O_CREAT | O_WRONLY | O_TRUNC - | O_NONBLOCK | O_EXLOCK, 0644); - if (fd < 0) { - if (errno == EAGAIN) - errx(1, "%s: file locked", pid_file); - else - err(1, "%s", pid_file); - } - snprintf(buf, sizeof(buf), - "%lu\n", (unsigned long) getpid()); - if (write(fd, buf, strlen(buf)) < 0) - err(1, "%s: write", pid_file); - /* Leave the pid file open and locked */ - } - /* - * Loop forever accepting connection requests and forking off - * children to handle them. - */ - while (1) { - addrlen = server_addr.su_len; - fd = accept(ctl_sock, (struct sockaddr *)&his_addr, &addrlen); - if (fork() == 0) { - /* child */ - (void) dup2(fd, 0); - (void) dup2(fd, 1); - close(ctl_sock); - break; - } - close(fd); - } - } else { - addrlen = sizeof(his_addr); - if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); - exit(1); - } - } - - (void) signal(SIGCHLD, SIG_IGN); - (void) signal(SIGPIPE, lostconn); - if (signal(SIGURG, myoob) == SIG_ERR) - syslog(LOG_ERR, "signal: %m"); - - addrlen = sizeof(ctrl_addr); - if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { - syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); - exit(1); - } -#ifdef VIRTUAL_HOSTING - /* select our identity from virtual host table */ - selecthost(&ctrl_addr); -#endif -#ifdef IP_TOS - if (ctrl_addr.su_family == AF_INET) - { - tos = IPTOS_LOWDELAY; - if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); - } -#endif - /* - * Disable Nagle on the control channel so that we don't have to wait - * for peer's ACK before issuing our next reply. - */ - if (setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) - syslog(LOG_WARNING, "control setsockopt TCP_NODELAY: %m"); - - data_source.su_port = htons(ntohs(ctrl_addr.su_port) - 1); - - /* set this here so klogin can use it... */ - (void)snprintf(ttyline, sizeof(ttyline), "ftp%d", getpid()); - - /* Try to handle urgent data inline */ -#ifdef SO_OOBINLINE - if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) - syslog(LOG_ERR, "setsockopt: %m"); -#endif - -#ifdef F_SETOWN - if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) - syslog(LOG_ERR, "fcntl F_SETOWN: %m"); -#endif - dolog((struct sockaddr *)&his_addr); - /* - * Set up default state - */ - data = -1; - type = TYPE_A; - form = FORM_N; - stru = STRU_F; - mode = MODE_S; - tmpline[0] = '\0'; - - /* If logins are disabled, print out the message. */ - if ((fd = fopen(_PATH_NOLOGIN,"r")) != NULL) { - while (fgets(line, sizeof(line), fd) != NULL) { - if ((cp = strchr(line, '\n')) != NULL) - *cp = '\0'; - lreply(530, "%s", line); - } - (void) fflush(stdout); - (void) fclose(fd); - reply(530, "System not available."); - exit(0); - } -#ifdef VIRTUAL_HOSTING - if ((fd = fopen(thishost->welcome, "r")) != NULL) { -#else - if ((fd = fopen(_PATH_FTPWELCOME, "r")) != NULL) { -#endif - while (fgets(line, sizeof(line), fd) != NULL) { - if ((cp = strchr(line, '\n')) != NULL) - *cp = '\0'; - lreply(220, "%s", line); - } - (void) fflush(stdout); - (void) fclose(fd); - /* reply(220,) must follow */ - } -#ifndef VIRTUAL_HOSTING - if ((hostname = malloc(MAXHOSTNAMELEN)) == NULL) - fatal("Ran out of memory."); - (void) gethostname(hostname, MAXHOSTNAMELEN - 1); - hostname[MAXHOSTNAMELEN - 1] = '\0'; -#endif - reply(220, "%s FTP server (%s) ready.", hostname, version); - (void) setjmp(errcatch); - for (;;) - (void) yyparse(); - /* NOTREACHED */ -} - -static void -lostconn(signo) - int signo; -{ - - if (debug) - syslog(LOG_DEBUG, "lost connection"); - dologout(1); -} - -#ifdef VIRTUAL_HOSTING -/* - * read in virtual host tables (if they exist) - */ - -static void -inithosts() -{ - FILE *fp; - char *cp; - struct ftphost *hrp, *lhrp; - char line[1024]; - struct addrinfo hints, *res, *ai; - - /* - * Fill in the default host information - */ - if (gethostname(line, sizeof(line)) < 0) - line[0] = '\0'; - if ((hrp = malloc(sizeof(struct ftphost))) == NULL || - (hrp->hostname = strdup(line)) == NULL) - fatal("Ran out of memory."); - hrp->hostinfo = NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; - hints.ai_family = AF_UNSPEC; - getaddrinfo(hrp->hostname, NULL, &hints, &res); - if (res) - hrp->hostinfo = res; - hrp->statfile = _PATH_FTPDSTATFILE; - hrp->welcome = _PATH_FTPWELCOME; - hrp->loginmsg = _PATH_FTPLOGINMESG; - hrp->anonuser = "ftp"; - hrp->next = NULL; - thishost = firsthost = lhrp = hrp; - if ((fp = fopen(_PATH_FTPHOSTS, "r")) != NULL) { - int addrsize, error, gothost; - void *addr; - struct hostent *hp; - - while (fgets(line, sizeof(line), fp) != NULL) { - int i, hp_error; - - if ((cp = strchr(line, '\n')) == NULL) { - /* ignore long lines */ - while (fgets(line, sizeof(line), fp) != NULL && - strchr(line, '\n') == NULL) - ; - continue; - } - *cp = '\0'; - cp = strtok(line, " \t"); - /* skip comments and empty lines */ - if (cp == NULL || line[0] == '#') - continue; - - hints.ai_flags = 0; - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_PASSIVE; - error = getaddrinfo(cp, NULL, &hints, &res); - if (error != NULL) - continue; - for (ai = res; ai != NULL && ai->ai_addr != NULL; - ai = ai->ai_next) { - - gothost = 0; - for (hrp = firsthost; hrp != NULL; hrp = hrp->next) { - struct addrinfo *hi; - - for (hi = hrp->hostinfo; hi != NULL; - hi = hi->ai_next) - if (hi->ai_addrlen == ai->ai_addrlen && - memcmp(hi->ai_addr, - ai->ai_addr, - ai->ai_addr->sa_len) == 0) { - gothost++; - break; - } - if (gothost) - break; - } - if (hrp == NULL) { - if ((hrp = malloc(sizeof(struct ftphost))) == NULL) - continue; - /* defaults */ - hrp->statfile = _PATH_FTPDSTATFILE; - hrp->welcome = _PATH_FTPWELCOME; - hrp->loginmsg = _PATH_FTPLOGINMESG; - hrp->anonuser = "ftp"; - hrp->next = NULL; - lhrp->next = hrp; - lhrp = hrp; - } - hrp->hostinfo = res; - - /* - * determine hostname to use. - * force defined name if there is a valid alias - * otherwise fallback to primary hostname - */ - /* XXX: getaddrinfo() can't do alias check */ - switch(hrp->hostinfo->ai_family) { - case AF_INET: - addr = &((struct sockaddr_in *)&hrp->hostinfo->ai_addr)->sin_addr; - addrsize = sizeof(struct sockaddr_in); - break; - case AF_INET6: - addr = &((struct sockaddr_in6 *)&hrp->hostinfo->ai_addr)->sin6_addr; - addrsize = sizeof(struct sockaddr_in6); - break; - default: - /* should not reach here */ - if (hrp->hostinfo != NULL) - freeaddrinfo(hrp->hostinfo); - free(hrp); - continue; - /* NOTREACHED */ - } - if ((hp = getipnodebyaddr((char*)addr, addrsize, - hrp->hostinfo->ai_family, - &hp_error)) != NULL) { - if (strcmp(cp, hp->h_name) != 0) { - if (hp->h_aliases == NULL) - cp = hp->h_name; - else { - i = 0; - while (hp->h_aliases[i] && - strcmp(cp, hp->h_aliases[i]) != 0) - ++i; - if (hp->h_aliases[i] == NULL) - cp = hp->h_name; - } - } - } - hrp->hostname = strdup(cp); - freehostent(hp); - /* ok, now we now peel off the rest */ - i = 0; - while (i < 4 && (cp = strtok(NULL, " \t")) != NULL) { - if (*cp != '-' && (cp = strdup(cp)) != NULL) { - switch (i) { - case 0: /* anon user permissions */ - hrp->anonuser = cp; - break; - case 1: /* statistics file */ - hrp->statfile = cp; - break; - case 2: /* welcome message */ - hrp->welcome = cp; - break; - case 3: /* login message */ - hrp->loginmsg = cp; - break; - } - } - ++i; - } - /* XXX: re-initialization for getaddrinfo() loop */ - cp = strtok(line, " \t"); - } - } - (void) fclose(fp); - } -} - -static void -selecthost(su) - union sockunion *su; -{ - struct ftphost *hrp; - u_int16_t port; -#ifdef INET6 - struct in6_addr *mapped_in6 = NULL; -#endif - struct addrinfo *hi; - -#ifdef INET6 - /* - * XXX IPv4 mapped IPv6 addr consideraton, - * specified in rfc2373. - */ - if (su->su_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&su->su_sin6.sin6_addr)) - mapped_in6 = &su->su_sin6.sin6_addr; -#endif - - hrp = thishost = firsthost; /* default */ - port = su->su_port; - su->su_port = 0; - while (hrp != NULL) { - for (hi = hrp->hostinfo; hi != NULL; hi = hi->ai_next) { - if (memcmp(su, hi->ai_addr, hi->ai_addrlen) == 0) { - thishost = hrp; - break; - } -#ifdef INET6 - /* XXX IPv4 mapped IPv6 addr consideraton */ - if (hi->ai_addr->sa_family == AF_INET && mapped_in6 != NULL && - (memcmp(&mapped_in6->s6_addr[12], - &((struct sockaddr_in *)hi->ai_addr)->sin_addr, - sizeof(struct in_addr)) == 0)) { - thishost = hrp; - break; - } -#endif - } - hrp = hrp->next; - } - su->su_port = port; - /* setup static variables as appropriate */ - hostname = thishost->hostname; - ftpuser = thishost->anonuser; -} -#endif - -/* - * Helper function for sgetpwnam(). - */ -static char * -sgetsave(s) - char *s; -{ - char *new = malloc((unsigned) strlen(s) + 1); - - if (new == NULL) { - perror_reply(421, "Local resource failure: malloc"); - dologout(1); - /* NOTREACHED */ - } - (void) strcpy(new, s); - return (new); -} - -/* - * Save the result of a getpwnam. Used for USER command, since - * the data returned must not be clobbered by any other command - * (e.g., globbing). - */ -static struct passwd * -sgetpwnam(name) - char *name; -{ - static struct passwd save; - struct passwd *p; - - if ((p = getpwnam(name)) == NULL) - return (p); - if (save.pw_name) { - free(save.pw_name); - free(save.pw_passwd); - free(save.pw_gecos); - free(save.pw_dir); - free(save.pw_shell); - } - save = *p; - save.pw_name = sgetsave(p->pw_name); - save.pw_passwd = sgetsave(p->pw_passwd); - save.pw_gecos = sgetsave(p->pw_gecos); - save.pw_dir = sgetsave(p->pw_dir); - save.pw_shell = sgetsave(p->pw_shell); - return (&save); -} - -static int login_attempts; /* number of failed login attempts */ -static int askpasswd; /* had user command, ask for passwd */ -static char curname[MAXLOGNAME]; /* current USER name */ - -/* - * USER command. - * Sets global passwd pointer pw if named account exists and is acceptable; - * sets askpasswd if a PASS command is expected. If logged in previously, - * need to reset state. If name is "ftp" or "anonymous", the name is not in - * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return. - * If account doesn't exist, ask for passwd anyway. Otherwise, check user - * requesting login privileges. Disallow anyone who does not have a standard - * shell as returned by getusershell(). Disallow anyone mentioned in the file - * _PATH_FTPUSERS to allow people such as root and uucp to be avoided. - */ -void -user(name) - char *name; -{ - char *cp, *shell; - - if (logged_in) { - if (guest) { - reply(530, "Can't change user from guest login."); - return; - } else if (dochroot) { - reply(530, "Can't change user from chroot user."); - return; - } - end_login(); - } - - guest = 0; - if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { -#if !defined(_PATH_FTPUSERS) -#define _PATH_FTPUSERS "/etc/ftpusers" -#endif - if (checkuser(_PATH_FTPUSERS, "ftp", 0) || - checkuser(_PATH_FTPUSERS, "anonymous", 0)) - reply(530, "User %s access denied.", name); -#ifdef VIRTUAL_HOSTING - else if ((pw = sgetpwnam(thishost->anonuser)) != NULL) { -#else - else if ((pw = sgetpwnam("ftp")) != NULL) { -#endif - guest = 1; - askpasswd = 1; - reply(331, - "Guest login ok, send your email address as password."); - } else - reply(530, "User %s unknown.", name); - if (!askpasswd && logging) - syslog(LOG_NOTICE, - "ANONYMOUS FTP LOGIN REFUSED FROM %s", remotehost); - return; - } - if (anon_only != 0) { - reply(530, "Sorry, only anonymous ftp allowed."); - return; - } - - if ((pw = sgetpwnam(name))) { - if ((shell = pw->pw_shell) == NULL || *shell == 0) - shell = _PATH_BSHELL; - while ((cp = getusershell()) != NULL) - if (strcmp(cp, shell) == 0) - break; - endusershell(); - - if (cp == NULL || checkuser(_PATH_FTPUSERS, name, 1)) { - reply(530, "User %s access denied.", name); - if (logging) - syslog(LOG_NOTICE, - "FTP LOGIN REFUSED FROM %s, %s", - remotehost, name); - pw = (struct passwd *) NULL; - return; - } - } - if (logging) - strncpy(curname, name, sizeof(curname)-1); -#ifdef SKEY - pwok = skeyaccess(name, NULL, remotehost, remotehost); - reply(331, "%s", skey_challenge(name, pw, pwok)); -#else - reply(331, "Password required for %s.", name); -#endif - askpasswd = 1; - /* - * Delay before reading passwd after first failed - * attempt to slow down passwd-guessing programs. - */ - if (login_attempts) - sleep((unsigned) login_attempts); -} - -/* - * Check if a user is in the file "fname" - */ -static int -checkuser(fname, name, pwset) - char *fname; - char *name; - int pwset; -{ - FILE *fd; - int found = 0; - char *p, line[BUFSIZ]; - - if ((fd = fopen(fname, "r")) != NULL) { - while (!found && fgets(line, sizeof(line), fd) != NULL) - if ((p = strchr(line, '\n')) != NULL) { - *p = '\0'; - if (line[0] == '#') - continue; - /* - * if first chr is '@', check group membership - */ - if (line[0] == '@') { - int i = 0; - struct group *grp; - - if ((grp = getgrnam(line+1)) == NULL) - continue; - /* - * Check user's default group - */ - if (pwset && grp->gr_gid == pw->pw_gid) - found = 1; - /* - * Check supplementary groups - */ - while (!found && grp->gr_mem[i]) - found = strcmp(name, - grp->gr_mem[i++]) - == 0; - } - /* - * Otherwise, just check for username match - */ - else - found = strcmp(line, name) == 0; - } - (void) fclose(fd); - } - return (found); -} - -/* - * Terminate login as previous user, if any, resetting state; - * used when USER command is given or login fails. - */ -static void -end_login() -{ -#ifdef USE_PAM - int e; -#endif - - (void) seteuid((uid_t)0); - if (logged_in) - ftpd_logwtmp(ttyline, "", ""); - pw = NULL; -#ifdef LOGIN_CAP - setusercontext(NULL, getpwuid(0), (uid_t)0, - LOGIN_SETPRIORITY|LOGIN_SETRESOURCES|LOGIN_SETUMASK); -#endif -#ifdef USE_PAM - if ((e = pam_setcred(pamh, PAM_DELETE_CRED)) != PAM_SUCCESS) - syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); - if ((e = pam_close_session(pamh,0)) != PAM_SUCCESS) - syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pamh, e)); - if ((e = pam_end(pamh, e)) != PAM_SUCCESS) - syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); - pamh = NULL; -#endif - logged_in = 0; - guest = 0; - dochroot = 0; -} - -#ifdef USE_PAM - -/* - * the following code is stolen from imap-uw PAM authentication module and - * login.c - */ -#define COPY_STRING(s) (s ? strdup(s) : NULL) - -struct cred_t { - const char *uname; /* user name */ - const char *pass; /* password */ -}; -typedef struct cred_t cred_t; - -static int -auth_conv(int num_msg, const struct pam_message **msg, - struct pam_response **resp, void *appdata) -{ - int i; - cred_t *cred = (cred_t *) appdata; - struct pam_response *reply = - malloc(sizeof(struct pam_response) * num_msg); - - for (i = 0; i < num_msg; i++) { - switch (msg[i]->msg_style) { - case PAM_PROMPT_ECHO_ON: /* assume want user name */ - reply[i].resp_retcode = PAM_SUCCESS; - reply[i].resp = COPY_STRING(cred->uname); - /* PAM frees resp. */ - break; - case PAM_PROMPT_ECHO_OFF: /* assume want password */ - reply[i].resp_retcode = PAM_SUCCESS; - reply[i].resp = COPY_STRING(cred->pass); - /* PAM frees resp. */ - break; - case PAM_TEXT_INFO: - case PAM_ERROR_MSG: - reply[i].resp_retcode = PAM_SUCCESS; - reply[i].resp = NULL; - break; - default: /* unknown message style */ - free(reply); - return PAM_CONV_ERR; - } - } - - *resp = reply; - return PAM_SUCCESS; -} - -/* - * Attempt to authenticate the user using PAM. Returns 0 if the user is - * authenticated, or 1 if not authenticated. If some sort of PAM system - * error occurs (e.g., the "/etc/pam.conf" file is missing) then this - * function returns -1. This can be used as an indication that we should - * fall back to a different authentication mechanism. - */ -static int -auth_pam(struct passwd **ppw, const char *pass) -{ - pam_handle_t *pamh = NULL; - const char *tmpl_user; - const void *item; - int rval; - int e; - cred_t auth_cred = { (*ppw)->pw_name, pass }; - struct pam_conv conv = { &auth_conv, &auth_cred }; - - e = pam_start("ftpd", (*ppw)->pw_name, &conv, &pamh); - if (e != PAM_SUCCESS) { - syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); - return -1; - } - - e = pam_set_item(pamh, PAM_RHOST, remotehost); - if (e != PAM_SUCCESS) { - syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", - pam_strerror(pamh, e)); - return -1; - } - - e = pam_authenticate(pamh, 0); - switch (e) { - case PAM_SUCCESS: - /* - * With PAM we support the concept of a "template" - * user. The user enters a login name which is - * authenticated by PAM, usually via a remote service - * such as RADIUS or TACACS+. If authentication - * succeeds, a different but related "template" name - * is used for setting the credentials, shell, and - * home directory. The name the user enters need only - * exist on the remote authentication server, but the - * template name must be present in the local password - * database. - * - * This is supported by two various mechanisms in the - * individual modules. However, from the application's - * point of view, the template user is always passed - * back as a changed value of the PAM_USER item. - */ - if ((e = pam_get_item(pamh, PAM_USER, &item)) == - PAM_SUCCESS) { - tmpl_user = (const char *) item; - if (strcmp((*ppw)->pw_name, tmpl_user) != 0) - *ppw = getpwnam(tmpl_user); - } else - syslog(LOG_ERR, "Couldn't get PAM_USER: %s", - pam_strerror(pamh, e)); - rval = 0; - break; - - case PAM_AUTH_ERR: - case PAM_USER_UNKNOWN: - case PAM_MAXTRIES: - rval = 1; - break; - - default: - syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pamh, e)); - rval = -1; - break; - } - - if (rval == 0) { - e = pam_acct_mgmt(pamh, 0); - if (e == PAM_NEW_AUTHTOK_REQD) { - e = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); - if (e != PAM_SUCCESS) { - syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pamh, e)); - rval = 1; - } - } else if (e != PAM_SUCCESS) { - rval = 1; - } - } - - if (rval != 0) { - if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { - syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); - } - pamh = NULL; - } - return rval; -} - -#endif /* USE_PAM */ - -void -pass(passwd) - char *passwd; -{ - int rval; - FILE *fd; -#ifdef LOGIN_CAP - login_cap_t *lc = NULL; -#endif -#ifdef USE_PAM - int e; -#endif - - if (logged_in || askpasswd == 0) { - reply(503, "Login with USER first."); - return; - } - askpasswd = 0; - if (!guest) { /* "ftp" is only account allowed no password */ - if (pw == NULL) { - rval = 1; /* failure below */ - goto skip; - } -#ifdef USE_PAM - rval = auth_pam(&pw, passwd); - if (rval >= 0) - goto skip; -#endif -#ifdef SKEY - if (pwok) - rval = strcmp(pw->pw_passwd, - crypt(passwd, pw->pw_passwd)); - if (rval) - rval = strcmp(pw->pw_passwd, - skey_crypt(passwd, pw->pw_passwd, pw, pwok)); -#else - rval = strcmp(pw->pw_passwd, crypt(passwd, pw->pw_passwd)); -#endif - /* The strcmp does not catch null passwords! */ - if (*pw->pw_passwd == '\0' || - (pw->pw_expire && time(NULL) >= pw->pw_expire)) - rval = 1; /* failure */ -skip: - /* - * If rval == 1, the user failed the authentication check - * above. If rval == 0, either PAM or local authentication - * succeeded. - */ - if (rval) { - reply(530, "Login incorrect."); - if (logging) - syslog(LOG_NOTICE, - "FTP LOGIN FAILED FROM %s, %s", - remotehost, curname); - pw = NULL; - if (login_attempts++ >= 5) { - syslog(LOG_NOTICE, - "repeated login failures from %s", - remotehost); - exit(0); - } - return; - } - } -#ifdef SKEY - pwok = 0; -#endif - login_attempts = 0; /* this time successful */ - if (setegid((gid_t)pw->pw_gid) < 0) { - reply(550, "Can't set gid."); - return; - } - /* May be overridden by login.conf */ - (void) umask(defumask); -#ifdef LOGIN_CAP - if ((lc = login_getpwclass(pw)) != NULL) { - char remote_ip[MAXHOSTNAMELEN]; - - getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len, - remote_ip, sizeof(remote_ip) - 1, NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID); - remote_ip[sizeof(remote_ip) - 1] = 0; - if (!auth_hostok(lc, remotehost, remote_ip)) { - syslog(LOG_INFO|LOG_AUTH, - "FTP LOGIN FAILED (HOST) as %s: permission denied.", - pw->pw_name); - reply(530, "Permission denied.\n"); - pw = NULL; - return; - } - if (!auth_timeok(lc, time(NULL))) { - reply(530, "Login not available right now.\n"); - pw = NULL; - return; - } - } - setusercontext(lc, pw, (uid_t)0, - LOGIN_SETLOGIN|LOGIN_SETGROUP|LOGIN_SETPRIORITY| - LOGIN_SETRESOURCES|LOGIN_SETUMASK); -#else - setlogin(pw->pw_name); - (void) initgroups(pw->pw_name, pw->pw_gid); -#endif - -#ifdef USE_PAM - if (pamh) { - if ((e = pam_open_session(pamh, 0)) != PAM_SUCCESS) { - syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pamh, e)); - } else if ((e = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { - syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pamh, e)); - } - } -#endif - - /* open wtmp before chroot */ - ftpd_logwtmp(ttyline, pw->pw_name, remotehost); - logged_in = 1; - - if (guest && stats && statfd < 0) -#ifdef VIRTUAL_HOSTING - if ((statfd = open(thishost->statfile, O_WRONLY|O_APPEND)) < 0) -#else - if ((statfd = open(_PATH_FTPDSTATFILE, O_WRONLY|O_APPEND)) < 0) -#endif - stats = 0; - - dochroot = -#ifdef LOGIN_CAP /* Allow login.conf configuration as well */ - login_getcapbool(lc, "ftp-chroot", 0) || -#endif - checkuser(_PATH_FTPCHROOT, pw->pw_name, 1); - if (guest) { - /* - * We MUST do a chdir() after the chroot. Otherwise - * the old current directory will be accessible as "." - * outside the new root! - */ - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't set guest privileges."); - goto bad; - } - } else if (dochroot) { - if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) { - reply(550, "Can't change root."); - goto bad; - } - } else if (chdir(pw->pw_dir) < 0) { - if (chdir("/") < 0) { - reply(530, "User %s: can't change directory to %s.", - pw->pw_name, pw->pw_dir); - goto bad; - } else - lreply(230, "No directory! Logging in with home=/"); - } - if (seteuid((uid_t)pw->pw_uid) < 0) { - reply(550, "Can't set uid."); - goto bad; - } - - /* - * Display a login message, if it exists. - * N.B. reply(230,) must follow the message. - */ -#ifdef VIRTUAL_HOSTING - if ((fd = fopen(thishost->loginmsg, "r")) != NULL) { -#else - if ((fd = fopen(_PATH_FTPLOGINMESG, "r")) != NULL) { -#endif - char *cp, line[LINE_MAX]; - - while (fgets(line, sizeof(line), fd) != NULL) { - if ((cp = strchr(line, '\n')) != NULL) - *cp = '\0'; - lreply(230, "%s", line); - } - (void) fflush(stdout); - (void) fclose(fd); - } - if (guest) { - if (ident != NULL) - free(ident); - ident = strdup(passwd); - if (ident == NULL) - fatal("Ran out of memory."); - - reply(230, "Guest login ok, access restrictions apply."); -#ifdef SETPROCTITLE -#ifdef VIRTUAL_HOSTING - if (thishost != firsthost) - snprintf(proctitle, sizeof(proctitle), - "%s: anonymous(%s)/%.*s", remotehost, hostname, - (int)(sizeof(proctitle) - sizeof(remotehost) - - sizeof(": anonymous/")), passwd); - else -#endif - snprintf(proctitle, sizeof(proctitle), - "%s: anonymous/%.*s", remotehost, - (int)(sizeof(proctitle) - sizeof(remotehost) - - sizeof(": anonymous/")), passwd); - setproctitle("%s", proctitle); -#endif /* SETPROCTITLE */ - if (logging) - syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s, %s", - remotehost, passwd); - } else { - if (dochroot) - reply(230, "User %s logged in, access restrictions apply.", - pw->pw_name); - else - reply(230, "User %s logged in.", pw->pw_name); - -#ifdef SETPROCTITLE - snprintf(proctitle, sizeof(proctitle), - "%s: %s", remotehost, pw->pw_name); - setproctitle("%s", proctitle); -#endif /* SETPROCTITLE */ - if (logging) - syslog(LOG_INFO, "FTP LOGIN FROM %s as %s", - remotehost, pw->pw_name); - } -#ifdef LOGIN_CAP - login_close(lc); -#endif - return; -bad: - /* Forget all about it... */ -#ifdef LOGIN_CAP - login_close(lc); -#endif - end_login(); -} - -void -retrieve(cmd, name) - char *cmd, *name; -{ - FILE *fin, *dout; - struct stat st; - int (*closefunc) __P((FILE *)); - time_t start; - - if (cmd == 0) { - fin = fopen(name, "r"), closefunc = fclose; - st.st_size = 0; - } else { - char line[BUFSIZ]; - - (void) snprintf(line, sizeof(line), cmd, name), name = line; - fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; - st.st_size = -1; - st.st_blksize = BUFSIZ; - } - if (fin == NULL) { - if (errno != 0) { - perror_reply(550, name); - if (cmd == 0) { - LOGCMD("get", name); - } - } - return; - } - byte_count = -1; - if (cmd == 0 && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { - reply(550, "%s: not a plain file.", name); - goto done; - } - if (restart_point) { - if (type == TYPE_A) { - off_t i, n; - int c; - - n = restart_point; - i = 0; - while (i++ < n) { - if ((c=getc(fin)) == EOF) { - perror_reply(550, name); - goto done; - } - if (c == '\n') - i++; - } - } else if (lseek(fileno(fin), restart_point, L_SET) < 0) { - perror_reply(550, name); - goto done; - } - } - dout = dataconn(name, st.st_size, "w"); - if (dout == NULL) - goto done; - time(&start); - send_data(fin, dout, st.st_blksize, st.st_size, - restart_point == 0 && cmd == 0 && S_ISREG(st.st_mode)); - if (cmd == 0 && guest && stats) - logxfer(name, st.st_size, start); - (void) fclose(dout); - data = -1; - pdata = -1; -done: - if (cmd == 0) - LOGBYTES("get", name, byte_count); - (*closefunc)(fin); -} - -void -store(name, mode, unique) - char *name, *mode; - int unique; -{ - FILE *fout, *din; - struct stat st; - int (*closefunc) __P((FILE *)); - - if ((unique || guest) && stat(name, &st) == 0 && - (name = gunique(name)) == NULL) { - LOGCMD(*mode == 'w' ? "put" : "append", name); - return; - } - - if (restart_point) - mode = "r+"; - fout = fopen(name, mode); - closefunc = fclose; - if (fout == NULL) { - perror_reply(553, name); - LOGCMD(*mode == 'w' ? "put" : "append", name); - return; - } - byte_count = -1; - if (restart_point) { - if (type == TYPE_A) { - off_t i, n; - int c; - - n = restart_point; - i = 0; - while (i++ < n) { - if ((c=getc(fout)) == EOF) { - perror_reply(550, name); - goto done; - } - if (c == '\n') - i++; - } - /* - * We must do this seek to "current" position - * because we are changing from reading to - * writing. - */ - if (fseek(fout, 0L, L_INCR) < 0) { - perror_reply(550, name); - goto done; - } - } else if (lseek(fileno(fout), restart_point, L_SET) < 0) { - perror_reply(550, name); - goto done; - } - } - din = dataconn(name, (off_t)-1, "r"); - if (din == NULL) - goto done; - if (receive_data(din, fout) == 0) { - if (unique) - reply(226, "Transfer complete (unique file name:%s).", - name); - else - reply(226, "Transfer complete."); - } - (void) fclose(din); - data = -1; - pdata = -1; -done: - LOGBYTES(*mode == 'w' ? "put" : "append", name, byte_count); - (*closefunc)(fout); -} - -static FILE * -getdatasock(mode) - char *mode; -{ - int on = 1, s, t, tries; - - if (data >= 0) - return (fdopen(data, mode)); - (void) seteuid((uid_t)0); - - s = socket(data_dest.su_family, SOCK_STREAM, 0); - if (s < 0) - goto bad; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (char *) &on, sizeof(on)) < 0) - goto bad; - /* anchor socket to avoid multi-homing problems */ - data_source = ctrl_addr; - data_source.su_port = htons(20); /* ftp-data port */ - for (tries = 1; ; tries++) { - if (bind(s, (struct sockaddr *)&data_source, - data_source.su_len) >= 0) - break; - if (errno != EADDRINUSE || tries > 10) - goto bad; - sleep(tries); - } - (void) seteuid((uid_t)pw->pw_uid); -#ifdef IP_TOS - if (data_source.su_family == AF_INET) - { - on = IPTOS_THROUGHPUT; - if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); - } -#endif -#ifdef TCP_NOPUSH - /* - * Turn off push flag to keep sender TCP from sending short packets - * at the boundaries of each write(). Should probably do a SO_SNDBUF - * to set the send buffer size as well, but that may not be desirable - * in heavy-load situations. - */ - on = 1; - if (setsockopt(s, IPPROTO_TCP, TCP_NOPUSH, (char *)&on, sizeof on) < 0) - syslog(LOG_WARNING, "setsockopt (TCP_NOPUSH): %m"); -#endif -#ifdef SO_SNDBUF - on = 65536; - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&on, sizeof on) < 0) - syslog(LOG_WARNING, "setsockopt (SO_SNDBUF): %m"); -#endif - - return (fdopen(s, mode)); -bad: - /* Return the real value of errno (close may change it) */ - t = errno; - (void) seteuid((uid_t)pw->pw_uid); - (void) close(s); - errno = t; - return (NULL); -} - -static FILE * -dataconn(name, size, mode) - char *name; - off_t size; - char *mode; -{ - char sizebuf[32]; - FILE *file; - int retry = 0, tos; - - file_size = size; - byte_count = 0; - if (size != (off_t) -1) - (void) snprintf(sizebuf, sizeof(sizebuf), " (%qd bytes)", size); - else - *sizebuf = '\0'; - if (pdata >= 0) { - union sockunion from; - int s, fromlen = ctrl_addr.su_len; - struct timeval timeout; - fd_set set; - - FD_ZERO(&set); - FD_SET(pdata, &set); - - timeout.tv_usec = 0; - timeout.tv_sec = 120; - - if (select(pdata+1, &set, (fd_set *) 0, (fd_set *) 0, &timeout) == 0 || - (s = accept(pdata, (struct sockaddr *) &from, &fromlen)) < 0) { - reply(425, "Can't open data connection."); - (void) close(pdata); - pdata = -1; - return (NULL); - } - (void) close(pdata); - pdata = s; -#ifdef IP_TOS - if (from.su_family == AF_INET) - { - tos = IPTOS_THROUGHPUT; - (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, - sizeof(int)); - } -#endif - reply(150, "Opening %s mode data connection for '%s'%s.", - type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); - return (fdopen(pdata, mode)); - } - if (data >= 0) { - reply(125, "Using existing data connection for '%s'%s.", - name, sizebuf); - usedefault = 1; - return (fdopen(data, mode)); - } - if (usedefault) - data_dest = his_addr; - usedefault = 1; - file = getdatasock(mode); - if (file == NULL) { -#if defined(HAVE_GETNAMEINFO) - char hostbuf[BUFSIZ], portbuf[BUFSIZ]; - getnameinfo((struct sockaddr *)&data_source, - data_source.su_len, hostbuf, sizeof(hostbuf) - 1, - portbuf, sizeof(portbuf), - NI_NUMERICHOST|NI_NUMERICSERV|NI_WITHSCOPEID); - reply(425, "Can't create data socket (%s,%s): %s.", - hostbuf, portbuf, strerror(errno)); -#else - reply(425, "Can't create data socket (%s,%d): %s.", - inet_ntoa(data_source.su_sin.sin_addr), - ntohs(data_source.su_sin.sin_port), strerror(errno)); -#endif - return (NULL); - } - data = fileno(file); - while (connect(data, (struct sockaddr *)&data_dest, - data_dest.su_len) < 0) { - if (errno == EADDRINUSE && retry < swaitmax) { - sleep((unsigned) swaitint); - retry += swaitint; - continue; - } - perror_reply(425, "Can't build data connection"); - (void) fclose(file); - data = -1; - return (NULL); - } - reply(150, "Opening %s mode data connection for '%s'%s.", - type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); - return (file); -} - -/* - * Tranfer the contents of "instr" to "outstr" peer using the appropriate - * encapsulation of the data subject to Mode, Structure, and Type. - * - * NB: Form isn't handled. - */ -static void -send_data(instr, outstr, blksize, filesize, isreg) - FILE *instr, *outstr; - off_t blksize; - off_t filesize; - int isreg; -{ - int c, filefd, netfd; - char *buf, *bp; - size_t len; - off_t cnt; - - transflag++; - if (setjmp(urgcatch)) { - transflag = 0; - return; - } - switch (type) { - - case TYPE_A: - while ((c = getc(instr)) != EOF) { - byte_count++; - if (c == '\n') { - if (ferror(outstr)) - goto data_err; - (void) putc('\r', outstr); - } - (void) putc(c, outstr); - } - fflush(outstr); - transflag = 0; - if (ferror(instr)) - goto file_err; - if (ferror(outstr)) - goto data_err; - reply(226, "Transfer complete."); - return; - - case TYPE_I: - case TYPE_L: - /* - * isreg is only set if we are not doing restart and we - * are sending a regular file - */ - netfd = fileno(outstr); - filefd = fileno(instr); - -#if defined(HAVE_SENDFILE) - if (isreg) { - - off_t offset; - int err; - - len = filesize; - err = cnt = offset = 0; - - while (err != -1 && cnt < filesize) { - err = sendfile(filefd, netfd, offset, len, - (struct sf_hdtr *) NULL, &cnt, 0); - byte_count += cnt; - offset += cnt; - len -= cnt; - - if (err == -1) { - if (!cnt) - goto oldway; - - goto data_err; - } - } - - reply(226, "Transfer complete."); - return; - } -#else - if (isreg && filesize < (off_t)16 * 1024 * 1024) { - buf = mmap(0, filesize, PROT_READ, MAP_SHARED, filefd, - (off_t)0); - if (buf == MAP_FAILED) { - syslog(LOG_WARNING, "mmap(%lu): %m", - (unsigned long)filesize); - goto oldway; - } - bp = buf; - len = filesize; - do { - cnt = write(netfd, bp, len); - len -= cnt; - bp += cnt; - if (cnt > 0) byte_count += cnt; - } while(cnt > 0 && len > 0); - - transflag = 0; - munmap(buf, (size_t)filesize); - if (cnt < 0) - goto data_err; - reply(226, "Transfer complete."); - return; - } -#endif -oldway: - if ((buf = malloc((u_int)blksize)) == NULL) { - transflag = 0; - perror_reply(451, "Local resource failure: malloc"); - return; - } - - while ((cnt = read(filefd, buf, (u_int)blksize)) > 0 && - write(netfd, buf, cnt) == cnt) - byte_count += cnt; - transflag = 0; - (void)free(buf); - if (cnt != 0) { - if (cnt < 0) - goto file_err; - goto data_err; - } - reply(226, "Transfer complete."); - return; - default: - transflag = 0; - reply(550, "Unimplemented TYPE %d in send_data", type); - return; - } - -data_err: - transflag = 0; - perror_reply(426, "Data connection"); - return; - -file_err: - transflag = 0; - perror_reply(551, "Error on input file"); -} - -/* - * Transfer data from peer to "outstr" using the appropriate encapulation of - * the data subject to Mode, Structure, and Type. - * - * N.B.: Form isn't handled. - */ -static int -receive_data(instr, outstr) - FILE *instr, *outstr; -{ - int c; - int cnt, bare_lfs; - char buf[BUFSIZ]; - - transflag++; - if (setjmp(urgcatch)) { - transflag = 0; - return (-1); - } - - bare_lfs = 0; - - switch (type) { - - case TYPE_I: - case TYPE_L: - while ((cnt = read(fileno(instr), buf, sizeof(buf))) > 0) { - if (write(fileno(outstr), buf, cnt) != cnt) - goto file_err; - byte_count += cnt; - } - if (cnt < 0) - goto data_err; - transflag = 0; - return (0); - - case TYPE_E: - reply(553, "TYPE E not implemented."); - transflag = 0; - return (-1); - - case TYPE_A: - while ((c = getc(instr)) != EOF) { - byte_count++; - if (c == '\n') - bare_lfs++; - while (c == '\r') { - if (ferror(outstr)) - goto data_err; - if ((c = getc(instr)) != '\n') { - (void) putc ('\r', outstr); - if (c == '\0' || c == EOF) - goto contin2; - } - } - (void) putc(c, outstr); - contin2: ; - } - fflush(outstr); - if (ferror(instr)) - goto data_err; - if (ferror(outstr)) - goto file_err; - transflag = 0; - if (bare_lfs) { - lreply(226, - "WARNING! %d bare linefeeds received in ASCII mode", - bare_lfs); - (void)printf(" File may not have transferred correctly.\r\n"); - } - return (0); - default: - reply(550, "Unimplemented TYPE %d in receive_data", type); - transflag = 0; - return (-1); - } - -data_err: - transflag = 0; - perror_reply(426, "Data Connection"); - return (-1); - -file_err: - transflag = 0; - perror_reply(452, "Error writing file"); - return (-1); -} - -void -statfilecmd(filename) - char *filename; -{ - FILE *fin; - int c; - char line[LINE_MAX]; - - (void)snprintf(line, sizeof(line), _PATH_LS " -lgA %s", filename); - fin = ftpd_popen(line, "r"); - lreply(211, "status of %s:", filename); - while ((c = getc(fin)) != EOF) { - if (c == '\n') { - if (ferror(stdout)){ - perror_reply(421, "control connection"); - (void) ftpd_pclose(fin); - dologout(1); - /* NOTREACHED */ - } - if (ferror(fin)) { - perror_reply(551, filename); - (void) ftpd_pclose(fin); - return; - } - (void) putc('\r', stdout); - } - (void) putc(c, stdout); - } - (void) ftpd_pclose(fin); - reply(211, "End of Status"); -} - -void -statcmd() -{ - union sockunion *su; - u_char *a, *p; - char hname[INET6_ADDRSTRLEN]; - int ispassive; - - lreply(211, "%s FTP server status:", hostname, version); - printf(" %s\r\n", version); - printf(" Connected to %s", remotehost); -#if defined(HAVE_GETNAMEINFO) - if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len, - hname, sizeof(hname) - 1, NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID)) { - if (strcmp(hname, remotehost) != 0) - printf(" (%s)", hname); -#else - { - if (!isdigit(remotehost[0])) - printf(" (%s)", inet_ntoa(his_addr.su_sin.sin_addr)); -#endif - } - printf("\r\n"); - if (logged_in) { - if (guest) - printf(" Logged in anonymously\r\n"); - else - printf(" Logged in as %s\r\n", pw->pw_name); - } else if (askpasswd) - printf(" Waiting for password\r\n"); - else - printf(" Waiting for user name\r\n"); - printf(" TYPE: %s", typenames[type]); - if (type == TYPE_A || type == TYPE_E) - printf(", FORM: %s", formnames[form]); - if (type == TYPE_L) -#if NBBY == 8 - printf(" %d", NBBY); -#else - printf(" %d", bytesize); /* need definition! */ -#endif - printf("; STRUcture: %s; transfer MODE: %s\r\n", - strunames[stru], modenames[mode]); - if (data != -1) - printf(" Data connection open\r\n"); - else if (pdata != -1) { - ispassive = 1; - su = &pasv_addr; - goto printaddr; - } else if (usedefault == 0) { - ispassive = 0; - su = &data_dest; -printaddr: -#define UC(b) (((int) b) & 0xff) -#if defined(VIRTUAL_HOSTING) - if (epsvall) { - printf(" EPSV only mode (EPSV ALL)\r\n"); - goto epsvonly; - } -#endif - - /* PORT/PASV */ - if (su->su_family == AF_INET) { - a = (u_char *) &su->su_sin.sin_addr; - p = (u_char *) &su->su_sin.sin_port; - printf(" %s (%d,%d,%d,%d,%d,%d)\r\n", - ispassive ? "PASV" : "PORT", - UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - UC(p[0]), UC(p[1])); - } - - /* LPRT/LPSV */ - { - int alen, af, i; - - switch (su->su_family) { - case AF_INET: - a = (u_char *) &su->su_sin.sin_addr; - p = (u_char *) &su->su_sin.sin_port; - alen = sizeof(su->su_sin.sin_addr); - af = 4; - break; - case AF_INET6: - a = (u_char *) &su->su_sin6.sin6_addr; - p = (u_char *) &su->su_sin6.sin6_port; - alen = sizeof(su->su_sin6.sin6_addr); - af = 6; - break; - default: - af = 0; - break; - } - if (af) { - printf(" %s (%d,%d,", ispassive ? "LPSV" : "LPRT", - af, alen); - for (i = 0; i < alen; i++) - printf("%d,", UC(a[i])); - printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1])); - } - } - -#if defined(HAVE_GETNAMEINFO) -epsvonly:; - /* EPRT/EPSV */ - { - int af; - - switch (su->su_family) { - case AF_INET: - af = 1; - break; - case AF_INET6: - af = 2; - break; - default: - af = 0; - break; - } - if (af) { - if (!getnameinfo((struct sockaddr *)su, su->su_len, - hname, sizeof(hname) - 1, NULL, 0, - NI_NUMERICHOST)) { - printf(" %s |%d|%s|%d|\r\n", - ispassive ? "EPSV" : "EPRT", - af, hname, htons(su->su_port)); - } - } - } -#endif -#undef UC - } else - printf(" No data connection\r\n"); - reply(211, "End of status"); -} - -void -fatal(s) - char *s; -{ - - reply(451, "Error in server: %s\n", s); - reply(221, "Closing connection due to server error."); - dologout(0); - /* NOTREACHED */ -} - -void -#if __STDC__ -reply(int n, const char *fmt, ...) -#else -reply(n, fmt, va_alist) - int n; - char *fmt; - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void)printf("%d ", n); - (void)vprintf(fmt, ap); - (void)printf("\r\n"); - (void)fflush(stdout); - if (debug) { - syslog(LOG_DEBUG, "<--- %d ", n); - vsyslog(LOG_DEBUG, fmt, ap); - } -} - -void -#if __STDC__ -lreply(int n, const char *fmt, ...) -#else -lreply(n, fmt, va_alist) - int n; - char *fmt; - va_dcl -#endif -{ - va_list ap; -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void)printf("%d- ", n); - (void)vprintf(fmt, ap); - (void)printf("\r\n"); - (void)fflush(stdout); - if (debug) { - syslog(LOG_DEBUG, "<--- %d- ", n); - vsyslog(LOG_DEBUG, fmt, ap); - } -} - -static void -ack(s) - char *s; -{ - - reply(250, "%s command successful.", s); -} - -void -nack(s) - char *s; -{ - - reply(502, "%s command not implemented.", s); -} - -/* ARGSUSED */ -void -yyerror(s) - char *s; -{ - char *cp; - - if ((cp = strchr(cbuf,'\n'))) - *cp = '\0'; - reply(500, "'%s': command not understood.", cbuf); -} - -void -delete(name) - char *name; -{ - struct stat st; - - LOGCMD("delete", name); - if (stat(name, &st) < 0) { - perror_reply(550, name); - return; - } - if ((st.st_mode&S_IFMT) == S_IFDIR) { - if (rmdir(name) < 0) { - perror_reply(550, name); - return; - } - goto done; - } - if (unlink(name) < 0) { - perror_reply(550, name); - return; - } -done: - ack("DELE"); -} - -void -cwd(path) - char *path; -{ - - if (chdir(path) < 0) - perror_reply(550, path); - else - ack("CWD"); -} - -void -makedir(name) - char *name; -{ - - LOGCMD("mkdir", name); - if (mkdir(name, 0777) < 0) - perror_reply(550, name); - else - reply(257, "MKD command successful."); -} - -void -removedir(name) - char *name; -{ - - LOGCMD("rmdir", name); - if (rmdir(name) < 0) - perror_reply(550, name); - else - ack("RMD"); -} - -void -pwd() -{ - char path[MAXPATHLEN + 1]; - - if (getwd(path) == (char *)NULL) - reply(550, "%s.", path); - else - reply(257, "\"%s\" is current directory.", path); -} - -char * -renamefrom(name) - char *name; -{ - struct stat st; - - if (stat(name, &st) < 0) { - perror_reply(550, name); - return ((char *)0); - } - reply(350, "File exists, ready for destination name"); - return (name); -} - -void -renamecmd(from, to) - char *from, *to; -{ - struct stat st; - - LOGCMD2("rename", from, to); - - if (guest && (stat(to, &st) == 0)) { - reply(550, "%s: permission denied", to); - return; - } - - if (rename(from, to) < 0) - perror_reply(550, "rename"); - else - ack("RNTO"); -} - -static void -dolog(who) - struct sockaddr *who; -{ -#if defined(HAVE_GETNAMEINFO) - int error; -#endif - -#if defined(HAVE_REALHOSTNAME_SA) - realhostname_sa(remotehost, sizeof(remotehost) - 1, who, who->sa_len); -#else - struct sockaddr_in *sin = (struct sockaddr_in *)who; - struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, - sizeof(struct in_addr), AF_INET); - - if (hp) - (void) strncpy(remotehost, hp->h_name, sizeof(remotehost)); - else - (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), - sizeof(remotehost)); -#endif - -#ifdef SETPROCTITLE -#ifdef VIRTUAL_HOSTING - if (thishost != firsthost) - snprintf(proctitle, sizeof(proctitle), "%s: connected (to %s)", - remotehost, hostname); - else -#endif - snprintf(proctitle, sizeof(proctitle), "%s: connected", - remotehost); - setproctitle("%s", proctitle); -#endif /* SETPROCTITLE */ - - if (logging) { -#ifdef VIRTUAL_HOSTING - if (thishost != firsthost) - syslog(LOG_INFO, "connection from %s (to %s)", - remotehost, hostname); - else -#endif - { -#if defined(HAVE_GETNAMEINFO) - char who_name[MAXHOSTNAMELEN]; - - error = getnameinfo(who, who->sa_len, - who_name, sizeof(who_name) - 1, - NULL, 0, - NI_NUMERICHOST|NI_WITHSCOPEID); - syslog(LOG_INFO, "connection from %s (%s)", remotehost, - error == 0 ? who_name : ""); -#else - syslog(LOG_INFO, "connection from %s", remotehost); -#endif - } - } -} - -/* - * Record logout in wtmp file - * and exit with supplied status. - */ -void -dologout(status) - int status; -{ - /* - * Prevent reception of SIGURG from resulting in a resumption - * back to the main program loop. - */ - transflag = 0; - - if (logged_in) { - (void) seteuid((uid_t)0); - ftpd_logwtmp(ttyline, "", ""); - } - /* beware of flushing buffers after a SIGPIPE */ - _exit(status); -} - -static void -myoob(signo) - int signo; -{ - char *cp; - - /* only process if transfer occurring */ - if (!transflag) - return; - cp = tmpline; - if (getline(cp, 7, stdin) == NULL) { - reply(221, "You could at least say goodbye."); - dologout(0); - } - upper(cp); - if (strcmp(cp, "ABOR\r\n") == 0) { - tmpline[0] = '\0'; - reply(426, "Transfer aborted. Data connection closed."); - reply(226, "Abort successful"); - longjmp(urgcatch, 1); - } - if (strcmp(cp, "STAT\r\n") == 0) { - tmpline[0] = '\0'; - if (file_size != (off_t) -1) - reply(213, "Status: %qd of %qd bytes transferred", - byte_count, file_size); - else - reply(213, "Status: %qd bytes transferred", byte_count); - } -} - -/* - * Note: a response of 425 is not mentioned as a possible response to - * the PASV command in RFC959. However, it has been blessed as - * a legitimate response by Jon Postel in a telephone conversation - * with Rick Adams on 25 Jan 89. - */ -void -passive() -{ - int len; - char *p, *a; - - if (pdata >= 0) /* close old port if one set */ - close(pdata); - - pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0); - if (pdata < 0) { - perror_reply(425, "Can't open passive connection"); - return; - } - - (void) seteuid((uid_t)0); - -#ifdef IP_PORTRANGE - if (ctrl_addr.su_family == AF_INET) { - int on = restricted_data_ports ? IP_PORTRANGE_HIGH - : IP_PORTRANGE_DEFAULT; - - if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, - (char *)&on, sizeof(on)) < 0) - goto pasv_error; - } -#endif -#ifdef IPV6_PORTRANGE - if (ctrl_addr.su_family == AF_INET6) { - int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH - : IPV6_PORTRANGE_DEFAULT; - - if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE, - (char *)&on, sizeof(on)) < 0) - goto pasv_error; - } -#endif - - pasv_addr = ctrl_addr; - pasv_addr.su_port = 0; - if (bind(pdata, (struct sockaddr *)&pasv_addr, pasv_addr.su_len) < 0) - goto pasv_error; - - (void) seteuid((uid_t)pw->pw_uid); - - len = sizeof(pasv_addr); - if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) - goto pasv_error; - if (listen(pdata, 1) < 0) - goto pasv_error; - if (pasv_addr.su_family == AF_INET) - a = (char *) &pasv_addr.su_sin.sin_addr; - else if (pasv_addr.su_family == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) - a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12]; - else - goto pasv_error; - - p = (char *) &pasv_addr.su_port; - -#define UC(b) (((int) b) & 0xff) - - reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), - UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); - return; - -pasv_error: - (void) seteuid((uid_t)pw->pw_uid); - (void) close(pdata); - pdata = -1; - perror_reply(425, "Can't open passive connection"); - return; -} - -/* - * Long Passive defined in RFC 1639. - * 228 Entering Long Passive Mode - * (af, hal, h1, h2, h3,..., pal, p1, p2...) - */ - -void -long_passive(cmd, pf) - char *cmd; - int pf; -{ - int len; - char *p, *a; - - if (pdata >= 0) /* close old port if one set */ - close(pdata); - - if (pf != PF_UNSPEC) { - if (ctrl_addr.su_family != pf) { - switch (ctrl_addr.su_family) { - case AF_INET: - pf = 1; - break; - case AF_INET6: - pf = 2; - break; - default: - pf = 0; - break; - } - /* - * XXX - * only EPRT/EPSV ready clients will understand this - */ - if (strcmp(cmd, "EPSV") == 0 && pf) { - reply(522, "Network protocol mismatch, " - "use (%d)", pf); - } else - reply(501, "Network protocol mismatch"); /*XXX*/ - - return; - } - } - - pdata = socket(ctrl_addr.su_family, SOCK_STREAM, 0); - if (pdata < 0) { - perror_reply(425, "Can't open passive connection"); - return; - } - - (void) seteuid((uid_t)0); - - pasv_addr = ctrl_addr; - pasv_addr.su_port = 0; - len = pasv_addr.su_len; - -#ifdef IP_PORTRANGE - if (ctrl_addr.su_family == AF_INET) { - int on = restricted_data_ports ? IP_PORTRANGE_HIGH - : IP_PORTRANGE_DEFAULT; - - if (setsockopt(pdata, IPPROTO_IP, IP_PORTRANGE, - (char *)&on, sizeof(on)) < 0) - goto pasv_error; - } -#endif -#ifdef IPV6_PORTRANGE - if (ctrl_addr.su_family == AF_INET6) { - int on = restricted_data_ports ? IPV6_PORTRANGE_HIGH - : IPV6_PORTRANGE_DEFAULT; - - if (setsockopt(pdata, IPPROTO_IPV6, IPV6_PORTRANGE, - (char *)&on, sizeof(on)) < 0) - goto pasv_error; - } -#endif - - if (bind(pdata, (struct sockaddr *)&pasv_addr, len) < 0) - goto pasv_error; - - (void) seteuid((uid_t)pw->pw_uid); - - if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0) - goto pasv_error; - if (listen(pdata, 1) < 0) - goto pasv_error; - -#define UC(b) (((int) b) & 0xff) - - if (strcmp(cmd, "LPSV") == 0) { - p = (char *)&pasv_addr.su_port; - switch (pasv_addr.su_family) { - case AF_INET: - a = (char *) &pasv_addr.su_sin.sin_addr; - v4_reply: - reply(228, -"Entering Long Passive Mode (%d,%d,%d,%d,%d,%d,%d,%d,%d)", - 4, 4, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - 2, UC(p[0]), UC(p[1])); - return; - case AF_INET6: - if (IN6_IS_ADDR_V4MAPPED(&pasv_addr.su_sin6.sin6_addr)) { - a = (char *) &pasv_addr.su_sin6.sin6_addr.s6_addr[12]; - goto v4_reply; - } - a = (char *) &pasv_addr.su_sin6.sin6_addr; - reply(228, -"Entering Long Passive Mode " -"(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)", - 6, 16, UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), - UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), - UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), - UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), - 2, UC(p[0]), UC(p[1])); - return; - } - } else if (strcmp(cmd, "EPSV") == 0) { - switch (pasv_addr.su_family) { - case AF_INET: - case AF_INET6: - reply(229, "Entering Extended Passive Mode (|||%d|)", - ntohs(pasv_addr.su_port)); - return; - } - } else { - /* more proper error code? */ - } - -pasv_error: - (void) seteuid((uid_t)pw->pw_uid); - (void) close(pdata); - pdata = -1; - perror_reply(425, "Can't open passive connection"); - return; -} - -/* - * Generate unique name for file with basename "local". - * The file named "local" is already known to exist. - * Generates failure reply on error. - */ -static char * -gunique(local) - char *local; -{ - static char new[MAXPATHLEN]; - struct stat st; - int count; - char *cp; - - cp = strrchr(local, '/'); - if (cp) - *cp = '\0'; - if (stat(cp ? local : ".", &st) < 0) { - perror_reply(553, cp ? local : "."); - return ((char *) 0); - } - if (cp) - *cp = '/'; - /* -4 is for the .nn we put on the end below */ - (void) snprintf(new, sizeof(new) - 4, "%s", local); - cp = new + strlen(new); - *cp++ = '.'; - for (count = 1; count < 100; count++) { - (void)sprintf(cp, "%d", count); - if (stat(new, &st) < 0) - return (new); - } - reply(452, "Unique file name cannot be created."); - return (NULL); -} - -/* - * Format and send reply containing system error number. - */ -void -perror_reply(code, string) - int code; - char *string; -{ - - reply(code, "%s: %s.", string, strerror(errno)); -} - -static char *onefile[] = { - "", - 0 -}; - -void -send_file_list(whichf) - char *whichf; -{ - struct stat st; - DIR *dirp = NULL; - struct dirent *dir; - FILE *dout = NULL; - char **dirlist, *dirname; - int simple = 0; - int freeglob = 0; - glob_t gl; - - if (strpbrk(whichf, "~{[*?") != NULL) { - int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - - memset(&gl, 0, sizeof(gl)); - gl.gl_matchc = MAXGLOBARGS; -#if !defined(GLOB_MAXPATH) -#define GLOB_MAXPATH 0x1000 -#endif - flags |= GLOB_MAXPATH; - freeglob = 1; - if (glob(whichf, flags, 0, &gl)) { - reply(550, "not found"); - goto out; - } else if (gl.gl_pathc == 0) { - errno = ENOENT; - perror_reply(550, whichf); - goto out; - } - dirlist = gl.gl_pathv; - } else { - onefile[0] = whichf; - dirlist = onefile; - simple = 1; - } - - if (setjmp(urgcatch)) { - transflag = 0; - goto out; - } - while ((dirname = *dirlist++)) { - if (stat(dirname, &st) < 0) { - /* - * If user typed "ls -l", etc, and the client - * used NLST, do what the user meant. - */ - if (dirname[0] == '-' && *dirlist == NULL && - transflag == 0) { - retrieve(_PATH_LS " %s", dirname); - goto out; - } - perror_reply(550, whichf); - if (dout != NULL) { - (void) fclose(dout); - transflag = 0; - data = -1; - pdata = -1; - } - goto out; - } - - if (S_ISREG(st.st_mode)) { - if (dout == NULL) { - dout = dataconn("file list", (off_t)-1, "w"); - if (dout == NULL) - goto out; - transflag++; - } - fprintf(dout, "%s%s\n", dirname, - type == TYPE_A ? "\r" : ""); - byte_count += strlen(dirname) + 1; - continue; - } else if (!S_ISDIR(st.st_mode)) - continue; - - if ((dirp = opendir(dirname)) == NULL) - continue; - - while ((dir = readdir(dirp)) != NULL) { - char nbuf[MAXPATHLEN]; - - if (dir->d_name[0] == '.' && dir->d_namlen == 1) - continue; - if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && - dir->d_namlen == 2) - continue; - - snprintf(nbuf, sizeof(nbuf), - "%s/%s", dirname, dir->d_name); - - /* - * We have to do a stat to insure it's - * not a directory or special file. - */ - if (simple || (stat(nbuf, &st) == 0 && - S_ISREG(st.st_mode))) { - if (dout == NULL) { - dout = dataconn("file list", (off_t)-1, - "w"); - if (dout == NULL) - goto out; - transflag++; - } - if (nbuf[0] == '.' && nbuf[1] == '/') - fprintf(dout, "%s%s\n", &nbuf[2], - type == TYPE_A ? "\r" : ""); - else - fprintf(dout, "%s%s\n", nbuf, - type == TYPE_A ? "\r" : ""); - byte_count += strlen(nbuf) + 1; - } - } - (void) closedir(dirp); - } - - if (dout == NULL) - reply(550, "No files found."); - else if (ferror(dout) != 0) - perror_reply(550, "Data connection"); - else - reply(226, "Transfer complete."); - - transflag = 0; - if (dout != NULL) - (void) fclose(dout); - data = -1; - pdata = -1; -out: - if (freeglob) { - freeglob = 0; - globfree(&gl); - } -} - -void -reapchild(signo) - int signo; -{ - while (wait3(NULL, WNOHANG, NULL) > 0); -} - -#ifdef OLD_SETPROCTITLE -/* - * Clobber argv so ps will show what we're doing. (Stolen from sendmail.) - * Warning, since this is usually started from inetd.conf, it often doesn't - * have much of an environment or arglist to overwrite. - */ -void -#if __STDC__ -setproctitle(const char *fmt, ...) -#else -setproctitle(fmt, va_alist) - char *fmt; - va_dcl -#endif -{ - int i; - va_list ap; - char *p, *bp, ch; - char buf[LINE_MAX]; - -#if __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void)vsnprintf(buf, sizeof(buf), fmt, ap); - - /* make ps print our process name */ - p = Argv[0]; - *p++ = '-'; - - i = strlen(buf); - if (i > LastArgv - p - 2) { - i = LastArgv - p - 2; - buf[i] = '\0'; - } - bp = buf; - while (ch = *bp++) - if (ch != '\n' && ch != '\r') - *p++ = ch; - while (p < LastArgv) - *p++ = ' '; -} -#endif /* OLD_SETPROCTITLE */ - -static void -logxfer(name, size, start) - char *name; - long size; - long start; -{ - char buf[1024]; - char path[MAXPATHLEN + 1]; - time_t now; - - if (statfd >= 0 && getwd(path) != NULL) { - time(&now); - snprintf(buf, sizeof(buf), "%.20s!%s!%s!%s/%s!%ld!%ld\n", - ctime(&now)+4, ident, remotehost, - path, name, size, now - start + (now == start)); - write(statfd, buf, strlen(buf)); - } -} diff --git a/ftpd.tproj/logwtmp.c b/ftpd.tproj/logwtmp.c deleted file mode 100644 index 904f525..0000000 --- a/ftpd.tproj/logwtmp.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 1988, 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. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93"; -#endif -static const char rcsid[] = - "$FreeBSD: src/libexec/ftpd/logwtmp.c,v 1.9 2000/01/27 09:28:21 shin Exp $"; -#endif /* not lint */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "extern.h" - -static int fd = -1; - -/* - * Modified version of logwtmp that holds wtmp file open - * after first call, for use with ftp (which may chroot - * after login, but before logout). - */ -void -ftpd_logwtmp(line, name, host) - char *line, *name, *host; -{ - struct utmp ut; - struct stat buf; - -#if defined(HAVE_GETNAMEINFO) - if (strlen(host) > UT_HOSTSIZE) { - struct addrinfo hints, *res; - int error; - static char hostbuf[BUFSIZ]; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - error = getaddrinfo(host, NULL, &hints, &res); - if (error) - host = "invalid hostname"; - else { - getnameinfo(res->ai_addr, res->ai_addrlen, - hostbuf, sizeof(hostbuf), NULL, 0, - NI_NUMERICHOST); - host = hostbuf; - if (strlen(host) > UT_HOSTSIZE) - host[UT_HOSTSIZE] = '\0'; - } - } -#else - if (strlen(host) > UT_HOSTSIZE) { - struct hostent *hp = gethostbyname(host); - - if (hp != NULL) { - struct in_addr in; - - memmove(&in, hp->h_addr, sizeof(in)); - host = inet_ntoa(in); - } else - host = "invalid hostname"; - } -#endif - if (fd < 0 && (fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0) - return; - if (fstat(fd, &buf) == 0) { - (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); - (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); - (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); - (void)time(&ut.ut_time); - if (write(fd, (char *)&ut, sizeof(struct utmp)) != - sizeof(struct utmp)) - (void)ftruncate(fd, buf.st_size); - } -} diff --git a/ftpd.tproj/ls.c b/ftpd.tproj/ls.c deleted file mode 100644 index 824e232..0000000 --- a/ftpd.tproj/ls.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Michael Fischbein. - * - * 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. - */ - -#ifndef lint -static const char copyright[] = -"@(#) Copyright (c) 1989, 1993, 1994\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)ls.c 8.5 (Berkeley) 4/2/94"; -#else -static const char rcsid[] = - "$FreeBSD: src/bin/ls/ls.c,v 1.45 2000/08/13 12:17:03 joe Exp $"; -#endif -#endif /* not lint */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef COLORLS -#include -#include -#endif - -#include "ls.h" -#include "ls_extern.h" - -#if !defined(HAVE_FFLAGSTOSTR) -static struct { - char *name; - u_long flag; - int invert; -} mapping[] = { - /* shorter names per flag first, all prefixed by "no" */ - { "nosappnd", SF_APPEND, 0 }, - { "nosappend", SF_APPEND, 0 }, - { "noarch", SF_ARCHIVED, 0 }, - { "noarchived", SF_ARCHIVED, 0 }, - { "noschg", SF_IMMUTABLE, 0 }, - { "noschange", SF_IMMUTABLE, 0 }, - { "nosimmutable", SF_IMMUTABLE, 0 }, -#if defined(SF_NOUNLINK) - { "nosunlnk", SF_NOUNLINK, 0 }, - { "nosunlink", SF_NOUNLINK, 0 }, -#endif - { "nouappnd", UF_APPEND, 0 }, - { "nouappend", UF_APPEND, 0 }, - { "nouchg", UF_IMMUTABLE, 0 }, - { "nouchange", UF_IMMUTABLE, 0 }, - { "nouimmutable", UF_IMMUTABLE, 0 }, - { "nodump", UF_NODUMP, 1 }, - { "noopaque", UF_OPAQUE, 0 } -#if defined(UF_NOUNLINK) -, - { "nouunlnk", UF_NOUNLINK, 0 }, - { "nouunlink", UF_NOUNLINK, 0 } -#endif -}; -#define longestflaglen 12 -#define nmappings (sizeof(mapping) / sizeof(mapping[0])) - -/* - * fflagstostr -- - * Convert file flags to a comma-separated string. If no flags - * are set, return the empty string. - */ -char * -fflagstostr(flags) - u_long flags; -{ - char *string; - char *sp, *dp; - u_long setflags; - int i; - - if ((string = (char *)malloc(nmappings * (longestflaglen + 1))) == NULL) - return (NULL); - - setflags = flags; - dp = string; - for (i = 0; i < nmappings; i++) { - if (setflags & mapping[i].flag) { - if (dp > string) - *dp++ = ','; - for (sp = mapping[i].invert ? mapping[i].name : - mapping[i].name + 2; *sp; *dp++ = *sp++) ; - setflags &= ~mapping[i].flag; - } - } - *dp = '\0'; - return (string); -} -#endif - -/* - * Upward approximation of the maximum number of characters needed to - * represent a value of integral type t as a string, excluding the - * NUL terminator, with provision for a sign. - */ -#define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1) - -static void display __P((FTSENT *, FTSENT *)); -static u_quad_t makenines __P((u_long)); -static int mastercmp __P((const FTSENT **, const FTSENT **)); -static void traverse __P((int, char **, int)); - -static void (*printfcn) __P((DISPLAY *)); -static int (*sortfcn) __P((const FTSENT *, const FTSENT *)); - -long blocksize; /* block size units */ -int termwidth = 80; /* default terminal width */ - -/* flags */ -int f_accesstime; /* use time of last access */ -int f_column; /* columnated format */ -int f_flags; /* show flags associated with a file */ -int f_inode; /* print inode */ -int f_kblocks; /* print size in kilobytes */ -int f_listdir; /* list actual directory, not contents */ -int f_listdot; /* list files beginning with . */ -int f_longform; /* long listing format */ -int f_nonprint; /* show unprintables as ? */ -int f_nosort; /* don't sort output */ -int f_notabs; /* don't use tab-separated multi-col output */ -int f_numericonly; /* don't convert uid/gid to name */ -int f_octal; /* show unprintables as \xxx */ -int f_octal_escape; /* like f_octal but use C escapes if possible */ -int f_recursive; /* ls subdirectories also */ -int f_reversesort; /* reverse whatever sort is used */ -int f_sectime; /* print the real time for all files */ -int f_singlecol; /* use single column output */ -int f_size; /* list size in short listing */ -int f_statustime; /* use time of last mode change */ -int f_timesort; /* sort by time vice name */ -int f_type; /* add type character for non-regular files */ -int f_whiteout; /* show whiteout entries */ -#ifdef COLORLS -int f_color; /* add type in color for non-regular files */ - -char *ansi_bgcol; /* ANSI sequence to set background colour */ -char *ansi_fgcol; /* ANSI sequence to set foreground colour */ -char *ansi_coloff; /* ANSI sequence to reset colours */ -#endif - -int rval; - -int -main(argc, argv) - int argc; - char *argv[]; -{ - static char dot[] = ".", *dotav[] = { dot, NULL }; - struct winsize win; - int ch, fts_options, notused; - char *p; - -#ifdef COLORLS - char termcapbuf[1024]; /* termcap definition buffer */ - char tcapbuf[512]; /* capability buffer */ - char *bp = tcapbuf; -#endif - - (void) setlocale(LC_ALL, ""); - - /* Terminal defaults to -Cq, non-terminal defaults to -1. */ - if (isatty(STDOUT_FILENO)) { - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 || - !win.ws_col) { - if ((p = getenv("COLUMNS")) != NULL) - termwidth = atoi(p); - } - else - termwidth = win.ws_col; - f_column = f_nonprint = 1; - } else { - f_singlecol = 1; - /* retrieve environment variable, in case of explicit -C */ - if ((p = getenv("COLUMNS"))) - termwidth = atoi(p); - } - - /* Root is -A automatically. */ - if (!getuid()) - f_listdot = 1; - - fts_options = FTS_PHYSICAL; - while ((ch = getopt(argc, argv, "1ABCFGHLPRTWabcdfgiklnoqrstu")) != -1) { - switch (ch) { - /* - * The -1, -C and -l options all override each other so shell - * aliasing works right. - */ - case '1': - f_singlecol = 1; - f_column = f_longform = 0; - break; - case 'B': - f_nonprint = 0; - f_octal = 1; - f_octal_escape = 0; - break; - case 'C': - f_column = 1; - f_longform = f_singlecol = 0; - break; - case 'l': - f_longform = 1; - f_column = f_singlecol = 0; - break; - /* The -c and -u options override each other. */ - case 'c': - f_statustime = 1; - f_accesstime = 0; - break; - case 'u': - f_accesstime = 1; - f_statustime = 0; - break; - case 'F': - f_type = 1; - break; - case 'H': - fts_options |= FTS_COMFOLLOW; - break; - case 'G': - setenv("CLICOLOR", "", 1); - break; - case 'L': - fts_options &= ~FTS_PHYSICAL; - fts_options |= FTS_LOGICAL; - break; - case 'P': - fts_options &= ~FTS_COMFOLLOW; - fts_options &= ~FTS_LOGICAL; - fts_options |= FTS_PHYSICAL; - break; - case 'R': - f_recursive = 1; - break; - case 'a': - fts_options |= FTS_SEEDOT; - /* FALLTHROUGH */ - case 'A': - f_listdot = 1; - break; - /* The -d option turns off the -R option. */ - case 'd': - f_listdir = 1; - f_recursive = 0; - break; - case 'f': - f_nosort = 1; - break; - case 'g': /* Compatibility with 4.3BSD. */ - break; - case 'i': - f_inode = 1; - break; - case 'k': - f_kblocks = 1; - break; - case 'n': - f_numericonly = 1; - break; - case 'o': - f_flags = 1; - break; - case 'q': - f_nonprint = 1; - f_octal = 0; - f_octal_escape = 0; - break; - case 'r': - f_reversesort = 1; - break; - case 's': - f_size = 1; - break; - case 'T': - f_sectime = 1; - break; - case 't': - f_timesort = 1; - break; - case 'W': - f_whiteout = 1; - break; - case 'b': - f_nonprint = 0; - f_octal = 0; - f_octal_escape = 1; - break; - default: - case '?': - usage(); - } - } - argc -= optind; - argv += optind; - - /* Enabling of colours is conditional on the environment. */ - if (getenv("CLICOLOR") && - (isatty(STDOUT_FILENO) || getenv("CLICOLOR_FORCE"))) -#ifdef COLORLS - if (tgetent(termcapbuf, getenv("TERM")) == 1) { - ansi_fgcol = tgetstr("AF", &bp); - ansi_bgcol = tgetstr("AB", &bp); - - /* To switch colours off use 'op' if - * available, otherwise use 'oc', or - * don't do colours at all. */ - ansi_coloff = tgetstr("op", &bp); - if (!ansi_coloff) - ansi_coloff = tgetstr("oc", &bp); - if (ansi_fgcol && ansi_bgcol && ansi_coloff) - f_color = 1; - } -#else - (void)fprintf(stderr, "Color support not compiled in.\n"); -#endif /*COLORLS*/ - -#ifdef COLORLS - if (f_color) { - /* - * We can't put tabs and color sequences together: - * column number will be incremented incorrectly - * for "stty oxtabs" mode. - */ - f_notabs = 1; - (void) signal(SIGINT, colorquit); - (void) signal(SIGQUIT, colorquit); - parsecolors(getenv("LSCOLORS")); - } -#endif - - /* - * If not -F, -i, -l, -s or -t options, don't require stat - * information, unless in color mode in which case we do - * need this to determine which colors to display. - */ - if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type -#ifdef COLORLS - && !f_color -#endif - ) - fts_options |= FTS_NOSTAT; - - /* - * If not -F, -d or -l options, follow any symbolic links listed on - * the command line. - */ - if (!f_longform && !f_listdir && !f_type) - fts_options |= FTS_COMFOLLOW; - - /* - * If -W, show whiteout entries - */ -#ifdef FTS_WHITEOUT - if (f_whiteout) - fts_options |= FTS_WHITEOUT; -#endif - - /* If -l or -s, figure out block size. */ - if (f_longform || f_size) { - if (f_kblocks) - blocksize = 2; - else { - (void)getbsize(¬used, &blocksize); - blocksize /= 512; - } - } - - /* Select a sort function. */ - if (f_reversesort) { - if (!f_timesort) - sortfcn = revnamecmp; - else if (f_accesstime) - sortfcn = revacccmp; - else if (f_statustime) - sortfcn = revstatcmp; - else /* Use modification time. */ - sortfcn = revmodcmp; - } else { - if (!f_timesort) - sortfcn = namecmp; - else if (f_accesstime) - sortfcn = acccmp; - else if (f_statustime) - sortfcn = statcmp; - else /* Use modification time. */ - sortfcn = modcmp; - } - - /* Select a print function. */ - if (f_singlecol) - printfcn = printscol; - else if (f_longform) - printfcn = printlong; - else - printfcn = printcol; - - if (argc) - traverse(argc, argv, fts_options); - else - traverse(1, dotav, fts_options); - exit(rval); -} - -static int output; /* If anything output. */ - -/* - * Traverse() walks the logical directory structure specified by the argv list - * in the order specified by the mastercmp() comparison function. During the - * traversal it passes linked lists of structures to display() which represent - * a superset (may be exact set) of the files to be displayed. - */ -static void -traverse(argc, argv, options) - int argc, options; - char *argv[]; -{ - FTS *ftsp; - FTSENT *p, *chp; - int ch_options; - - if ((ftsp = - fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) - err(1, NULL); - - display(NULL, fts_children(ftsp, 0)); - if (f_listdir) - return; - - /* - * If not recursing down this tree and don't need stat info, just get - * the names. - */ - ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0; - - while ((p = fts_read(ftsp)) != NULL) - switch (p->fts_info) { - case FTS_DC: - warnx("%s: directory causes a cycle", p->fts_name); - break; - case FTS_DNR: - case FTS_ERR: - warnx("%s: %s", p->fts_name, strerror(p->fts_errno)); - rval = 1; - break; - case FTS_D: - if (p->fts_level != FTS_ROOTLEVEL && - p->fts_name[0] == '.' && !f_listdot) - break; - - /* - * If already output something, put out a newline as - * a separator. If multiple arguments, precede each - * directory with its name. - */ - if (output) - (void)printf("\n%s:\n", p->fts_path); - else if (argc > 1) { - (void)printf("%s:\n", p->fts_path); - output = 1; - } - - chp = fts_children(ftsp, ch_options); - display(p, chp); - - if (!f_recursive && chp != NULL) - (void)fts_set(ftsp, p, FTS_SKIP); - break; - } - if (errno) - err(1, "fts_read"); -} - -/* - * Display() takes a linked list of FTSENT structures and passes the list - * along with any other necessary information to the print function. P - * points to the parent directory of the display list. - */ -static void -display(p, list) - FTSENT *p, *list; -{ - struct stat *sp; - DISPLAY d; - FTSENT *cur; - NAMES *np; - u_quad_t maxsize; - u_long btotal, maxblock, maxinode, maxlen, maxnlink; - int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser; - char *initmax; - int entries, needstats; - char *user, *group, *flags; - char buf[STRBUF_SIZEOF(u_quad_t) + 1]; - char ngroup[STRBUF_SIZEOF(uid_t) + 1]; - char nuser[STRBUF_SIZEOF(gid_t) + 1]; - - /* - * If list is NULL there are two possibilities: that the parent - * directory p has no children, or that fts_children() returned an - * error. We ignore the error case since it will be replicated - * on the next call to fts_read() on the post-order visit to the - * directory p, and will be signaled in traverse(). - */ - if (list == NULL) - return; - - needstats = f_inode || f_longform || f_size; - flen = 0; - btotal = 0; - initmax = getenv("LS_COLWIDTHS"); - /* Fields match -lios order. New ones should be added at the end. */ - if (initmax != NULL && *initmax != '\0') { - char *initmax2, *jinitmax; - int ninitmax; - - /* Fill-in "::" as "0:0:0" for the sake of scanf. */ - jinitmax = initmax2 = malloc(strlen(initmax) * 2 + 2); - if (jinitmax == NULL) - err(1, NULL); - if (*initmax == ':') - strcpy(initmax2, "0:"), initmax2 += 2; - else - *initmax2++ = *initmax, *initmax2 = '\0'; - for (initmax++; *initmax != '\0'; initmax++) { - if (initmax[-1] == ':' && initmax[0] == ':') { - *initmax2++ = '0'; - *initmax2++ = initmax[0]; - initmax2[1] = '\0'; - } else { - *initmax2++ = initmax[0]; - initmax2[1] = '\0'; - } - } - if (initmax2[-1] == ':') strcpy(initmax2, "0"); - - ninitmax = sscanf(jinitmax, - " %lu : %lu : %lu : %i : %i : %i : %qu : %lu ", - &maxinode, &maxblock, &maxnlink, &maxuser, - &maxgroup, &maxflags, &maxsize, &maxlen); - f_notabs = 1; - switch (ninitmax) { - case 0: maxinode = 0; - case 1: maxblock = 0; - case 2: maxnlink = 0; - case 3: maxuser = 0; - case 4: maxgroup = 0; - case 5: maxflags = 0; - case 6: maxsize = 0; - case 7: maxlen = 0; -#ifdef COLORLS - if (!f_color) -#endif - f_notabs = 0; - } - maxinode = makenines(maxinode); - maxblock = makenines(maxblock); - maxnlink = makenines(maxnlink); - maxsize = makenines(maxsize); - } else if (initmax == NULL || *initmax == '\0') - maxblock = maxinode = maxlen = maxnlink = - maxuser = maxgroup = maxflags = maxsize = 0; - bcfile = 0; - flags = NULL; - for (cur = list, entries = 0; cur; cur = cur->fts_link) { - if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { - warnx("%s: %s", - cur->fts_name, strerror(cur->fts_errno)); - cur->fts_number = NO_PRINT; - rval = 1; - continue; - } - - /* - * P is NULL if list is the argv list, to which different rules - * apply. - */ - if (p == NULL) { - /* Directories will be displayed later. */ - if (cur->fts_info == FTS_D && !f_listdir) { - cur->fts_number = NO_PRINT; - continue; - } - } else { - /* Only display dot file if -a/-A set. */ - if (cur->fts_name[0] == '.' && !f_listdot) { - cur->fts_number = NO_PRINT; - continue; - } - } - if (cur->fts_namelen > maxlen) - maxlen = cur->fts_namelen; - if (f_octal || f_octal_escape) { - int t = len_octal(cur->fts_name, cur->fts_namelen); - if (t > maxlen) maxlen = t; - } - if (needstats) { - sp = cur->fts_statp; - if (sp->st_blocks > maxblock) - maxblock = sp->st_blocks; - if (sp->st_ino > maxinode) - maxinode = sp->st_ino; - if (sp->st_nlink > maxnlink) - maxnlink = sp->st_nlink; - if (sp->st_size > maxsize) - maxsize = sp->st_size; - - btotal += sp->st_blocks; - if (f_longform) { - if (f_numericonly) { - (void)snprintf(nuser, sizeof(nuser), - "%u", sp->st_uid); - (void)snprintf(ngroup, sizeof(ngroup), - "%u", sp->st_gid); - user = nuser; - group = ngroup; - } else { - user = user_from_uid(sp->st_uid, 0); - group = group_from_gid(sp->st_gid, 0); - } - if ((ulen = strlen(user)) > maxuser) - maxuser = ulen; - if ((glen = strlen(group)) > maxgroup) - maxgroup = glen; - if (f_flags) { - flags = fflagstostr(sp->st_flags); - if (flags != NULL && *flags == '\0') { - free(flags); - flags = strdup("-"); - } - if (flags == NULL) - err(1, NULL); - if ((flen = strlen(flags)) > maxflags) - maxflags = flen; - } else - flen = 0; - - if ((np = malloc(sizeof(NAMES) + - ulen + glen + flen + 3)) == NULL) - err(1, NULL); - - np->user = &np->data[0]; - (void)strcpy(np->user, user); - np->group = &np->data[ulen + 1]; - (void)strcpy(np->group, group); - - if (S_ISCHR(sp->st_mode) || - S_ISBLK(sp->st_mode)) - bcfile = 1; - - if (f_flags) { - np->flags = &np->data[ulen + glen + 2]; - (void)strcpy(np->flags, flags); - free(flags); - } - cur->fts_pointer = np; - } - } - ++entries; - } - - if (!entries) - return; - - d.list = list; - d.entries = entries; - d.maxlen = maxlen; - if (needstats) { - d.bcfile = bcfile; - d.btotal = btotal; - (void)snprintf(buf, sizeof(buf), "%lu", maxblock); - d.s_block = strlen(buf); - d.s_flags = maxflags; - d.s_group = maxgroup; - (void)snprintf(buf, sizeof(buf), "%lu", maxinode); - d.s_inode = strlen(buf); - (void)snprintf(buf, sizeof(buf), "%lu", maxnlink); - d.s_nlink = strlen(buf); - (void)snprintf(buf, sizeof(buf), "%qu", maxsize); - d.s_size = strlen(buf); - d.s_user = maxuser; - } - - printfcn(&d); - output = 1; - - if (f_longform) - for (cur = list; cur; cur = cur->fts_link) - free(cur->fts_pointer); -} - -/* - * Ordering for mastercmp: - * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories - * as larger than directories. Within either group, use the sort function. - * All other levels use the sort function. Error entries remain unsorted. - */ -static int -mastercmp(a, b) - const FTSENT **a, **b; -{ - int a_info, b_info; - - a_info = (*a)->fts_info; - if (a_info == FTS_ERR) - return (0); - b_info = (*b)->fts_info; - if (b_info == FTS_ERR) - return (0); - - if (a_info == FTS_NS || b_info == FTS_NS) - return (namecmp(*a, *b)); - - if (a_info != b_info && - (*a)->fts_level == FTS_ROOTLEVEL && !f_listdir) { - if (a_info == FTS_D) - return (1); - if (b_info == FTS_D) - return (-1); - } - return (sortfcn(*a, *b)); -} - -/* - * Makenines() returns (10**n)-1. This is useful for converting a width - * into a number that wide in decimal. - */ -static u_quad_t -makenines(n) - u_long n; -{ - u_long i; - u_quad_t reg; - - reg = 1; - /* Use a loop instead of pow(), since all values of n are small. */ - for (i = 0; i < n; i++) - reg *= 10; - reg--; - - return reg; -} diff --git a/ftpd.tproj/ls.h b/ftpd.tproj/ls.h deleted file mode 100644 index 1d10c12..0000000 --- a/ftpd.tproj/ls.h +++ /dev/null @@ -1,81 +0,0 @@ - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Michael Fischbein. - * - * 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. - * - * from: @(#)ls.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/ls/ls.h,v 1.14 2000/07/04 23:09:23 assar Exp $ - */ - -#define NO_PRINT 1 - -extern long blocksize; /* block size units */ - -extern int f_accesstime; /* use time of last access */ -extern int f_flags; /* show flags associated with a file */ -extern int f_inode; /* print inode */ -extern int f_longform; /* long listing format */ -extern int f_octal; /* print unprintables in octal */ -extern int f_octal_escape; /* like f_octal but use C escapes if possible */ -extern int f_nonprint; /* show unprintables as ? */ -extern int f_sectime; /* print the real time for all files */ -extern int f_size; /* list size in short listing */ -extern int f_statustime; /* use time of last mode change */ -extern int f_notabs; /* don't use tab-separated multi-col output */ -extern int f_type; /* add type character for non-regular files */ -#ifdef COLORLS -extern int f_color; /* add type in color for non-regular files */ -#endif - -typedef struct { - FTSENT *list; - u_long btotal; - int bcfile; - int entries; - int maxlen; - int s_block; - int s_flags; - int s_group; - int s_inode; - int s_nlink; - int s_size; - int s_user; -} DISPLAY; - -typedef struct { - char *user; - char *group; - char *flags; - char data[1]; -} NAMES; diff --git a/ftpd.tproj/popen.c b/ftpd.tproj/popen.c deleted file mode 100644 index dc7c682..0000000 --- a/ftpd.tproj/popen.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software written by Ken Arnold and - * published in UNIX Review, Vol. 6, No. 8. - * - * 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. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94"; -#endif -static const char rcsid[] = - "$FreeBSD: src/libexec/ftpd/popen.c,v 1.20 2001/03/19 19:11:00 jlemon Exp $"; -#endif /* not lint */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "extern.h" -#include "pathnames.h" -#include -#include -#include - -#define MAXUSRARGS 100 -#define MAXGLOBARGS 1000 - -/* - * Special version of popen which avoids call to shell. This ensures noone - * may create a pipe to a hidden program as a side effect of a list or dir - * command. - */ -static int *pids; -static int fds; - -FILE * -ftpd_popen(program, type) - char *program, *type; -{ - char *cp; - FILE *iop; - int argc, gargc, pdes[2], pid; - char **pop, *argv[MAXUSRARGS], *gargv[MAXGLOBARGS]; - - if (((*type != 'r') && (*type != 'w')) || type[1]) - return (NULL); - - if (!pids) { - if ((fds = getdtablesize()) <= 0) - return (NULL); - if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) - return (NULL); - memset(pids, 0, fds * sizeof(int)); - } - if (pipe(pdes) < 0) - return (NULL); - - /* break up string into pieces */ - for (argc = 0, cp = program; argc < MAXUSRARGS; cp = NULL) { - if (!(argv[argc++] = strtok(cp, " \t\n"))) - break; - } - argv[argc - 1] = NULL; - - /* glob each piece */ - gargv[0] = argv[0]; - for (gargc = argc = 1; argv[argc] && gargc < (MAXGLOBARGS-1); argc++) { - glob_t gl; - int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; - - memset(&gl, 0, sizeof(gl)); - gl.gl_matchc = MAXGLOBARGS; -#if !defined(GLOB_MAXPATH) -#define GLOB_MAXPATH 0x1000 -#endif - flags |= GLOB_MAXPATH; - if (glob(argv[argc], flags, NULL, &gl)) - gargv[gargc++] = strdup(argv[argc]); - else - for (pop = gl.gl_pathv; *pop && gargc < (MAXGLOBARGS-1); - pop++) - gargv[gargc++] = strdup(*pop); - globfree(&gl); - } - gargv[gargc] = NULL; - - iop = NULL; - fflush(NULL); - pid = (strcmp(gargv[0], _PATH_LS) == 0) ? fork() : vfork(); - switch(pid) { - case -1: /* error */ - (void)close(pdes[0]); - (void)close(pdes[1]); - goto pfree; - /* NOTREACHED */ - case 0: /* child */ - if (*type == 'r') { - if (pdes[1] != STDOUT_FILENO) { - dup2(pdes[1], STDOUT_FILENO); - (void)close(pdes[1]); - } - dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */ - (void)close(pdes[0]); - } else { - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - (void)close(pdes[0]); - } - (void)close(pdes[1]); - } - if (strcmp(gargv[0], _PATH_LS) == 0) { - /* Reset getopt for ls_main() */ - optreset = optind = optopt = 1; - /* Close syslogging to remove pwd.db missing msgs */ - closelog(); - /* Trigger to sense new /etc/localtime after chroot */ - if (getenv("TZ") == NULL) { - setenv("TZ", "", 0); - tzset(); - unsetenv("TZ"); - tzset(); - } - exit(ls_main(gargc, gargv)); - } - execv(gargv[0], gargv); - _exit(1); - } - /* parent; assume fdopen can't fail... */ - if (*type == 'r') { - iop = fdopen(pdes[0], type); - (void)close(pdes[1]); - } else { - iop = fdopen(pdes[1], type); - (void)close(pdes[0]); - } - pids[fileno(iop)] = pid; - -pfree: for (argc = 1; gargv[argc] != NULL; argc++) - free(gargv[argc]); - - return (iop); -} - -int -ftpd_pclose(iop) - FILE *iop; -{ - int fdes, omask, status; - pid_t pid; - - /* - * pclose returns -1 if stream is not associated with a - * `popened' command, or, if already `pclosed'. - */ - if (pids == 0 || pids[fdes = fileno(iop)] == 0) - return (-1); - (void)fclose(iop); - omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); - while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) - continue; - (void)sigsetmask(omask); - pids[fdes] = 0; - if (pid < 0) - return (pid); - if (WIFEXITED(status)) - return (WEXITSTATUS(status)); - return (1); -} diff --git a/ftpd.tproj/print.c b/ftpd.tproj/print.c deleted file mode 100644 index 7bd2471..0000000 --- a/ftpd.tproj/print.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Michael Fischbein. - * - * 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. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94"; -#else -static const char rcsid[] = - "$FreeBSD: src/bin/ls/print.c,v 1.38 2001/03/21 15:14:47 ache Exp $"; -#endif -#endif /* not lint */ - -#include -#include - -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#ifdef COLORLS -#include -#include -#include -#endif - -#include "ls.h" -#include "ls_extern.h" - -static int printaname __P((FTSENT *, u_long, u_long)); -static void printlink __P((FTSENT *)); -static void printtime __P((time_t)); -static int printtype __P((u_int)); -#ifdef COLORLS -static void endcolor __P((int)); -static int colortype __P((mode_t)); -#endif - -#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) - -#ifdef COLORLS -/* Most of these are taken from */ -typedef enum Colors { - C_DIR, /* directory */ - C_LNK, /* symbolic link */ - C_SOCK, /* socket */ - C_FIFO, /* pipe */ - C_EXEC, /* executable */ - C_BLK, /* block special */ - C_CHR, /* character special */ - C_SUID, /* setuid executable */ - C_SGID, /* setgid executable */ - C_WSDIR, /* directory writeble to others, with sticky bit */ - C_WDIR, /* directory writeble to others, without sticky bit */ - C_NUMCOLORS /* just a place-holder */ -} Colors ; - -char *defcolors = "4x5x2x3x1x464301060203"; - -static int colors[C_NUMCOLORS][2]; -#endif - -void -printscol(dp) - DISPLAY *dp; -{ - FTSENT *p; - - for (p = dp->list; p; p = p->fts_link) { - if (IS_NOPRINT(p)) - continue; - (void)printaname(p, dp->s_inode, dp->s_block); - (void)putchar('\n'); - } -} - -/* - * print name in current style - */ -static int -printname(name) - const char *name; -{ - if (f_octal || f_octal_escape) - return prn_octal(name); - else if (f_nonprint) - return prn_printable(name); - else - return printf("%s", name); -} - -void -printlong(dp) - DISPLAY *dp; -{ - struct stat *sp; - FTSENT *p; - NAMES *np; - char buf[20]; -#ifdef COLORLS - int color_printed = 0; -#endif - - if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) - (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); - - for (p = dp->list; p; p = p->fts_link) { - if (IS_NOPRINT(p)) - continue; - sp = p->fts_statp; - if (f_inode) - (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino); - if (f_size) - (void)printf("%*qd ", - dp->s_block, howmany(sp->st_blocks, blocksize)); - (void)strmode(sp->st_mode, buf); - np = p->fts_pointer; - (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink, - sp->st_nlink, dp->s_user, np->user, dp->s_group, - np->group); - if (f_flags) - (void)printf("%-*s ", dp->s_flags, np->flags); - if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) - if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0) - (void)printf("%3d, 0x%08x ", - major(sp->st_rdev), - (u_int)minor(sp->st_rdev)); - else - (void)printf("%3d, %3d ", - major(sp->st_rdev), minor(sp->st_rdev)); - else if (dp->bcfile) - (void)printf("%*s%*qd ", - 8 - dp->s_size, "", dp->s_size, sp->st_size); - else - (void)printf("%*qd ", dp->s_size, sp->st_size); - if (f_accesstime) - printtime(sp->st_atime); - else if (f_statustime) - printtime(sp->st_ctime); - else - printtime(sp->st_mtime); -#ifdef COLORLS - if (f_color) - color_printed = colortype(sp->st_mode); -#endif - (void)printname(p->fts_name); -#ifdef COLORLS - if (f_color && color_printed) - endcolor(0); -#endif - if (f_type) - (void)printtype(sp->st_mode); - if (S_ISLNK(sp->st_mode)) - printlink(p); - (void)putchar('\n'); - } -} - -void -printcol(dp) - DISPLAY *dp; -{ - extern int termwidth; - static FTSENT **array; - static int lastentries = -1; - FTSENT *p; - int base, chcnt, cnt, col, colwidth, num; - int endcol, numcols, numrows, row; - int tabwidth; - - if (f_notabs) - tabwidth = 1; - else - tabwidth = 8; - - /* - * Have to do random access in the linked list -- build a table - * of pointers. - */ - if (dp->entries > lastentries) { - lastentries = dp->entries; - if ((array = - realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) { - warn(NULL); - printscol(dp); - } - } - for (p = dp->list, num = 0; p; p = p->fts_link) - if (p->fts_number != NO_PRINT) - array[num++] = p; - - colwidth = dp->maxlen; - if (f_inode) - colwidth += dp->s_inode + 1; - if (f_size) - colwidth += dp->s_block + 1; - if (f_type) - colwidth += 1; - - colwidth = (colwidth + tabwidth) & ~(tabwidth - 1); - if (termwidth < 2 * colwidth) { - printscol(dp); - return; - } - - numcols = termwidth / colwidth; - numrows = num / numcols; - if (num % numcols) - ++numrows; - - if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) - (void)printf("total %lu\n", howmany(dp->btotal, blocksize)); - for (row = 0; row < numrows; ++row) { - endcol = colwidth; - for (base = row, chcnt = col = 0; col < numcols; ++col) { - chcnt += printaname(array[base], dp->s_inode, - dp->s_block); - if ((base += numrows) >= num) - break; - while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1))) - <= endcol){ - (void)putchar(f_notabs ? ' ' : '\t'); - chcnt = cnt; - } - endcol += colwidth; - } - (void)putchar('\n'); - } -} - -/* - * print [inode] [size] name - * return # of characters printed, no trailing characters. - */ -static int -printaname(p, inodefield, sizefield) - FTSENT *p; - u_long sizefield, inodefield; -{ - struct stat *sp; - int chcnt; -#ifdef COLORLS - int color_printed = 0; -#endif - - sp = p->fts_statp; - chcnt = 0; - if (f_inode) - chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino); - if (f_size) - chcnt += printf("%*qd ", - (int)sizefield, howmany(sp->st_blocks, blocksize)); -#ifdef COLORLS - if (f_color) - color_printed = colortype(sp->st_mode); -#endif - chcnt += printname(p->fts_name); -#ifdef COLORLS - if (f_color && color_printed) - endcolor(0); -#endif - if (f_type) - chcnt += printtype(sp->st_mode); - return (chcnt); -} - -static void -printtime(ftime) - time_t ftime; -{ - char longstring[80]; - static time_t now; - const char *format; - static int d_first = -1; - - if (d_first < 0) -#if defined(HAVE_LANGINFO) - d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); -#else - d_first = 0; -#endif - if (now == 0) - now = time(NULL); - -#define SIXMONTHS ((365 / 2) * 86400) - if (f_sectime) - /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */ - format = d_first ? "%e %b %T %Y " : "%b %e %T %Y "; - else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS) - /* mmm dd hh:mm || dd mmm hh:mm */ - format = d_first ? "%e %b %R " : "%b %e %R "; - else - /* mmm dd yyyy || dd mmm yyyy */ - format = d_first ? "%e %b %Y " : "%b %e %Y "; - strftime(longstring, sizeof(longstring), format, localtime(&ftime)); - fputs(longstring, stdout); -} - -static int -printtype(mode) - u_int mode; -{ - switch (mode & S_IFMT) { - case S_IFDIR: - (void)putchar('/'); - return (1); - case S_IFIFO: - (void)putchar('|'); - return (1); - case S_IFLNK: - (void)putchar('@'); - return (1); - case S_IFSOCK: - (void)putchar('='); - return (1); - case S_IFWHT: - (void)putchar('%'); - return (1); - } - if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { - (void)putchar('*'); - return (1); - } - return (0); -} - -#ifdef COLORLS -static int -putch(c) - int c; -{ - (void) putchar(c); - return 0; -} - -static int -writech(c) - int c; -{ - char tmp = c; - - (void) write(STDOUT_FILENO, &tmp, 1); - return 0; -} - -static void -printcolor(c) - Colors c; -{ - char *ansiseq; - - if (colors[c][0] != -1) { - ansiseq = tgoto(ansi_fgcol, 0, colors[c][0]); - if (ansiseq) - tputs(ansiseq, 1, putch); - } - - if (colors[c][1] != -1) { - ansiseq = tgoto(ansi_bgcol, 0, colors[c][1]); - if (ansiseq) - tputs(ansiseq, 1, putch); - } -} - -static void -endcolor(sig) - int sig; -{ - tputs(ansi_coloff, 1, sig ? writech : putch); -} - -static int -colortype(mode) - mode_t mode; -{ - switch(mode & S_IFMT) { - case S_IFDIR: - if (mode & S_IWOTH) - if (mode & S_ISTXT) - printcolor(C_WSDIR); - else - printcolor(C_WDIR); - else - printcolor(C_DIR); - return(1); - case S_IFLNK: - printcolor(C_LNK); - return(1); - case S_IFSOCK: - printcolor(C_SOCK); - return(1); - case S_IFIFO: - printcolor(C_FIFO); - return(1); - case S_IFBLK: - printcolor(C_BLK); - return(1); - case S_IFCHR: - printcolor(C_CHR); - return(1); - } - if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) { - if (mode & S_ISUID) - printcolor(C_SUID); - else if (mode & S_ISGID) - printcolor(C_SGID); - else - printcolor(C_EXEC); - return(1); - } - return(0); -} - -void -parsecolors(cs) -char *cs; -{ - int i, j, len; - char c[2]; - - if (cs == NULL) cs = ""; /* LSCOLORS not set */ - len = strlen(cs); - for (i = 0 ; i < C_NUMCOLORS ; i++) { - if (len <= 2*i) { - c[0] = defcolors[2*i]; - c[1] = defcolors[2*i+1]; - } - else { - c[0] = cs[2*i]; - c[1] = cs[2*i+1]; - } - for (j = 0 ; j < 2 ; j++) { - if ((c[j] < '0' || c[j] > '7') && - tolower((unsigned char)c[j]) != 'x') { - fprintf(stderr, - "error: invalid character '%c' in LSCOLORS env var\n", - c[j]); - c[j] = defcolors[2*i+j]; - } - if (tolower((unsigned char)c[j]) == 'x') - colors[i][j] = -1; - else - colors[i][j] = c[j]-'0'; - } - } -} - -void -colorquit(sig) - int sig; -{ - endcolor(sig); - - (void) signal(sig, SIG_DFL); - (void) kill(getpid(), sig); -} -#endif /*COLORLS*/ - -static void -printlink(p) - FTSENT *p; -{ - int lnklen; - char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1]; - - if (p->fts_level == FTS_ROOTLEVEL) - (void)snprintf(name, sizeof(name), "%s", p->fts_name); - else - (void)snprintf(name, sizeof(name), - "%s/%s", p->fts_parent->fts_accpath, p->fts_name); - if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) { - (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno)); - return; - } - path[lnklen] = '\0'; - (void)printf(" -> "); - printname(path); -} diff --git a/ftpd.tproj/util.c b/ftpd.tproj/util.c deleted file mode 100644 index e6ac806..0000000 --- a/ftpd.tproj/util.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Michael Fischbein. - * - * 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. - */ - -#ifndef lint -#if 0 -static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94"; -#else -static const char rcsid[] = - "$FreeBSD: src/bin/ls/util.c,v 1.23 2000/07/22 05:28:46 green Exp $"; -#endif -#endif /* not lint */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "ls.h" -#include "ls_extern.h" - -int -prn_printable(s) - const char *s; -{ - unsigned char c; - int n; - - for (n = 0; (c = *s) != '\0'; ++s, ++n) - if (isprint(c)) - putchar(c); - else - putchar('?'); - return n; -} - -/* - * The fts system makes it difficult to replace fts_name with a different- - * sized string, so we just calculate the real length here and do the - * conversion in prn_octal() - * - * XXX when using f_octal_escape (-b) rather than f_octal (-B), the - * length computed by len_octal may be too big. I just can't be buggered - * to fix this as an efficient fix would involve a lookup table. Same goes - * for the rather inelegant code in prn_octal. - * - * DES 1998/04/23 - */ - -int -len_octal(s, len) - const char *s; - int len; -{ - int r = 0; - - while (len--) - if (isprint((unsigned char)*s++)) r++; else r += 4; - return r; -} - -int -prn_octal(s) - const char *s; -{ - unsigned char ch; - int len = 0; - - while ((ch = *s++)) - { - if (isprint(ch) && (ch != '\"') && (ch != '\\')) - putchar(ch), len++; - else if (f_octal_escape) { - putchar('\\'); - switch (ch) { - case '\\': - putchar('\\'); - break; - case '\"': - putchar('"'); - break; - case '\a': - putchar('a'); - break; - case '\b': - putchar('b'); - break; - case '\f': - putchar('f'); - break; - case '\n': - putchar('n'); - break; - case '\r': - putchar('r'); - break; - case '\t': - putchar('t'); - break; - case '\v': - putchar('v'); - break; - default: - putchar('0' + (ch >> 6)); - putchar('0' + ((ch >> 3) & 7)); - putchar('0' + (ch & 7)); - len += 2; - break; - } - len += 2; - } - else { - putchar('\\'); - putchar('0' + (ch >> 6)); - putchar('0' + ((ch >> 3) & 7)); - putchar('0' + (ch & 7)); - len += 4; - } - } - return len; -} - -void -usage() -{ - (void)fprintf(stderr, -#ifdef COLORLS - "usage: ls [-ABCFGHLPRTWabcdfgiklnoqrstu1]" -#else - "usage: ls [-ABCFHLPRTWabcdfgiklnoqrstu1]" -#endif - " [file ...]\n"); - exit(1); -} diff --git a/identd.tproj/Makefile b/identd.tproj/Makefile index b8d220f..c3ee7d2 100644 --- a/identd.tproj/Makefile +++ b/identd.tproj/Makefile @@ -16,7 +16,7 @@ HFILES = error.h identd.h xpaths.h CFILES = config.c identd.c netbsd.c parse.c proxy.c version.c -OTHERSRCS = CREDITS Makefile.dist README identd.8 Makefile.preamble +OTHERSRCS = CREDITS Makefile.dist README identd.8 Makefile.preamble Makefile.postamble MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/identd.tproj/Makefile.postamble b/identd.tproj/Makefile.postamble new file mode 100644 index 0000000..b4ab713 --- /dev/null +++ b/identd.tproj/Makefile.postamble @@ -0,0 +1,3 @@ +after_install: + install -d $(DSTROOT)/usr/share/man/man8 + install -c -m 444 identd.8 $(DSTROOT)/usr/share/man/man8 diff --git a/identd.tproj/identd.8 b/identd.tproj/identd.8 index 4bf839c..6c8a67e 100644 --- a/identd.tproj/identd.8 +++ b/identd.tproj/identd.8 @@ -2,7 +2,7 @@ .\" Copyright (c) 1992 Peter Eriksson, Lysator, Linkoping University. .\" This software has been released into the public domain. .\" -.\" $Id: identd.8,v 1.1.1.1 1999/05/02 03:57:41 wsanchez Exp $ +.\" $Id: identd.8,v 1.2 2002/03/29 01:34:27 bbraun Exp $ .\" .TH IDENTD 8 "27 May 1992" .SH NAME @@ -62,7 +62,7 @@ flag should be used when starting the daemon from .B inetd with the "wait" option in the .B /etc/inetd.conf -file . This is the prefered mode of +file . This is the preferred mode of operation since that will start a copy of .B identd at the first connection request and then @@ -83,7 +83,7 @@ The flag can be used to make the daemon run in standalone mode without the assistance from .B inetd. -This mode is the least prefered mode since +This mode is the least preferred mode since a bug or any other fatal condition in the server will make it terminate and it will then have to be restarted manually. Other than that is has the same advantage as the diff --git a/ifconfig.tproj/Makefile.preamble b/ifconfig.tproj/Makefile.preamble index 5a6d897..bf2aff8 100644 --- a/ifconfig.tproj/Makefile.preamble +++ b/ifconfig.tproj/Makefile.preamble @@ -1,3 +1,3 @@ OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include -OTHER_CFLAGS += -DUSE_IF_MEDIA +OTHER_CFLAGS += -DUSE_IF_MEDIA -DINET6 -DNO_IPX diff --git a/ifconfig.tproj/ifconfig.8 b/ifconfig.tproj/ifconfig.8 index 216d66a..f525c81 100644 --- a/ifconfig.tproj/ifconfig.8 +++ b/ifconfig.tproj/ifconfig.8 @@ -10,7 +10,7 @@ .\" 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: +.\" must display the following acknowledgment: .\" 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 @@ -29,35 +29,48 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94 +.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94 +.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.27.2.14 2001/08/23 06:35:38 yar Exp $ .\" -.Dd June 1, 1994 +.Dd July 2, 2001 .Dt IFCONFIG 8 -.Os BSD 4.2 +.Os .Sh NAME .Nm ifconfig .Nd configure network interface parameters .Sh SYNOPSIS -.Nm ifconfig -.Ar interface address_family +.Nm +.Op Fl L +.Op Fl m +.Ar interface +.Op Cm create +.Op Ar address_family .Oo -.Ar address +.Ar address Ns Op Cm / Ns Ar prefixlength .Op Ar dest_address .Oc .Op Ar parameters -.Nm ifconfig +.Nm .Ar interface -.Op Ar protocol_family -.Nm ifconfig +.Cm destroy +.Nm .Fl a +.Op Fl L .Op Fl d +.Op Fl m .Op Fl u .Op Ar address_family -.Nm ifconfig +.Nm .Fl l .Op Fl d .Op Fl u .Op Ar address_family +.Nm +.Op Fl L +.Op Fl d +.Op Fl m +.Op Fl u +.Op Fl C .Sh DESCRIPTION .Nm Ifconfig is used to assign an address @@ -69,99 +82,117 @@ of each interface present on a machine; it may also be used at a later time to redefine an interface's address or other operating parameters. .Pp -Available operands for -.Nm ifconfig: -.Bl -tag -width Ds -.It Ar Address +The following options are available: +.Bl -tag -width indent +.It Ar address For the -.Tn DARPA-Internet +.Tn DARPA Ns -Internet family, the address is either a host name present in the host name data -base, +base, .Xr hosts 5 , or a .Tn DARPA Internet address expressed in the Internet standard .Dq dot notation . -For the Xerox Network Systems(tm) family, -addresses are -.Ar net:a.b.c.d.e.f , -where -.Ar net -is the assigned network number (in decimal), -and each of the six bytes of the host number, -.Ar a -through -.Ar f , -are specified in hexadecimal. -The host number may be omitted on 10Mb/s Ethernet interfaces, -which use the hardware physical address, -and on interfaces other than the first. -For the -.Tn ISO -family, addresses are specified as a long hexadecimal string, -as in the Xerox family. However, two consecutive dots imply a zero -byte, and the dots are optional, if the user wishes to (carefully) -count out long strings of digits in network byte order. +.Pp +It is also possible to use the CIDR notation (also known as the +slash notation) to include the netmask. +That is, one can specify an address like +.Li 192.168.0.1/16 . +.\" For the Xerox Network Systems(tm) family, +.\" addresses are +.\" .Ar net:a.b.c.d.e.f , +.\" where +.\" .Ar net +.\" is the assigned network number (in decimal), +.\" and each of the six bytes of the host number, +.\" .Ar a +.\" through +.\" .Ar f , +.\" are specified in hexadecimal. +.\" The host number may be omitted on IEEE 802 protocol +.\" (Ethernet, FDDI, and Token Ring) interfaces, +.\" which use the hardware physical address, +.\" and on interfaces other than the first. +.\" For the +.\" .Tn ISO +.\" family, addresses are specified as a long hexadecimal string, +.\" as in the Xerox family. +.\" However, two consecutive dots imply a zero +.\" byte, and the dots are optional, if the user wishes to (carefully) +.\" count out long strings of digits in network byte order. .It Ar address_family -Specifies the -.Ar address family +Specify the +address family which affects interpretation of the remaining parameters. Since an interface can receive transmissions in differing protocols -with different naming schemes, specifying the address family is recommeded. +with different naming schemes, specifying the address family is recommended. The address or protocol families currently supported are .Dq inet , -.Dq iso , -and -.Dq ns . -.It Ar Interface -The -.Ar interface +.Dq inet6 , +.\" and +.\" .Dq ns . +.It Ar dest_address +Specify the address of the correspondent on the other end +of a point to point link. +.It Ar interface +This parameter is a string of the form .Dq name unit , for example, -.Dq en0 +.Dq Li en0 . .El .Pp -The following parameters may be set with -.Nm ifconfig : -.Bl -tag -width dest_addressxx +The following parameters may be set with +.Nm : +.Bl -tag -width indent +.It Cm add +Another name for the +.Cm alias +parameter. +Introduced for compatibility +with +.Bsx . .It Cm alias -Establish an additional network address for this interface. This is -sometimes useful when changing network numbers, and one wishes to -accept packets addressed to the old interface. -A -.Ar netmask -should be used with this parameter. -If the new ( -.Ar alias -) address is on the same subnet as an existing address assigned to -this interface, the netmask must be "255.255.255.255". If a netmask -is not supplied, the command will use the one implied by the address -itself (e.g, Class A). If the 'all ones' netmask is used, the system -will handle route installation. If another netmask is used, a route -to that address must be installed by hand, e.g., "route add -host -XX.XX.XX.XX -interface 127.0.0.1", where "XX.XX.XX.XX" is the new -alias (c.f. -.Ar route -(8)). In either case, the administrator may have to remove a route -by hand when the alias is removed ( -.Ar -alias -or -.Ar delete -) +Establish an additional network address for this interface. +This is sometimes useful when changing network numbers, and +one wishes to accept packets addressed to the old interface. +If the address is on the same subnet as the first network address +for this interface, a netmask of +.Li 0xffffffff +has to be specified. +.It Fl alias +Remove the network address specified. +This would be used if you incorrectly specified an alias, or it +was no longer needed. +If you have incorrectly set an NS address having the side effect +of specifying the host portion, removing all NS addresses will +allow you to respecify the host portion. +.It Cm anycast +(Inet6 only.) +Specify that the address configured is an anycast address. +Based on the current specification, +only routers may configure anycast addresses. +Anycast address will not be used as source address of any of outgoing +IPv6 packets. .It Cm arp -Enable the use of the Address Resolution Protocol in mapping +Enable the use of the Address Resolution Protocol +.Pq Xr arp 4 +in mapping between network level addresses and link level addresses (default). This is currently implemented for mapping between .Tn DARPA Internet -addresses and 10Mb/s Ethernet addresses. +addresses and +.Tn IEEE +802 48-bit MAC addresses (Ethernet, FDDI, and Token Ring addresses). .It Fl arp -Disable the use of the Address Resolution Protocol. +Disable the use of the Address Resolution Protocol +.Pq Xr arp 4 . .It Cm broadcast -(Inet only) +(Inet only.) Specify the address to use to represent broadcasts to the network. The default broadcast address is the address with a host part of all 1's. @@ -170,32 +201,112 @@ Enable driver dependent debugging code; usually, this turns on extra console error logging. .It Fl debug Disable driver dependent debugging code. -.ne 1i .It Cm delete -Remove the network address specified. -This would be used if you incorrectly specified an alias, or it -was no longer needed. -If you have incorrectly set an NS address having the side effect -of specifying the host portion, removing all NS addresses will -allow you to respecify the host portion. -.It Cm dest_address -Specify the address of the correspondent on the other end -of a point to point link. +Another name for the +.Fl alias +parameter. .It Cm down -Mark an interface ``down''. When an interface is -marked ``down'', the system will not attempt to -transmit messages through that interface. +Mark an interface +.Dq down . +When an interface is marked +.Dq down , +the system will not attempt to +transmit messages through that interface. If possible, the interface will be reset to disable reception as well. This action does not automatically disable routes using the interface. -.It Cm ipdst -This is used to specify an Internet host who is willing to receive -ip packets encapsulating NS packets bound for a remote network. -An apparent point to point link is constructed, and -the address specified will be taken as the NS address and network -of the destination. -IP encapsulation of -.Tn CLNP -packets is done differently. +.It Cm ether +Another name for the +.Cm lladdr +parameter. +.\" .It Cm ipdst +.\" This is used to specify an Internet host who is willing to receive +.\" ip packets encapsulating NS packets bound for a remote network. +.\" An apparent point to point link is constructed, and +.\" the address specified will be taken as the NS address and network +.\" of the destination. +.\" IP encapsulation of +.\" .Tn CLNP +.\" packets is done differently. +.It Cm lladdr Ar addr +Set the link-level address on an interface. +This can be used to +e.g. set a new MAC address on an ethernet interface, though the +mechanism used is not ethernet-specific. +The address +.Ar addr +is specified as a series of colon-separated hex digits. +If the interface is already +up when this option is used, it will be briefly brought down and +then brought back up again in order to ensure that the receive +filter in the underlying ethernet hardware is properly reprogrammed. +.It Cm media Ar type +If the driver supports the media selection system, set the media type +of the interface to +.Ar type . +Some interfaces support the mutually exclusive use of one of several +different physical media connectors. +For example, a 10Mb/s Ethernet +interface might support the use of either +.Tn AUI +or twisted pair connectors. +Setting the media type to +.Dq 10base5/AUI +would change the currently active connector to the AUI port. +Setting it to +.Dq 10baseT/UTP +would activate twisted pair. +Refer to the interfaces' driver +specific documentation or man page for a complete list of the +available types. +.It Cm mediaopt Ar opts +If the driver supports the media selection system, set the specified +media options on the interface. +The +.Ar opts +argument +is a comma delimited list of options to apply to the interface. +Refer to the interfaces' driver specific man page for a complete +list of available options. +.It Fl mediaopt Ar opts +If the driver supports the media selection system, disable the +specified media options on the interface. +.It Cm tunnel Ar src_addr dest_addr +(IP tunnel devices only.) +Configure the physical source and destination address for IP tunnel +interfaces +.Pq Xr gif 4 . +The arguments +.Ar src_addr +and +.Ar dest_addr +are interpreted as the outer source/destination for the encapsulating +IPv4/IPv6 header. +.It Cm deletetunnel +Unconfigure the physical source and destination address for IP tunnel +interfaces previously configured with +.Cm tunnel . +.It Cm create +Create the specified network pseudo-device. +If the interface is given without a unit number, try to create a new +device with an arbitrary unit number. +If creation of an arbitrary device is sucessful, the new device name is +printed to standard output. +.It Cm destroy +Destroy the specified network pseudo-device. +.It Cm plumb +Another name for the +.Cm create +parameter. +Included for +.Tn Solaris +compatibility. +.It Cm unplumb +Another name for the +.Cm destroy +parameter. +Included for +.Tn Solaris +compatibility. .It Cm metric Ar n Set the routing metric of the interface to .Ar n , @@ -205,14 +316,25 @@ The routing metric is used by the routing protocol Higher metrics have the effect of making a route less favorable; metrics are counted as addition hops to the destination network or host. +.It Cm mtu Ar n +Set the maximum transmission unit of the interface to +.Ar n , +default is interface specific. +The MTU is used to limit the size of packets that are transmitted on an +interface. +Not all interfaces support setting the MTU, and some interfaces have +range restrictions. .It Cm netmask Ar mask -(Inet and ISO) +.\" (Inet and ISO.) +(Inet only.) Specify how much of the address to reserve for subdividing networks into sub-networks. The mask includes the network part of the local address and the subnet part, which is taken from the host field of the address. The mask can be specified as a single hexadecimal number -with a leading 0x, with a dot-notation Internet address, +with a leading +.Ql 0x , +with a dot-notation Internet address, or with a pseudo-network name listed in the network table .Xr networks 5 . The mask contains 1's for the bit positions in the 32-bit address @@ -221,98 +343,155 @@ and 0's for the host part. The mask should contain at least the standard network portion, and the subnet field should be contiguous with the network portion. -.\" see +.Pp +The netmask can also be specified in CIDR notation after the address. +See the +.Ar address +option above for more information. +.It Cm prefixlen Ar len +(Inet6 only.) +Specify that +.Ar len +bits are reserved for subdividing networks into sub-networks. +The +.Ar len +must be integer, and for syntactical reason it must be between 0 to 128. +It is almost always 64 under the current IPv6 assignment rule. +If the parameter is omitted, 64 is used. +.\" see .\" Xr eon 5 . -.It Cm nsellength Ar n -.Pf ( Tn ISO -only) -This specifies a trailing number of bytes for a received -.Tn NSAP -used for local identification, the remaining leading part of which is -taken to be the -.Tn NET -(Network Entity Title). -The default value is 1, which is conformant to US -.Tn GOSIP . -When an ISO address is set in an ifconfig command, -it is really the -.Tn NSAP -which is being specified. -For example, in -.Tn US GOSIP , -20 hex digits should be -specified in the -.Tn ISO NSAP -to be assigned to the interface. -There is some evidence that a number different from 1 may be useful -for -.Tn AFI -37 type addresses. -.It Cm trailers -Request the use of a ``trailer'' link level encapsulation when -sending (default). -If a network interface supports -.Cm trailers , -the system will, when possible, encapsulate outgoing -messages in a manner which minimizes the number of -memory to memory copy operations performed by the receiver. -On networks that support the Address Resolution Protocol (see -.Xr arp 4 ; -currently, only 10 Mb/s Ethernet), -this flag indicates that the system should request that other -systems use trailers when sending to this host. -Similarly, trailer encapsulations will be sent to other -hosts that have made such requests. -Currently used by Internet protocols only. -.It Fl trailers -Disable the use of a ``trailer'' link level encapsulation. -.It Cm link[0-2] +.\" .It Cm nsellength Ar n +.\" .Pf ( Tn ISO +.\" only) +.\" This specifies a trailing number of bytes for a received +.\" .Tn NSAP +.\" used for local identification, the remaining leading part of which is +.\" taken to be the +.\" .Tn NET +.\" (Network Entity Title). +.\" The default value is 1, which is conformant to US +.\" .Tn GOSIP . +.\" When an ISO address is set in an ifconfig command, +.\" it is really the +.\" .Tn NSAP +.\" which is being specified. +.\" For example, in +.\" .Tn US GOSIP , +.\" 20 hex digits should be +.\" specified in the +.\" .Tn ISO NSAP +.\" to be assigned to the interface. +.\" There is some evidence that a number different from 1 may be useful +.\" for +.\" .Tn AFI +.\" 37 type addresses. +.It Cm remove +Another name for the +.Fl alias +parameter. +Introduced for compatibility +with +.Bsx . +.Sm off +.It Cm link Op Cm 0 No - Cm 2 +.Sm on Enable special processing of the link level of the interface. These three options are interface specific in actual effect, however, -they are in general used to select special modes of operation. An example -of this is to enable SLIP compression. Currently, only used by SLIP. -.ne 1i -.It Fl link[0-2] +they are in general used to select special modes of operation. +An example +of this is to enable SLIP compression, or to select the connector type +for some Ethernet cards. +Refer to the man page for the specific driver +for more information. +.Sm off +.It Fl link Op Cm 0 No - Cm 2 +.Sm on Disable special processing at the link level with the specified interface. .It Cm up -Mark an interface ``up''. -This may be used to enable an interface after an ``ifconfig down.'' +Mark an interface +.Dq up . +This may be used to enable an interface after an +.Dq Nm Cm down . It happens automatically when setting the first address on an interface. If the interface was reset when previously marked down, the hardware will be re-initialized. .El .Pp -Special flags for -.Nm ifconfig: -.Bl -tag -width Ds -.It -a -Produce a full listing for all available interfaces. -.It -l -Produce a name-only listing for all available interfaces. -.It -d -limit the listing to those interfaces that are down. -.It -u -limit the listing to those interfaces that are up. -.El -.Pp -.Pp .Nm Ifconfig displays the current configuration for a network interface when no optional parameters are supplied. If a protocol family is specified, -Ifconfig will report only the details specific to that protocol family. +.Nm +will report only the details specific to that protocol family. +.Pp +If the driver does supports the media selection system, the supported +media list will be included in the output. +.Pp +If the +.Fl m +flag is passed before an interface name, +.Nm +will display all +of the supported media for the specified interface. +If +.Fl L +flag is supplied, address lifetime is displayed for IPv6 addresses, +as time offset string. +.Pp +Optionally, the +.Fl a +flag may be used instead of an interface name. +This flag instructs +.Nm +to display information about all interfaces in the system. +The +.Fl d +flag limits this to interfaces that are down, and +.Fl u +limits this to interfaces that are up. +When no arguments are given, +.Fl a +is implied. +.Pp +The +.Fl l +flag may be used to list all available interfaces on the system, with +no other additional information. +Use of this flag is mutually exclusive +with all other flags and commands, except for +.Fl d +(only list interfaces that are down) +and +.Fl u +(only list interfaces that are up). +.Pp +The +.Fl C +flag may be used to list all of the interface cloners available on +the system, with no additional information. +Use of this flag is mutually exclusive with all other flags and commands. .Pp Only the super-user may modify the configuration of a network interface. +.Sh NOTES +The media selection system is relatively new and only some drivers support +it (or have need for it). .Sh DIAGNOSTICS -Messages indicating the specified interface does not exit, the +Messages indicating the specified interface does not exist, the requested address is unknown, or the user is not privileged and tried to alter an interface's configuration. +.Sh BUGS +IPv6 link-local addresses are required for several basic communication +between IPv6 node. +If they are deleted by +.Nm +manually, the kernel might show very strange behavior. +So, such manual deletions are strongly discouraged. .Sh SEE ALSO .Xr netstat 1 , .Xr netintro 4 , +.\" .Xr eon 5 , .Xr rc 8 , -.Xr routed 8 , -.\" .Xr eon 5 +.Xr routed 8 .Sh HISTORY The .Nm diff --git a/ifconfig.tproj/ifconfig.c b/ifconfig.tproj/ifconfig.c index a69654e..39f344a 100644 --- a/ifconfig.tproj/ifconfig.c +++ b/ifconfig.tproj/ifconfig.c @@ -42,7 +42,7 @@ static const char copyright[] = static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; #endif static const char rcsid[] = - "$Id: ifconfig.c,v 1.2 2001/08/03 16:27:01 vlubet Exp $"; + "$Id: ifconfig.c,v 1.4 2002/03/05 20:35:12 lindak Exp $"; #endif /* not lint */ #include @@ -51,6 +51,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -63,6 +64,17 @@ static const char rcsid[] = #include #include +#ifdef INET6 +#include /* Define ND6_INFINITE_LIFETIME */ +#endif + + +/* XNS */ +#ifdef NS +#define NSIP +#include +#include +#endif /* OSI */ #include @@ -76,8 +88,23 @@ static const char rcsid[] = #include "ifconfig.h" +/* wrapper for KAME-special getnameinfo() */ +#ifndef NI_WITHSCOPEID +#define NI_WITHSCOPEID 0 +#endif + struct ifreq ifr, ridreq; struct ifaliasreq addreq; +#ifdef INET6 +struct in6_ifreq in6_ridreq; +struct in6_aliasreq in6_addreq = + { { 0 }, + { 0 }, + { 0 }, + { 0 }, + 0, + { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; +#endif struct sockaddr_in netmask; @@ -87,12 +114,23 @@ int metric; int mtu; int setaddr; int setipdst; +int setmask; int doalias; int clearaddr; -int newaddr; +int newaddr = 1; +#ifdef INET6 +static int ip6lifetime; +#endif struct afswtch; +int supmedia = 0; +int listcloners = 0; + +#ifdef INET6 +char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ +#endif + void Perror __P((const char *cmd)); int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp)); @@ -102,22 +140,41 @@ void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); void status __P((const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl, struct if_msghdr *ifm, struct ifa_msghdr *ifam)); +void tunnel_status __P((int s)); void usage __P((void)); -typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp)); +#ifdef INET6 +void in6_fillscopeid __P((struct sockaddr_in6 *sin6)); +int prefix __P((void *, int)); +static char *sec2str __P((time_t)); +int explicit_prefix = 0; +#endif +typedef void c_func __P((const char *cmd, int arg, int s, const struct afswtch *afp)); +typedef void c_func2 __P((const char *arg, const char *arg2, int s, const struct afswtch *afp)); c_func setifaddr, setifbroadaddr, setifdstaddr, setifnetmask; +c_func2 settunnel; +c_func deletetunnel; +#ifdef INET6 +c_func setifprefixlen; +c_func setip6flags; +c_func setip6pltime; +c_func setip6vltime; +c_func2 setip6lifetime; +#endif c_func setifipdst; -c_func setifflags, setifmetric, setifmtu; +c_func setifflags, setifmetric, setifmtu, setiflladdr; #define NEXTARG 0xffffff +#define NEXTARG2 0xfffffe const struct cmd { const char *c_name; int c_parameter; /* NEXTARG means next argv */ void (*c_func) __P((const char *, int, int, const struct afswtch *afp)); + void (*c_func2) __P((const char *, const char *, int, const struct afswtch *afp)); } cmds[] = { { "up", IFF_UP, setifflags } , { "down", -IFF_UP, setifflags }, @@ -125,20 +182,34 @@ struct cmd { { "-arp", IFF_NOARP, setifflags }, { "debug", IFF_DEBUG, setifflags }, { "-debug", -IFF_DEBUG, setifflags }, + { "add", IFF_UP, notealias }, { "alias", IFF_UP, notealias }, { "-alias", -IFF_UP, notealias }, { "delete", -IFF_UP, notealias }, + { "remove", -IFF_UP, notealias }, #ifdef notdef #define EN_SWABIPS 0x1000 { "swabips", EN_SWABIPS, setifflags }, { "-swabips", -EN_SWABIPS, setifflags }, #endif { "netmask", NEXTARG, setifnetmask }, - { "range", NEXTARG, 0 }, - { "phase", NEXTARG, 0 }, +#ifdef INET6 + { "prefixlen", NEXTARG, setifprefixlen }, + { "anycast", IN6_IFF_ANYCAST, setip6flags }, + { "tentative", IN6_IFF_TENTATIVE, setip6flags }, + { "-tentative", -IN6_IFF_TENTATIVE, setip6flags }, + { "deprecated", IN6_IFF_DEPRECATED, setip6flags }, + { "-deprecated", -IN6_IFF_DEPRECATED, setip6flags }, + { "autoconf", IN6_IFF_AUTOCONF, setip6flags }, + { "-autoconf", -IN6_IFF_AUTOCONF, setip6flags }, + { "pltime", NEXTARG, setip6pltime }, + { "vltime", NEXTARG, setip6vltime }, +#endif { "metric", NEXTARG, setifmetric }, { "broadcast", NEXTARG, setifbroadaddr }, { "ipdst", NEXTARG, setifipdst }, + { "tunnel", NEXTARG2, NULL, settunnel }, + { "deletetunnel", 0, deletetunnel }, { "link0", IFF_LINK0, setifflags }, { "-link0", -IFF_LINK0, setifflags }, { "link1", IFF_LINK1, setifflags }, @@ -149,11 +220,45 @@ struct cmd { { "media", NEXTARG, setmedia }, { "mediaopt", NEXTARG, setmediaopt }, { "-mediaopt", NEXTARG, unsetmediaopt }, +#endif +#ifdef USE_VLANS + { "vlan", NEXTARG, setvlantag }, + { "vlandev", NEXTARG, setvlandev }, + { "-vlandev", NEXTARG, unsetvlandev }, +#endif +#if 0 + /* XXX `create' special-cased below */ + {"create", 0, clone_create }, + {"plumb", 0, clone_create }, +#endif +#ifndef __APPLE__ + {"destroy", 0, clone_destroy }, + {"unplumb", 0, clone_destroy }, +#endif +#ifdef USE_IEEE80211 + { "ssid", NEXTARG, set80211ssid }, + { "nwid", NEXTARG, set80211ssid }, + { "stationname", NEXTARG, set80211stationname }, + { "station", NEXTARG, set80211stationname }, /* BSD/OS */ + { "channel", NEXTARG, set80211channel }, + { "authmode", NEXTARG, set80211authmode }, + { "powersavemode", NEXTARG, set80211powersavemode }, + { "powersave", 1, set80211powersave }, + { "-powersave", 0, set80211powersave }, + { "powersavesleep", NEXTARG, set80211powersavesleep }, + { "wepmode", NEXTARG, set80211wepmode }, + { "wep", 1, set80211wep }, + { "-wep", 0, set80211wep }, + { "weptxkey", NEXTARG, set80211weptxkey }, + { "wepkey", NEXTARG, set80211wepkey }, + { "nwkey", NEXTARG, set80211nwkey }, /* NetBSD */ + { "-nwkey", 0, set80211wep }, /* NetBSD */ #endif { "normal", -IFF_LINK0, setifflags }, { "compress", IFF_LINK0, setifflags }, { "noicmp", IFF_LINK1, setifflags }, { "mtu", NEXTARG, setifmtu }, + { "lladdr", NEXTARG, setiflladdr }, { 0, 0, setifaddr }, { 0, 0, setifdstaddr }, }; @@ -164,9 +269,21 @@ struct cmd { */ typedef void af_status __P((int, struct rt_addrinfo *)); typedef void af_getaddr __P((const char *, int)); +typedef void af_getprefix __P((const char *, int)); + +af_status in_status, at_status, ether_status; +af_getaddr in_getaddr, at_getaddr, ether_getaddr; -af_status in_status, ipx_status, at_status, ether_status; -af_getaddr in_getaddr, ipx_getaddr, at_getaddr; + +#ifdef INET6 +af_status in6_status; +af_getaddr in6_getaddr; +af_getprefix in6_getprefix; +#endif /*INET6*/ +#ifdef NS +af_status xns_status; +af_getaddr xns_getaddr; +#endif /* Known address families */ const @@ -175,18 +292,35 @@ struct afswtch { short af_af; af_status *af_status; af_getaddr *af_getaddr; + af_getprefix *af_getprefix; u_long af_difaddr; u_long af_aifaddr; caddr_t af_ridreq; caddr_t af_addreq; } afs[] = { #define C(x) ((caddr_t) &x) - { "inet", AF_INET, in_status, in_getaddr, + { "inet", AF_INET, in_status, in_getaddr, NULL, SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, - { "ether", AF_INET, ether_status, NULL }, /* XXX not real!! */ +#ifdef INET6 + { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix, + SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, + C(in6_ridreq), C(in6_addreq) }, +#endif /*INET6*/ +#ifdef NS + { "ns", AF_NS, xns_status, xns_getaddr, NULL, + SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) }, +#endif + { "ether", AF_LINK, ether_status, ether_getaddr, NULL, + 0, SIOCSIFLLADDR, NULL, C(ridreq) }, #if 0 /* XXX conflicts with the media command */ -#if USE_IF_MEDIA - { "media", AF_INET, media_status, NULL }, /* XXX not real!! */ +#ifdef USE_IF_MEDIA + { "media", AF_UNSPEC, media_status, NULL, NULL, }, /* XXX not real!! */ +#endif +#ifdef USE_VLANS + { "vlan", AF_UNSPEC, vlan_status, NULL, NULL, }, /* XXX not real!! */ +#endif +#ifdef USE_IEEE80211 + { "ieee80211", AF_UNSPEC, ieee80211_status, NULL, NULL, }, /* XXX not real!! */ #endif #endif { 0, 0, 0, 0 } @@ -222,11 +356,25 @@ rt_xaddrs(cp, cplim, rtinfo) void usage() { - fprintf(stderr, "%s\n%s\n%s\n%s\n", +#ifndef INET6 + fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: ifconfig interface address_family [address [dest_address]]", " [parameters]", - " ifconfig -a [-d] [-u] [address_family]", - " ifconfig -l [-d] [-u] [address_family]"); + " ifconfig -C", + " ifconfig interface create", + " ifconfig -a [-d] [-m] [-u] [address_family]", + " ifconfig -l [-d] [-u] [address_family]", + " ifconfig [-d] [-m] [-u]"); +#else + fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + "usage: ifconfig [-L] interface address_family [address [dest_address]]", + " [parameters]", + " ifconfig -C", + " ifconfig interface create", + " ifconfig -a [-L] [-d] [-m] [-u] [address_family]", + " ifconfig -l [-d] [-u] [address_family]", + " ifconfig [-L] [-d] [-m] [-u]"); +#endif exit(1); } @@ -251,23 +399,32 @@ main(argc, argv) /* Parse leading line options */ all = downonly = uponly = namesonly = 0; - while ((c = getopt(argc, argv, "adlmu")) != -1) { + while ((c = getopt(argc, argv, "adlmu" +#ifdef INET6 + "L" +#endif + )) != -1) { switch (c) { case 'a': /* scan all interfaces */ all++; break; + case 'd': /* restrict scan to "down" interfaces */ + downonly++; + break; case 'l': /* scan interface names only */ namesonly++; break; - case 'd': /* restrict scan to "down" interfaces */ - downonly++; + case 'm': /* show media choices in status */ + supmedia = 1; break; case 'u': /* restrict scan to "up" interfaces */ uponly++; break; - case 'm': /* show media choices in status */ - /* ignored for compatibility */ +#ifdef INET6 + case 'L': + ip6lifetime++; /* print IPv6 address lifetime */ break; +#endif default: usage(); break; @@ -277,13 +434,17 @@ main(argc, argv) argv += optind; /* -l cannot be used with -a or -m */ - if (namesonly && all) + if (namesonly && (all || supmedia)) usage(); /* nonsense.. */ if (uponly && downonly) usage(); + /* no arguments is equivalent to '-a' */ + if (!namesonly && argc < 1) + all = 1; + /* -a and -l allow an address family arg to limit the output */ if (all || namesonly) { if (argc > 1) @@ -306,6 +467,21 @@ main(argc, argv) strncpy(name, *argv, sizeof(name)); argc--, argv++; + + /* + * NOTE: We must special-case the `create' command right + * here as we would otherwise fail when trying to find + * the interface. + */ + if (argc > 0 && (strcmp(argv[0], "create") == 0 || + strcmp(argv[0], "plumb") == 0)) { +#ifndef __APPLE__ + clone_create(); +#endif + argc--, argv++; + if (argc == 0) + exit(0); + } } /* Check for address family */ @@ -433,7 +609,7 @@ ifconfig(argc, argv, afp) if (afp == NULL) afp = &afs[0]; - ifr.ifr_addr.sa_family = afp->af_af; + ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) @@ -447,19 +623,45 @@ ifconfig(argc, argv, afp) break; if (p->c_name == 0 && setaddr) p++; /* got src, do dst */ - if (p->c_func) { + if (p->c_func || p->c_func2) { if (p->c_parameter == NEXTARG) { if (argv[1] == NULL) errx(1, "'%s' requires argument", p->c_name); (*p->c_func)(argv[1], 0, s, afp); argc--, argv++; + } else if (p->c_parameter == NEXTARG2) { + if (argc < 3) + errx(1, "'%s' requires 2 arguments", + p->c_name); + (*p->c_func2)(argv[1], argv[2], s, afp); + argc -= 2, argv += 2; } else (*p->c_func)(*argv, p->c_parameter, s, afp); } argc--, argv++; } +#ifdef INET6 + if (ifr.ifr_addr.sa_family == AF_INET6 && explicit_prefix == 0) { + /* Aggregatable address architecture defines all prefixes + are 64. So, it is convenient to set prefixlen to 64 if + it is not specified. */ + setifprefixlen("64", 0, s, afp); + /* in6_getprefix("64", MASK) if MASK is available here... */ + } +#endif +#ifdef NS + if (setipdst && ifr.ifr_addr.sa_family == AF_NS) { + struct nsip_req rq; + int size = sizeof(rq); + + rq.rq_ns = addreq.ifra_addr; + rq.rq_ip = addreq.ifra_dstaddr; + if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0) + Perror("Encapsulation Routing"); + } +#endif if (clearaddr) { if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { warnx("interface %s cannot change %s addresses!", @@ -478,13 +680,13 @@ ifconfig(argc, argv, afp) } } if (newaddr) { - if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { + if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { warnx("interface %s cannot change %s addresses!", name, afp->af_name); newaddr = NULL; } } - if (newaddr) { + if (newaddr && (setaddr || setmask)) { strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) Perror("ioctl (SIOCAIFADDR)"); @@ -505,18 +707,95 @@ setifaddr(addr, param, s, afp) int s; const struct afswtch *afp; { + if (*afp->af_getaddr == NULL) + return; /* * Delay the ioctl to set the interface addr until flags are all set. * The address interpretation may depend on the flags, * and the flags may change when the address is set. */ - newaddr = 1; setaddr++; - if (doalias == 0) + if (doalias == 0 && afp->af_af != AF_LINK) clearaddr = 1; (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR)); } +void +settunnel(src, dst, s, afp) + const char *src, *dst; + int s; + const struct afswtch *afp; +{ + struct addrinfo hints, *srcres, *dstres; + struct ifaliasreq addreq; + int ecode; +#ifdef INET6 + struct in6_aliasreq in6_addreq; +#endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = afp->af_af; + + if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) + errx(1, "error in parsing address string: %s", + gai_strerror(ecode)); + + if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) + errx(1, + "source and destination address families do not match"); + + switch (srcres->ai_addr->sa_family) { + case AF_INET: + memset(&addreq, 0, sizeof(addreq)); + strncpy(addreq.ifra_name, name, IFNAMSIZ); + memcpy(&addreq.ifra_addr, srcres->ai_addr, + srcres->ai_addr->sa_len); + memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, + dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0) + warn("SIOCSIFPHYADDR"); + break; + +#ifdef INET6 + case AF_INET6: + memset(&in6_addreq, 0, sizeof(in6_addreq)); + strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); + memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, + srcres->ai_addr->sa_len); + memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, + dstres->ai_addr->sa_len); + + if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) + warn("SIOCSIFPHYADDR_IN6"); + break; +#endif /* INET6 */ + + default: + warn("address family not supported"); + } + + freeaddrinfo(srcres); + freeaddrinfo(dstres); +} + +/* ARGSUSED */ +void +deletetunnel(vname, param, s, afp) + const char *vname; + int param; + int s; + const struct afswtch *afp; +{ + + if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) + err(1, "SIOCDIFPHYADDR"); +} + void setifnetmask(addr, dummy, s, afp) const char *addr; @@ -524,9 +803,87 @@ setifnetmask(addr, dummy, s, afp) int s; const struct afswtch *afp; { + if (*afp->af_getaddr == NULL) + return; + setmask++; (*afp->af_getaddr)(addr, MASK); } +#ifdef INET6 +void +setifprefixlen(addr, dummy, s, afp) + const char *addr; + int dummy ; + int s; + const struct afswtch *afp; +{ + if (*afp->af_getprefix) + (*afp->af_getprefix)(addr, MASK); + explicit_prefix = 1; +} + +void +setip6flags(dummyaddr, flag, dummysoc, afp) + const char *dummyaddr ; + int flag; + int dummysoc ; + const struct afswtch *afp; +{ + if (afp->af_af != AF_INET6) + err(1, "address flags can be set only for inet6 addresses"); + + if (flag < 0) + in6_addreq.ifra_flags &= ~(-flag); + else + in6_addreq.ifra_flags |= flag; +} + +void +setip6pltime(seconds, dummy, s, afp) + const char *seconds; + int dummy ; + int s; + const struct afswtch *afp; +{ + setip6lifetime("pltime", seconds, s, afp); +} + +void +setip6vltime(seconds, dummy, s, afp) + const char *seconds; + int dummy ; + int s; + const struct afswtch *afp; +{ + setip6lifetime("vltime", seconds, s, afp); +} + +void +setip6lifetime(cmd, val, s, afp) + const char *cmd; + const char *val; + int s; + const struct afswtch *afp; +{ + time_t newval, t; + char *ep; + + t = time(NULL); + newval = (time_t)strtoul(val, &ep, 0); + if (val == ep) + errx(1, "invalid %s", cmd); + if (afp->af_af != AF_INET6) + errx(1, "%s not allowed for the AF", cmd); + if (strcmp(cmd, "vltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_expire = t + newval; + in6_addreq.ifra_lifetime.ia6t_vltime = newval; + } else if (strcmp(cmd, "pltime") == 0) { + in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; + in6_addreq.ifra_lifetime.ia6t_pltime = newval; + } +} +#endif + void setifbroadaddr(addr, dummy, s, afp) const char *addr; @@ -534,6 +891,7 @@ setifbroadaddr(addr, dummy, s, afp) int s; const struct afswtch *afp; { + if (afp->af_getaddr) (*afp->af_getaddr)(addr, DSTADDR); } @@ -578,9 +936,16 @@ setifdstaddr(addr, param, s, afp) int s; const struct afswtch *afp; { + if (*afp->af_getaddr == NULL) + return; (*afp->af_getaddr)(addr, DSTADDR); } +/* + * Note: doing an SIOCIGIFFLAGS scribbles on the union portion + * of the ifreq structure, which may confuse other parts of ifconfig. + * Make a private copy so we can avoid that. + */ void setifflags(vname, value, s, afp) const char *vname; @@ -588,20 +953,24 @@ setifflags(vname, value, s, afp) int s; const struct afswtch *afp; { - if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + struct ifreq my_ifr; + + bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); + + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { Perror("ioctl (SIOCGIFFLAGS)"); exit(1); } - strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); - flags = ifr.ifr_flags; + strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); + flags = my_ifr.ifr_flags; if (value < 0) { value = -value; flags &= ~value; } else flags |= value; - ifr.ifr_flags = flags; - if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) + my_ifr.ifr_flags = flags; + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) Perror(vname); } @@ -631,9 +1000,32 @@ setifmtu(val, dummy, s, afp) warn("ioctl (set mtu)"); } +void +setiflladdr(val, dummy, s, afp) + const char *val; + int dummy; + int s; + const struct afswtch *afp; +{ + struct ether_addr *ea; + + ea = ether_aton(val); + if (ea == NULL) { + warn("malformed link-level address"); + return; + } + strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; + ifr.ifr_addr.sa_family = AF_LINK; + bcopy(ea, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN); + if (ioctl(s, SIOCSIFLLADDR, (caddr_t)&ifr) < 0) + warn("ioctl (set lladdr)"); + + return; +} #define IFFBITS \ -"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6b6\7RUNNING" \ +"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ "\20MULTICAST" @@ -652,6 +1044,7 @@ status(afp, addrcount, sdl, ifm, ifam) const struct afswtch *p = NULL; struct rt_addrinfo info; int allfamilies, s; + struct ifstat ifs; if (afp == NULL) { allfamilies = 1; @@ -659,7 +1052,7 @@ status(afp, addrcount, sdl, ifm, ifam) } else allfamilies = 0; - ifr.ifr_addr.sa_family = afp->af_af; + ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) @@ -689,6 +1082,8 @@ status(afp, addrcount, sdl, ifm, ifam) printf(" mtu %d", mtu); putchar('\n'); + tunnel_status(s); + while (addrcount > 0) { info.rti_addrs = ifam->ifam_addrs; @@ -698,20 +1093,12 @@ status(afp, addrcount, sdl, ifm, ifam) &info); if (!allfamilies) { - if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family && -#if USE_IF_MEDIA - afp->af_status != media_status && -#endif - afp->af_status != ether_status) { + if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) { p = afp; (*p->af_status)(s, &info); } } else for (p = afs; p->af_name; p++) { - if (p->af_af == info.rti_info[RTAX_IFA]->sa_family && -#if USE_IF_MEDIA - p->af_status != media_status && -#endif - p->af_status != ether_status) + if (p->af_af == info.rti_info[RTAX_IFA]->sa_family) (*p->af_status)(s, &info); } addrcount--; @@ -723,14 +1110,97 @@ status(afp, addrcount, sdl, ifm, ifam) if (allfamilies || afp->af_status == media_status) media_status(s, NULL); #endif - if (!allfamilies && !p && - afp->af_status != ether_status) +#ifdef USE_VLANS + if (allfamilies || afp->af_status == vlan_status) + vlan_status(s, NULL); +#endif +#ifdef USE_IEEE80211 + if (allfamilies || afp->af_status == ieee80211_status) + ieee80211_status(s, NULL); +#endif + strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); + if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) + printf("%s", ifs.ascii); + + if (!allfamilies && !p && afp->af_status != media_status && + afp->af_status != ether_status +#ifdef USE_VLANS + && afp->af_status != vlan_status +#endif + ) warnx("%s has no %s interface address!", name, afp->af_name); close(s); return; } +void +tunnel_status(s) + int s; +{ + char psrcaddr[NI_MAXHOST]; + char pdstaddr[NI_MAXHOST]; + u_long srccmd, dstcmd; + struct ifreq *ifrp; + const char *ver = ""; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif +#ifdef INET6 + struct in6_ifreq in6_ifr; + int s6; +#endif /* INET6 */ + + psrcaddr[0] = pdstaddr[0] = '\0'; + +#ifdef INET6 + memset(&in6_ifr, 0, sizeof(in6_ifr)); + strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); + s6 = socket(AF_INET6, SOCK_DGRAM, 0); + if (s6 < 0) { + srccmd = SIOCGIFPSRCADDR; + dstcmd = SIOCGIFPDSTADDR; + ifrp = 𝔦 + } else { + close(s6); + srccmd = SIOCGIFPSRCADDR_IN6; + dstcmd = SIOCGIFPDSTADDR_IN6; + ifrp = (struct ifreq *)&in6_ifr; + } +#else /* INET6 */ + srccmd = SIOCGIFPSRCADDR; + dstcmd = SIOCGIFPDSTADDR; + ifrp = 𝔦 +#endif /* INET6 */ + + if (ioctl(s, srccmd, (caddr_t)ifrp) < 0) + return; +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); +#endif + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + psrcaddr, sizeof(psrcaddr), 0, 0, niflag); +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + ver = "6"; +#endif + + if (ioctl(s, dstcmd, (caddr_t)ifrp) < 0) + return; +#ifdef INET6 + if (ifrp->ifr_addr.sa_family == AF_INET6) + in6_fillscopeid((struct sockaddr_in6 *)&ifrp->ifr_addr); +#endif + getnameinfo(&ifrp->ifr_addr, ifrp->ifr_addr.sa_len, + pdstaddr, sizeof(pdstaddr), 0, 0, niflag); + + printf("\ttunnel inet%s %s --> %s\n", ver, + psrcaddr, pdstaddr); +} + void in_status(s, info) int s ; @@ -765,6 +1235,181 @@ in_status(s, info) putchar('\n'); } +#ifdef INET6 +void +in6_fillscopeid(sin6) + struct sockaddr_in6 *sin6; +{ +#if defined(__KAME__) && defined(KAME_SCOPEID) + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +} + +void +in6_status(s, info) + int s ; + struct rt_addrinfo * info; +{ + struct sockaddr_in6 *sin, null_sin; + struct in6_ifreq ifr6; + int s6; + u_int32_t flags6; + struct in6_addrlifetime lifetime; + time_t t = time(NULL); + int error; + u_int32_t scopeid; + + memset(&null_sin, 0, sizeof(null_sin)); + + sin = (struct sockaddr_in6 *)info->rti_info[RTAX_IFA]; + strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); + if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ifconfig: socket"); + return; + } + ifr6.ifr_addr = *sin; + if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + perror("ifconfig: ioctl(SIOCGIFAFLAG_IN6)"); + close(s6); + return; + } + flags6 = ifr6.ifr_ifru.ifru_flags6; + memset(&lifetime, 0, sizeof(lifetime)); + ifr6.ifr_addr = *sin; + if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) { + perror("ifconfig: ioctl(SIOCGIFALIFETIME_IN6)"); + close(s6); + return; + } + lifetime = ifr6.ifr_ifru.ifru_lifetime; + close(s6); + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && + *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { + u_short index; + + index = *(u_short *)&sin->sin6_addr.s6_addr[2]; + *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = ntohs(index); + } + scopeid = sin->sin6_scope_id; + + error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, + sizeof(addr_buf), NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID); + if (error != 0) + inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, + sizeof(addr_buf)); + printf("\tinet6 %s ", addr_buf); + + if (flags & IFF_POINTOPOINT) { + /* note RTAX_BRD overlap with IFF_BROADCAST */ + sin = (struct sockaddr_in6 *)info->rti_info[RTAX_BRD]; + /* + * some of the interfaces do not have valid destination + * address. + */ + if (sin && sin->sin6_family == AF_INET6) { + int error; + + /* XXX: embedded link local addr check */ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && + *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { + u_short index; + + index = *(u_short *)&sin->sin6_addr.s6_addr[2]; + *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = ntohs(index); + } + + error = getnameinfo((struct sockaddr *)sin, + sin->sin6_len, addr_buf, + sizeof(addr_buf), NULL, 0, + NI_NUMERICHOST|NI_WITHSCOPEID); + if (error != 0) + inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, + sizeof(addr_buf)); + printf("--> %s ", addr_buf); + } + } + + sin = (struct sockaddr_in6 *)info->rti_info[RTAX_NETMASK]; + if (!sin) + sin = &null_sin; + printf("prefixlen %d ", prefix(&sin->sin6_addr, + sizeof(struct in6_addr))); + + if ((flags6 & IN6_IFF_ANYCAST) != 0) + printf("anycast "); + if ((flags6 & IN6_IFF_TENTATIVE) != 0) + printf("tentative "); + if ((flags6 & IN6_IFF_DUPLICATED) != 0) + printf("duplicated "); + if ((flags6 & IN6_IFF_DETACHED) != 0) + printf("detached "); + if ((flags6 & IN6_IFF_DEPRECATED) != 0) + printf("deprecated "); + if ((flags6 & IN6_IFF_AUTOCONF) != 0) + printf("autoconf "); + if ((flags6 & IN6_IFF_TEMPORARY) != 0) + printf("temporary "); + + if (scopeid) + printf("scopeid 0x%x ", scopeid); + + if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { + printf("pltime "); + if (lifetime.ia6t_preferred) { + printf("%s ", lifetime.ia6t_preferred < t + ? "0" : sec2str(lifetime.ia6t_preferred - t)); + } else + printf("infty "); + + printf("vltime "); + if (lifetime.ia6t_expire) { + printf("%s ", lifetime.ia6t_expire < t + ? "0" : sec2str(lifetime.ia6t_expire - t)); + } else + printf("infty "); + } + + putchar('\n'); +} +#endif /*INET6*/ + +#ifdef NS +void +xns_status(s, info) + int s ; + struct rt_addrinfo * info; +{ + struct sockaddr_ns *sns, null_sns; + + memset(&null_sns, 0, sizeof(null_sns)); + + sns = (struct sockaddr_ns *)info->rti_info[RTAX_IFA]; + printf("\tns %s ", ns_ntoa(sns->sns_addr)); + + if (flags & IFF_POINTOPOINT) { + sns = (struct sockaddr_ns *)info->rti_info[RTAX_BRD]; + if (!sns) + sns = &null_sns; + printf("--> %s ", ns_ntoa(sns->sns_addr)); + } + + putchar('\n'); + close(s); +} +#endif + + void ether_status(s, info) int s ; @@ -823,6 +1468,26 @@ in_getaddr(s, which) if (which != MASK) sin->sin_family = AF_INET; + if (which == ADDR) { + char *p = NULL; + + if((p = strrchr(s, '/')) != NULL) { + /* address is `name/masklen' */ + int masklen; + int ret; + struct sockaddr_in *min = sintab[MASK]; + *p = '\0'; + ret = sscanf(p+1, "%u", &masklen); + if(ret != 1 || (masklen < 0 || masklen > 32)) { + *p = '/'; + errx(1, "%s: bad value", s); + } + min->sin_len = sizeof(*min); + min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) & + 0xffffffff); + } + } + if (inet_aton(s, &sin->sin_addr)) return; if ((hp = gethostbyname(s)) != 0) @@ -834,6 +1499,73 @@ in_getaddr(s, which) errx(1, "%s: bad value", s); } +#ifdef INET6 +#define SIN6(x) ((struct sockaddr_in6 *) &(x)) +struct sockaddr_in6 *sin6tab[] = { +SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), +SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)}; + +void +in6_getaddr(s, which) + const char *s; + int which; +{ + register struct sockaddr_in6 *sin = sin6tab[which]; + struct addrinfo hints, *res; + int error = -1; + + newaddr &= 1; + + sin->sin6_len = sizeof(*sin); + if (which != MASK) + sin->sin6_family = AF_INET6; + + if (which == ADDR) { + char *p = NULL; + if((p = strrchr(s, '/')) != NULL) { + *p = '\0'; + in6_getprefix(p + 1, MASK); + explicit_prefix = 1; + } + } + + if (sin->sin6_family == AF_INET6) { + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = AF_INET6; + error = getaddrinfo(s, NULL, &hints, &res); + } + if (error != 0) { + if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) + errx(1, "%s: bad value", s); + } else + bcopy(res->ai_addr, sin, res->ai_addrlen); +} + +void +in6_getprefix(plen, which) + const char *plen; + int which; +{ + register struct sockaddr_in6 *sin = sin6tab[which]; + register u_char *cp; + int len = atoi(plen); + + if ((len < 0) || (len > 128)) + errx(1, "%s: bad value", plen); + sin->sin6_len = sizeof(*sin); + if (which != MASK) + sin->sin6_family = AF_INET6; + if ((len == 0) || (len == 128)) { + memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr)); + return; + } + memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr)); + for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8) + *cp++ = 0xff; + *cp = 0xff << (8 - len); +} +#endif + /* * Print a value a la the %b format of the kernel's printf */ @@ -868,4 +1600,83 @@ printb(s, v, bits) } } +void +ether_getaddr(addr, which) + const char *addr; + int which; +{ + struct ether_addr *ea; + struct sockaddr *sea = &ridreq.ifr_addr; + + ea = ether_aton(addr); + if (ea == NULL) + errx(1, "malformed ether address"); + if (which == MASK) + errx(1, "Ethernet does not use netmasks"); + sea->sa_family = AF_LINK; + sea->sa_len = ETHER_ADDR_LEN; + bcopy(ea, sea->sa_data, ETHER_ADDR_LEN); +} + +#ifdef INET6 +int +prefix(val, size) + void *val; + int size; +{ + register u_char *name = (u_char *)val; + register int byte, bit, plen = 0; + + for (byte = 0; byte < size; byte++, plen += 8) + if (name[byte] != 0xff) + break; + if (byte == size) + return (plen); + for (bit = 7; bit != 0; bit--, plen++) + if (!(name[byte] & (1 << bit))) + break; + for (; bit != 0; bit--) + if (name[byte] & (1 << bit)) + return(0); + byte++; + for (; byte < size; byte++) + if (name[byte]) + return(0); + return (plen); +} + +static char * +sec2str(total) + time_t total; +{ + static char result[256]; + int days, hours, mins, secs; + int first = 1; + char *p = result; + + if (0) { + days = total / 3600 / 24; + hours = (total / 3600) % 24; + mins = (total / 60) % 60; + secs = total % 60; + + if (days) { + first = 0; + p += sprintf(p, "%dd", days); + } + if (!first || hours) { + first = 0; + p += sprintf(p, "%dh", hours); + } + if (!first || mins) { + first = 0; + p += sprintf(p, "%dm", mins); + } + sprintf(p, "%ds", secs); + } else + sprintf(result, "%lu", (unsigned long)total); + + return(result); +} +#endif /*INET6*/ diff --git a/ip6conf.tproj/6to4.conf b/ip6conf.tproj/6to4.conf new file mode 100644 index 0000000..b3a3c80 --- /dev/null +++ b/ip6conf.tproj/6to4.conf @@ -0,0 +1,20 @@ +# 6to4.conf +# Configuration file for 6to4 tunnel +# + +$in_if=""; # Inside (usually ethernet) interface - for local network + +$v6_net="1"; # 2002:x:x:v6_net:: +$v6_innernet="2"; # 2002:x:x:v6_innernet:: +$v6_prefixlen=16; # Change for more +$hostbits6=":1"; # should be determined via MAC of $in_if + +# Possible remote 6to4 routers: +# Anycast is default per RFC 3068, but can select another if desired + +$peer="6to4-anycast"; # RFC 3068 magic value +#$peer="6to4.ipv6.fh-regensburg.de"; # Germany, Europe +#$peer="asterix.ipv6.bt.com"; # Great Britain, Europe +#$peer="6to4.kfu.com"; # USA, West coast +#$peer="6to4.ipv6.microsoft.com"; # USA, West coast +#$peer="ipv6-router.cisco.com"; # USA, West coast; register at http://www.cisco.com/ipv6/ diff --git a/rbootd.tproj/Makefile b/ip6conf.tproj/Makefile similarity index 68% rename from rbootd.tproj/Makefile rename to ip6conf.tproj/Makefile index 6a4e127..cc966d0 100644 --- a/rbootd.tproj/Makefile +++ b/ip6conf.tproj/Makefile @@ -1,5 +1,5 @@ # -# Generated by the NeXT Project Builder. +# Generated by the Apple Project Builder. # # NOTE: Do NOT change this file -- Project Builder maintains it. # @@ -7,29 +7,29 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = rbootd +NAME = ip6 PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -HFILES = defs.h pathnames.h rmp.h rmp_var.h - -CFILES = bpf.c conf.c parseconf.c rbootd.c rmpproto.c utils.c - -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble rbootd.8 +CFILES = ip6tool.c +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble 6to4.conf \ + ip6config ip6config.8 ip6.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC MAKEFILE = tool.make -NEXTSTEP_INSTALLDIR = /usr/libexec -WINDOWS_INSTALLDIR = /usr/libexec -PDO_UNIX_INSTALLDIR = /usr/libexec +NEXTSTEP_INSTALLDIR = /usr/sbin +WINDOWS_INSTALLDIR = /usr/sbin +PDO_UNIX_INSTALLDIR = /usr/sbin LIBS = DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) +HEADER_PATHS =\ + -I$(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc diff --git a/ip6conf.tproj/Makefile.postamble b/ip6conf.tproj/Makefile.postamble new file mode 100644 index 0000000..9cad035 --- /dev/null +++ b/ip6conf.tproj/Makefile.postamble @@ -0,0 +1,13 @@ +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 ip6.8 "$(DSTROOT)/usr/share/man/man8/ip6.8" + install -c -m 644 ip6config.8 "$(DSTROOT)/usr/share/man/man8/ip6config.8" + +install-config-file: + install -d "$(DSTROOT)/private/etc" + install -c -m 644 6to4.conf "$(DSTROOT)/private/etc/6to4.conf" + +install-script: + install -d "$(DSTROOT)/usr/sbin" + install -c -m 755 ip6config "$(DSTROOT)/usr/sbin/ip6config" + diff --git a/ip6conf.tproj/Makefile.preamble b/ip6conf.tproj/Makefile.preamble new file mode 100644 index 0000000..6e6f709 --- /dev/null +++ b/ip6conf.tproj/Makefile.preamble @@ -0,0 +1,3 @@ +OTHER_GENERATED_OFILES = $(VERS_OFILE) +-include ../Makefile.include +AFTER_INSTALL += install-man-page install-config-file install-script diff --git a/trsp.tproj/PB.project b/ip6conf.tproj/PB.project similarity index 53% rename from trsp.tproj/PB.project rename to ip6conf.tproj/PB.project index 26e29e4..0b4964c 100644 --- a/trsp.tproj/PB.project +++ b/ip6conf.tproj/PB.project @@ -1,41 +1,44 @@ { - DOCICONFILES = (); + APPCLASS = NSApplication; FILESTABLE = { - C_FILES = (); + FRAMEWORKS = (); + HEADERSEARCH = ( + "$(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders" + ); H_FILES = (); + M_FILES = (); OTHER_LIBS = (); - OTHER_LINKED = (trsp.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, trsp.8); + OTHER_LINKED = (ip6tool.c); + OTHER_SOURCES = ( + Makefile.preamble, + Makefile, + Makefile.postamble, + 6to4.conf, + ip6config, + ip6config.8, + ip6.8 + ); PRECOMPILED_HEADERS = (); PROJECT_HEADERS = (); PUBLIC_HEADERS = (); SUBPROJECTS = (); }; - GENERATEMAIN = YES; LANGUAGE = English; LOCALIZABLE_FILES = {}; - NEXTSTEP_BUILDDIR = ""; - NEXTSTEP_BUILDTOOL = /bin/make; - NEXTSTEP_COMPILEROPTIONS = ""; + NEXTSTEP_BUILDTOOL = /usr/bin/gnumake; NEXTSTEP_INSTALLDIR = /usr/sbin; NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_LINKEROPTIONS = ""; + NEXTSTEP_MAINNIB = ping6; NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; PDO_UNIX_INSTALLDIR = /usr/sbin; PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; + PDO_UNIX_MAINNIB = ip6; PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = trsp; + PROJECTNAME = ip6conf; PROJECTTYPE = Tool; PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; WINDOWS_INSTALLDIR = /usr/sbin; WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; + WINDOWS_MAINNIB = ip6; WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; } diff --git a/ip6conf.tproj/ip6.8 b/ip6conf.tproj/ip6.8 new file mode 100644 index 0000000..feb6cc3 --- /dev/null +++ b/ip6conf.tproj/ip6.8 @@ -0,0 +1,45 @@ +.Dd May 23, 2002 +.Dt ip6 8 +.Os +.Sh NAME +.Nm ip6 +.Nd Enable or disable IPv6 on active interfaces +.Sh SYNOPSIS +.Nm +.Op Fl ax +.Op Fl ud interface +.Sh DESCRIPTION +.Nm +can be used to start up or shut down IPv6 on active interfaces. +When IPv6 is enabled on an interface the protocol is attached to the +interface, at which point the default settings in the kernel allow it +to acquire a link-local address and accept router advertisements. +Disabling detaches the protocol from the interface. +.Pp +Possible options are: +.Bl -tag -width xxx +.It Fl a +Start IPv6 on all interfaces. +.It Fl x +Stop IPv6 on all interfaces. +.It Fl u [interface] +Start IPv6 on interface. +.It Fl d [interface] +Stop IPv6 on interface. +.El +.Pp +.Sh REQUIREMENTS +You need support for IPv6 in your kernel. This is provided beginning +with Darwin Kernel Version 6.0. +.Pp +.Sh CONFIGURATION +The default IPv6 configuration for an interface assigns a link-local +address to it and sets the interface to receive router advertisements. +No further configuration is necessary for basic functionality. +However, various settings can be modified by using sysctl. +Pp +.Sh SEE ALSO +.Xr stf 4 , +IPv6 Documentation at +.Pa http://www.netbsd.org/Documentation/network/ipv6/ , +RFC 3068. diff --git a/ip6conf.tproj/ip6config b/ip6conf.tproj/ip6config new file mode 100644 index 0000000..5a8aaf2 --- /dev/null +++ b/ip6conf.tproj/ip6config @@ -0,0 +1,207 @@ +#!/usr/bin/perl +# +# Copyright (c) 2002 Apple Computer, Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# "Portions Copyright (c) 2002 Apple Computer, Inc. All Rights +# Reserved. This file contains Original Code and/or Modifications of +# Original Code as defined in and that are subject to the Apple Public +# Source License Version 1.0 (the 'License'). You may not use this file +# except in compliance with the License. Please obtain a copy of the +# License at http://www.apple.com/publicsource and read it before using +# this file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the +# License for the specific language governing rights and limitations +# under the License." +# +# @APPLE_LICENSE_HEADER_END@ +# +# Setup IPv6 for Darwin +# - Startup/shutdown IPv6 on the given interface +# - Startup/shutdown 6to4 on the given interface +# - Start/stop router advertisement. +# +# Setup 6to4 IPv6, for NetBSD (and maybe others) +# +# (c) Copyright 2000 Hubert Feyrer +# + + +# Directory for conf file +$etcdir="/private/etc"; +require "$etcdir/6to4.conf"; + +use Getopt::Std; + +########################################################################### +sub do_6to4_setup +{ + # + # Some sanity checks - check for link-local address and stf + # + if (`ifconfig -a | grep fe80: | wc -l` <= 0 or + `ifconfig -a | grep stf | wc -l` <= 0) { + die "$0: It seems your kernel does not support IPv6 or 6to4 (stf).\n"; + } + + # + # Take the requested interface from the user + # Figure out addressing, etc. + # + $localadr4 = `ifconfig $ARGV[1] inet | grep inet`; + $localadr4 =~ s/^.*inet\s*//; + $localadr4 =~ s/\s.*$//; + chomp($localadr4); + + @l4c = split('\.', $localadr4); + $prefix = sprintf("2002:%02x%02x:%02x%02x", @l4c[0..3]); + + $localadr6 = sprintf("$prefix:%04x", $v6_net); + + # + # Anycast is default in 6to4.conf file + # + if ($peer eq "6to4-anycast") { + # magic values from rfc 3068 + $remoteadr4 = "192.88.99.1"; + $remoteadr6 = "2002:c058:6301::"; + } + else { + chomp($remoteadr4 = `host $peer`); + $remoteadr4 =~ s/^.*address //; + + chomp($remoteadr6 = `host -t AAAA $peer`); + $remoteadr6 =~ s/^.*address //; + } + +} + +########################################################################### +sub do_usage +{ + print "Usage: $0 \n"; + print " start-v6 all | stop-v6 all\n"; + print " start-v6 [interface] | stop-v6 [interface]\n"; + print " start-stf [interface] | stop-stf\n"; + print " start-rtadvd | stop-rtadvd\n"; +} +########################################################################### + +# +# Process options - just help for now +# +getopts('h'); + +if ($opt_h) { + do_usage; + exit 0; +} + +# +# Handle commands +# + +# Start IPv6 +if ($ARGV[0] eq "start-v6" or $ARGV[0] eq "v6-start") { + if ($ARGV[1] eq "all") { + print "Starting IPv6 on all interfaces.\n"; + system "ip6 -a"; + } + else { + print "Starting IPv6 on $ARGV[1].\n"; + system "ip6 -u $ARGV[1]"; + } +} + +# Stop IPv6 +elsif ($ARGV[0] eq "stop-v6" or $ARGV[0] eq "v6-stop") { + if ($ARGV[1] eq "all") { + print "Stopping IPv6 on all interfaces.\n"; + system "ip6 -x"; + } + else { + print "Stopping IPv6 on $ARGV[1].\n"; + system "ip6 -d $ARGV[1]"; + } +} + +# Start 6to4 +elsif ($ARGV[0] eq "start-stf" or $ARGV[0] eq "stf-start") { + do_6to4_setup; + print "Starting 6to4 on $ARGV[1].\n"; + system "ifconfig stf0 inet6 $localadr6:$hostbits6 prefixlen $v6_prefixlen alias"; + system "route add -inet6 default $remoteadr6"; + if ($in_if ne "") { + system "ifconfig $in_if inet6 $prefix:$v6_innernet:$hostbits6"; + } +} + +# Stop 6to4 +elsif ($ARGV[0] eq "stop-stf" or $ARGV[0] eq "stf-stop") { + print "Stopping 6to4.\n"; + system "ifconfig stf0 down"; + $cmd="ifconfig stf0 inet6 " . + "| grep inet6 " . + "| sed -e 's/inet6//' " . + "-e 's/prefix.*//g' " . + "-e 's/^[ ]*//' " . + "-e 's/[ ]*\$//'"; + foreach $ip ( split('\s+', `$cmd`)) { + system "ifconfig stf0 inet6 -alias $ip"; + } + system "route delete -inet6 default"; +} + +# Start router advertisement +elsif ($ARGV[0] eq "rtadvd-start" or $ARGV[0] eq "start-rtadvd") { + print "WARNING: Setting up router advertisement should be done with great care\n"; + print "because of a number of security issues. You should make sure this is\n"; + print "allowed on your network and possibly fine-tune rtadvd.conf.\n"; + print "\n"; + print "Are you sure you want to start router advertisement (yes/no) ?: "; + while () { + chomp; + if ($_ eq "yes" or $_ eq "y") { + if ( -f "/var/run/rtadvd.pid" ) { + print "rtadvd already running!\n"; + } else { + print "Starting router advertisement.\n"; + system "sysctl -w net.inet6.ip6.forwarding=1"; + system "sysctl -w net.inet6.ip6.accept_rtadv=0"; + shift @ARGV; + system "rtadvd @ARGV"; + } + last; + } + elsif ($_ eq "no" or $_ eq "n") { + print "Router advertisement startup aborted.\n"; + last; + } + else { + print "Invalid entry! Try again.\n"; + print "Are you sure you want to start router advertisement? (yes/no): "; + } + } +} + +# Stop router advertisement +elsif ($ARGV[0] eq "rtadvd-stop" or $ARGV[0] eq "stop-rtadvd") { + if ( -f "/var/run/rtadvd.pid" ) { + print "Stopping router advertisement.\n"; + $pid = `cat /var/run/rtadvd.pid`; + system "kill -TERM $pid"; + system "rm -f /var/run/rtadvd.pid"; + system "rm -f /var/run/6to4-rtadvd.conf.$pid"; + } else { + print "no rtadvd running!\n"; + } +} +else { + do_usage; +} diff --git a/ip6conf.tproj/ip6config.8 b/ip6conf.tproj/ip6config.8 new file mode 100644 index 0000000..0a1ebdb --- /dev/null +++ b/ip6conf.tproj/ip6config.8 @@ -0,0 +1,160 @@ +.\" $NetBSD: 6to4.8,v 1.5 2001/12/03 19:03:21 wiz Exp $ +.Dd May 21, 2002 +.Dt ip6config 8 +.Os +.Sh NAME +.Nm ip6config +.Nd Configure IPv6 and 6to4 IPv6 tunnelling +.Sh SYNOPSIS +.Nm +.Op Fl h +.Ar command interface +.Sh DESCRIPTION +The +.Nm +script can be used to start up or shut down IPv6 on active interfaces. It +can also be used to configure a 6to4 tunnel and start or stop router +advertisement. +.Pp +When IPv6 is enabled on an interface the protocol is attached to the +interface, at which point the default settings in the kernel allow it +to acquire a link-local address and listen for router advertisements. +.Pp +6to4 is a mechanism by which your IPv6 address(es) are derived from an +assigned IPv4 address, and which involves automatic tunnelling to one or +more remove 6to4 hubs, which will then forward your v6 packets on the +6bone etc. Replies are routed back to you over IPv4 via (possibly) other +6to4 capable remote gateways. As such, IPv6-in-IPv4-encapsulated +packets are accepted from all v4-hosts. +.Pp +From your (single) IPv4 address, you get a whole IPv6 /48 network, +which allows you to split your network in 2^16 subnets, with 2^64 +hosts each. You need to setup routing for your internal network +properly, help is provided for setting up the border router here. +.Pp +This script takes the burden to calculate your IPv6 address from +existing IPv4 address and runs the commands to setup (and tear down) +automatic 6to4 IPv6 tunnelling. +.Pp +Finally, router advertisement for an internal network can be started +and stopped. This uses sysctl to set net.inet6.ip6.forwarding and +net.inet6.ip6.accept_rtadv to the proper values for routing. +.Pp +Possible options are: +.Bl -tag -width xxx +.It Fl h +Show usage. +.El +.Pp +Possible commands are: +.Bl -tag -width start-rtadvd +.It Sy start-v6 +Start IPv6 on given interface using default kernel settings. Attaches +protocol to the interface. If interface is "all", all valid interfaces +will be configured. +.It Sy stop-v6 +Stop IPv6 on given interface. Detaches protocol from the interface. If +interface is "all", all valid interfaces will be configured. +.It Sy start-stf +Configure 6to4 IPv6. The +.Xr stf 4 +interface is configured, and a default route to a remote 6to4 +gateway is established. In addition, the internal +network interface is assigned an address. +.It Sy stop-stf +Stops 6to4 IPv6. All addresses are removed from the +.Xr stf 4 +device, and the default route is removed. +.It Sy start-rtadvd +Starts router advertizement and IPv6 packet forwarding, +turning the machine into a IPv6 router. +.Xr rtadvd 8 +is invoked with a custom config file created under +.Pa /var/run . +Clients just need to be told to accept router advertizements, i.e. +the +.Sq net.inet6.ip6.accept_rtadv +sysctl needs to be set to +.Sq 1 . +You can arrange that by setting +.Dq ip6mode=autohost +in +.Pa /etc/rc.conf . +.It Sy stop-rtadvd +Stops router advertizement and IPv6 packet forwarding. +.Xr rtadvd 8 +is stopped, and the +.Xr rtadvd.conf 5 +config file is removed from +.Pa /var/run . +.El +.Sh REQUIREMENTS +Besides IPv4 connectivity, you need support for IPv6 and the +.Xr stf 4 +device in your kernel. This is provided beginning with Darwin +Kernel Version 6.0. +.Pp +No special values are needed in +.Pa /etc/rc.conf +to run this script, but see comment on setting up IPv6-clients +.Sq behind +your 6to4 router for the +.Sy rtadvd-start +command! +.Sh CONFIGURATION +The default IPv6 configuration for an interface assigns a link-local +address to it and sets the interface to receive router advertisements. +No further configuration is necessary for basic functionality. +However, various settings can be modified by using sysctl. +.Pp +The +.Nm +script reads its 6to4 configuration from a config file named +.Pa 6to4.conf . +The +.Pa 6to4.conf +file is in +.Xr perl 1 +syntax, and contains several +variables that can be tuned to adjust your setup. +.Bl -tag -width start-rtadvd +.It Sy in_if +The inside interface. If non-empty, this interface is +assigned the IPv6 address +2002:x:x:v6_innernet:hostbits6, see below. +This is only useful on machines that +have more than one network interface, e.g. with a modem and a +local ethernet. +.It Sy v6_net +The subnet address you want to use on the address of +your outbound interface. Defaults to +.Dq 1 . +.It Sy v6_innernet +The subnet address you want to use on the address of +your inbound interface. Defaults to +.Dq 2 . +.It Sy hostbits6 +The lower 64 bits of both the inbound and outbound interface's +addresses. +.It Sy peer +Name of the remote 6to4 server that'll take our +IPv6-in-IPv4 encapsulated packets and route them on +via IPv6. A special value of +.Dq 6to4-anycast +can be used for the anycast service defined in RFC 3068. +Other possible values are given in the example config file. +.El +.Sh SEE ALSO +.Xr stf 4 , +.Dq 6to4 IPv6 Explained +at +.Pa http://www.feyrer.de/NetBSD/6to4.html , +.Nx +IPv6 Documentation at +.Pa http://www.netbsd.org/Documentation/network/ipv6/ , +RFC 3068. +.Sh HISTORY +The +.Nm +6to4 utility and manpage portions were written by +Hubert Feyrer for NetBSD. diff --git a/ip6conf.tproj/ip6tool.c b/ip6conf.tproj/ip6tool.c new file mode 100644 index 0000000..a17b63b --- /dev/null +++ b/ip6conf.tproj/ip6tool.c @@ -0,0 +1,228 @@ +/* Copyright (c) 2002 Apple Computer, Inc. All rights reserved. +* +* @APPLE_LICENSE_HEADER_START@ +* +* "Portions Copyright (c) 2002 Apple Computer, Inc. All Rights +* Reserved. This file contains Original Code and/or Modifications of +* Original Code as defined in and that are subject to the Apple Public +* Source License Version 1.0 (the 'License'). You may not use this file +* except in compliance with the License. Please obtain a copy of the +* License at http://www.apple.com/publicsource and read it before using +* this file. +* +* The Original Code and all software distributed under the License are +* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the +* License for the specific language governing rights and limitations +* under the License." +* +* @APPLE_LICENSE_HEADER_END@ +* +*/ + +#include +#include +#include +#include +/* this is needed to get SIOCPROTOATTACH/SIOCPROTODETACH */ +#define KERNEL_PRIVATE +#include +#undef KERNEL_PRIVATE +#include +#include +#include + + +/* options */ +#define IPv6_STARTUP 1 +#define IPv6_SHUTDOWN 2 +#define IPv6_STARTUP_ALL 3 +#define IPv6_SHUTDOWN_ALL 4 + +const char *if_exceptions[] = {"lo0", "gif0", "faith0", "stf0"}; + +extern char *optarg; + +void do_usage(void); +int do_protoattach(int s, char *name); +int do_protodetach(int s, char *name); +int do_protoattach_all(int s); +int do_protodetach_all(int s); + + +int +main(int argc, char **argv) +{ + int s, + ch, + option = 0, + err; + char *interface = NULL; + + if ((ch = getopt(argc, argv, "u:d:ax")) != -1) { + switch (ch) { + case 'u': + /* option -u: start up proto */ + option = IPv6_STARTUP; + interface = optarg; + break; + case 'd': + /* option -d: shut down proto */ + option = IPv6_SHUTDOWN; + interface = optarg; + break; + case 'a': + /* option -a: start up proto on all interfaces */ + option = IPv6_STARTUP_ALL; + break; + case 'x': + /* option -x: shut down proto on all interfaces */ + option = IPv6_SHUTDOWN_ALL; + break; + default: + break; + } + } + + if (!option) { + do_usage(); + return 0; + } + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + err = s; + printf("%s: Error %d creating socket.\n", argv[0], err); + return 0; + } + + switch (option) { + case IPv6_STARTUP: + err = do_protoattach(s, interface); + if (err < 0) + printf("%s: Error %d encountered attaching to interface %s.\n", argv[0], err, interface); + + break; + case IPv6_SHUTDOWN: + err = do_protodetach(s, interface); + if (err < 0) + printf("%s: Error %d encountered detaching to interface %s.\n", argv[0], err, interface); + + break; + case IPv6_STARTUP_ALL: + err = do_protoattach_all(s); + if (err < 0) + printf("%s: Error %d encountered attaching to interfaces.\n", argv[0], err); + + break; + case IPv6_SHUTDOWN_ALL: + err = do_protodetach_all(s); + if (err < 0) + printf("%s: Error %d encountered detaching to interfaces.\n", argv[0], err); + + break; + default: + break; + } + + close(s); + + return 0; +} + +void +do_usage(void) +{ + printf("Usage: \n\ + Start up IPv6 on ALL interfaces: -a\n\ + Shut down IPv6 on ALL interfaces: -x\n\ + Start up IPv6 on given interface: -u [interface]\n\ + Shut down IPv6 on given interface: -d [interface].\n"); +} + +int +do_protoattach(int s, char *name) +{ + struct ifreq ifr; + + bzero(&ifr, sizeof(ifr)); + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + return (ioctl(s, SIOCPROTOATTACH, &ifr)); +} + +int +do_protodetach(int s, char *name) +{ + struct ifreq ifr; + + bzero(&ifr, sizeof(ifr)); + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + return (ioctl(s, SIOCPROTODETACH, &ifr)); +} + +int +do_protoattach_all(int s) +{ + struct ifaddrs *ifaddrs, *ifa; + int err; + + if ((err = getifaddrs(&ifaddrs)) < 0) + return err; /* getifaddrs properly sets errno */ + + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + /* skip over invalid interfaces */ + if ((strcmp(ifa->ifa_name, if_exceptions[0]))) + if (strcmp(ifa->ifa_name, if_exceptions[1])) + if (strcmp(ifa->ifa_name, if_exceptions[2])) + if (strcmp(ifa->ifa_name, if_exceptions[3])) { + /* this is a valid interface */ + err = do_protoattach(s, ifa->ifa_name); + if (err) + break; + + while (ifa->ifa_next != NULL && + !(strcmp(ifa->ifa_name, ifa->ifa_next->ifa_name))) { + /* skip multiple entries for same interface */ + ifa = ifa->ifa_next; + } + } + } + + freeifaddrs(ifaddrs); + + return err; +} + +int +do_protodetach_all(int s) +{ + struct ifaddrs *ifaddrs, *ifa; + int err; + + if ((err = getifaddrs(&ifaddrs)) < 0) + return err; /* getifaddrs properly sets errno */ + + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + /* skip over invalid interfaces */ + if ((strcmp(ifa->ifa_name, if_exceptions[0]))) + if (strcmp(ifa->ifa_name, if_exceptions[1])) + if (strcmp(ifa->ifa_name, if_exceptions[2])) + if (strcmp(ifa->ifa_name, if_exceptions[3])) { + /* this is a valid interface */ + err = do_protodetach(s, ifa->ifa_name); + if (err) + break; + + while (ifa->ifa_next != NULL && + !(strcmp(ifa->ifa_name, ifa->ifa_next->ifa_name))) { + /* skip multiple entries for same interface */ + ifa = ifa->ifa_next; + } + } + } + + freeifaddrs(ifaddrs); + + return err; +} \ No newline at end of file diff --git a/ipfw.tproj/ipfw.8 b/ipfw.tproj/ipfw.8 index 26a7980..fea3024 100644 --- a/ipfw.tproj/ipfw.8 +++ b/ipfw.tproj/ipfw.8 @@ -1,85 +1,231 @@ -.\" -.\" $Id: ipfw.8,v 1.1.1.1 2000/01/11 01:48:49 wsanchez Exp $ -.\" -.Dd July 20, 1996 -.Dt IPFW 8 SMM -.Os FreeBSD +.Dd February 16, 2000 +.Dt IPFW 8 +.Os Darwin .Sh NAME .Nm ipfw -.Nd controlling utility for IP firewall +.Nd IP firewall and traffic shaper control program .Sh SYNOPSIS -.Nm ipfw +.Nm .Op Fl q .Oo .Fl p Ar preproc -.Op Fl D Ar macro Ns Op Ns =value -.Op Fl U Ar macro +.Oo Fl D +.Ar macro Ns Op = Ns Ar value .Oc -file -.Nm ipfw -.Oo -.Fl f -| -.Fl q -.Oc -flush -.Nm ipfw -.Oo -.Fl q +.Op Fl U Ar macro .Oc -zero +.Ar pathname +.Nm +.Op Fl f | q +.Cm flush +.Nm +.Op Fl q +.Es \&{ \&} +.En Cm zero | resetlog | delete .Op Ar number ... -.Nm ipfw -delete -.Ar number ... -.Nm ipfw +.Nm +.Op Fl s Op Ar field .Op Fl aftN -list -.Op Ar number ... -.Nm ipfw -.Oo -.Fl ftN -.Oc -show +.Es \&{ \&} +.En Cm list | show .Op Ar number ... -.Nm ipfw -.Oo -.Fl q -.Oc -add +.Nm +.Op Fl q +.Cm add .Op Ar number -.Ar action -.Op log -.Ar proto -from -.Ar src -to -.Ar dst -.Op via Ar name | ipno -.Op Ar options +.Ar rule-body +.Nm +.Cm pipe +.Ar number +.Cm config +.Ar pipe-config-options +.Nm +.Cm pipe +.Es \&{ \&} +.En Cm delete | list | show +.Op Ar number ... +.Nm +.Cm queue +.Ar number +.Cm config +.Ar queue-config-options +.Nm +.Cm queue +.Es \&{ \&} +.En Cm delete | list | show +.Op Ar number ... .Sh DESCRIPTION -If used as shown in the first synopsis line, the -.Ar file -will be read line by line and applied as arguments to the .Nm +is the user interface for controlling the +.Xr ipfirewall 4 +and the +.Xr dummynet 4 +traffic shaper in +.Fx . +.Pp +Each incoming or outgoing packet is passed through the +.Nm +rules. +If host is acting as a gateway, packets forwarded by +the gateway are processed by +.Nm +twice. +In case a host is acting as a bridge, packets forwarded by +the bridge are processed by +.Nm +once. +.Pp +A firewall configuration is made of a list of numbered rules, +which is scanned for each packet until a match is found and +the relevant action is performed. +Depending on the action and certain system settings, packets +can be reinjected into the firewall at the rule after the +matching one for further processing. +All rules apply to all interfaces, so it is responsibility +of the system administrator to write the ruleset in such a +way as to minimize the number of checks. +.Pp +A configuration always includes a +.Em DEFAULT +rule (numbered 65535) which cannot be modified by the programmer +and always matches packets. +The action associated with the default rule can be either +.Cm deny +or +.Cm allow +depending on how the kernel is configured. +.Pp +If the ruleset includes one or more rules with the +.Cm keep-state +option, then +.Nm +assumes a +.Em stateful +behaviour, i.e. upon a match will create dynamic rules matching +the exact parameters (addresses and ports) of the matching packet. +.Pp +These dynamic rules, which have a limited lifetime, are checked +at the first occurrence of a +.Cm check-state +or +.Cm keep-state +rule, and are typically used to open the firewall on-demand to +legitimate traffic only. +See the +.Sx RULE FORMAT +and +.Sx EXAMPLES +sections below for more information on the stateful behaviour of +.Nm . +.Pp +All rules (including dynamic ones) have a few associated counters: +a packet count, a byte count, a log count and a timestamp +indicating the time of the last match. +Counters can be displayed or reset with +.Nm +commands. +.Pp +Rules can be added with the +.Cm add +command; deleted individually with the +.Cm delete +command, and globally with the +.Cm flush +command; displayed, optionally with the content of the +counters, using the +.Cm show +and +.Cm list +commands. +Finally, counters can be reset with the +.Cm zero +and +.Cm resetlog +commands. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl a +While listing, show counter values. +See also the +.Cm show command. +.It Fl f +Don't ask for confirmation for commands that can cause problems +if misused, +.No i.e. Cm flush . +.Em Note , +if there is no tty associated with the process, this is implied. +.It Fl q +While +.Cm add Ns ing , +.Cm zero Ns ing , +.Cm resetlog Ns ging +or +.Cm flush Ns ing , +be quiet about actions +(implies +.Fl f ) . +This is useful for adjusting rules by executing multiple +.Nm +commands in a script +(e.g., +.Ql sh\ /etc/rc.firewall ) , +or by processing a file of many +.Nm +rules, +across a remote login session. +If a +.Cm flush +is performed in normal (verbose) mode (with the default kernel +configuration), it prints a message. +Because all rules are flushed, the message cannot be delivered +to the login session. +This causes the remote login session to be closed and the +remainder of the ruleset is not processed. +Access to the console is required to recover. +.It Fl t +While listing, show last match timestamp. +.It Fl N +Try to resolve addresses and service names in output. +.It Fl s Op Ar field +While listing pipes, sort according to one of the four +counters (total and current packets or bytes). +.El +.Pp +To ease configuration, rules can be put into a file which is +processed using +.Nm +as shown in the first synopsis line. +An absolute +.Ar pathname +must be used. +The file +will be read line by line and applied as arguments to the +.Nm +utility. .Pp Optionally, a preprocessor can be specified using .Fl p Ar preproc where -.Ar file -is to be piped through. Useful preprocessors include +.Ar pathname +is to be piped through. +Useful preprocessors include .Xr cpp 1 and .Xr m4 1 . If .Ar preproc -doesn't start with a slash as its first character, the usual +doesn't start with a slash +.Pq Ql / +as its first character, the usual .Ev PATH -name search is performed. Care should be taken with this in environments -where not all filesystems are mounted (yet) by the time +name search is performed. +Care should be taken with this in environments where not all +filesystems are mounted (yet) by the time .Nm -is being run (e. g. since they are mounted over NFS). Once +is being run (e.g. when they are mounted over NFS). +Once .Fl p has been specified, optional .Fl D @@ -90,570 +236,867 @@ This allows for flexible configuration files (like conditionalizing them on the local hostname) and the use of macros to centralize frequently required arguments like IP addresses. .Pp -Each packet that has been received or is about to be sent goes through -the -.Nm -rules. In the case of a host acting as a gateway, packets that are -forwarded by the host are processed by +The .Nm -twice -.Po -once when entering, and once when leaving -.Pc . -Each packet can be filtered based on the following information that is -associated with it: -.Pp -.Bl -tag -offset indent -compact -width xxxx -.It Receive Interface Pq Ar recv -Interface over which the packet was received -.It Transmit Interface Pq Ar xmit -Interface over which the packet would be transmitted -.It Incoming Pq Ar in -Packet was just received -.It Outgoing Pq Ar out -Packet would be transmitted -.It Source IP Address -Sender's IP Address -.It Destination IP Address -Target's IP Address -.It Protocol -IP protocol, including but not limited to IP -.Pq Ar ip , -UDP -.Pq Ar udp , -TCP -.Pq Ar tcp , -or -ICMP -.Pq Ar icmp -.It Source Port -Sender's UDP or TCP port -.It Destination Port -Target's UDP or TCP port -.It Connection Setup Flag Pq Ar setup -This packet is a request to setup a TCP connection -.It Connection Established Flag Pq Ar established -This packet is part of an established TCP connection -.It All TCP Flags Pq Ar tcpflags -One or more of the TCP flags: close connection -.Pq Ar fin , -open connection -.Pq Ar syn , -reset connection -.Pq Ar rst , -push -.Pq Ar psh , -acknowledgment -.Pq Ar ack , -and -urgent -.Pq Ar urg -.It Fragment Flag Pq Ar frag -This packet is a fragment of an IP packet -.It IP Options Pq Ar ipoptions -One or more of the IP options: strict source route -.Pq Ar ssrr , -loose source route -.Pq Ar lsrr , -record route -.Pq Ar rr , -and timestamp -.Pq Ar ts -.It ICMP Types Pq Ar icmptypes -One or more of the ICMP types: echo reply -.Pq Ar 0 , -destination unreachable -.Pq Ar 3 , -source quench -.Pq Ar 4 , -redirect -.Pq Ar 5 , -echo request -.Pq Ar 8 , -router advertisement -.Pq Ar 9 , -router solicitation -.Pq Ar 10 , -time-to-live exceeded -.Pq Ar 11 , -IP header bad -.Pq Ar 12 , -timestamp request -.Pq Ar 13 , -timestamp reply -.Pq Ar 14 , -information request -.Pq Ar 15 , -information reply -.Pq Ar 16 , -address mask request -.Pq Ar 17 , -and address mask reply -.Pq Ar 18 -.El -.Pp -Note that may be dangerous to filter on the source IP address or -source TCP/UDP port because either or both could easily be spoofed. -.Pp +.Cm pipe +commands are used to configure the traffic shaper, as shown in the +.Sx TRAFFIC SHAPER CONFIGURATION +section below. +.Sh RULE FORMAT The .Nm -code works by going through the rule-list for each packet -until a match is found. -All rules have two associated counters, a packet count and -a byte count. -These counters are updated when a packet matches the rule. -.Pp -The rules are ordered by a -.Dq line-number -from 1 to 65534 that is used -to order and delete rules. Rules are tried in increasing order, and the -first rule that matches a packet applies. -Multiple rules may share the same number and apply in -the order in which they were added. -.Pp -If a rule is added without a number, it is numbered 100 higher than the highest -defined rule number, unless the highest defined rule number is 65435 or -greater, in which case new rules are given that same number. -.Pp -The delete operation deletes the first rule with number -.Ar number , -if any. -.Pp -The list command prints out the current rule set. -.Pp -The show command is equivalent to -.Sq ipfw -a list . -.Pp -The zero operation zeroes the counters associated with rule number -.Ar number . -.Pp -The flush operation removes all rules. -.Pp -Any command beginning with a -.Sq # , -or being all blank, is ignored. -.Pp -One rule is always present: -.Bd -literal -offset center -65535 deny all from any to any -.Ed -.Pp -This rule is the default policy, i.e., don't allow anything at all. -Your job in setting up rules is to modify this policy to match your -needs. -.Pp -However, if the kernel option -.Dq IPFIREWALL_DEFAULT_TO_ACCEPT -is active, the rule is instead: -.Bd -literal -offset center -65535 allow all from any to any +rule format is the following: +.Bd -ragged +.Op Cm prob Ar match_probability +.Ar action +.Op Cm log Op Cm logamount Ar number +.Ar proto +.Cm from Ar src +.Cm to Ar dst +.Op Ar interface-spec +.Op Ar options .Ed .Pp -This variation lets everything pass through. This option should only be -activated in particular circumstances, such as if you use the firewall -system as an on-demand denial-of-service filter that is normally wide open. +Each packet can be filtered based on the following information that is +associated with it: .Pp -The following options are available: -.Bl -tag -width flag -.It Fl a -While listing, show counter values. See also -.Dq show -command. -.It Fl f -Don't ask for confirmation for commands that can cause problems if misused -(i.e. flush). -.Ar Note , -if there is no tty associated with the process, this is implied. -.It Fl q -While adding, zeroing or flushing, be quiet about actions (implies '-f'). -This is useful for adjusting rules by executing multiple -.Nm -commands in a script -.Po -e.g., -.Sq sh /etc/rc.firewall -.Pc , -or by processing a file of many -.Nm -rules, -across a remote login session. If a flush is performed in normal -(verbose) mode (with the default kernel configuration), it prints a message. -Because all rules are flushed, the -message cannot be delivered to the login session. This causes the -remote login session to be closed and the remainder of the ruleset is -not processed. Access to the console is required to recover. -.It Fl t -While listing, show last match timestamp. -.It Fl N -Try to resolve addresses and service names in output. +.Bl -tag -width "Source and destination IP address" -offset indent -compact +.It Transmit and receive interface +(by name or address) +.It Direction +(incoming or outgoing) +.It Source and destination IP address +(possibly masked) +.It Protocol +(TCP, UDP, ICMP, etc.) +.It Source and destination port +(lists, ranges or masks) +.It TCP flags +.It IP fragment flag +.It IP options +.It ICMP types +.It User/group ID of the socket associated with the packet .El .Pp -.Ar action : -.Bl -hang -offset flag -width 1234567890123456 -.It Ar allow +Note that it may be dangerous to filter on the source IP +address or source TCP/UDP port because either or both could +easily be spoofed. +.Bl -tag -width indent +.It Cm prob Ar match_probability +A match is only declared with the specified probability +(floating point number between 0 and 1). +This can be useful for a number of applications such as +random packet drop or +(in conjunction with +.Xr dummynet 4 ) +to simulate the effect of multiple paths leading to out-of-order +packet delivery. +.It Ar action : +.Bl -tag -width indent +.It Cm allow Allow packets that match rule. -The search terminates. Aliases are -.Ar pass , -.Ar permit , +The search terminates. +Aliases are +.Cm pass , +.Cm permit and -.Ar accept . -.It Ar deny +.Cm accept . +.It Cm deny Discard packets that match this rule. The search terminates. -.Ar Drop +.Cm drop is an alias for -.Ar deny . -.It Ar reject -(Deprecated.) Discard packets that match this rule, and try to send an ICMP +.Cm deny . +.It Cm reject +(Deprecated). +Discard packets that match this rule, and try to send an ICMP host unreachable notice. The search terminates. -.It Ar unreach code +.It Cm unreach Ar code Discard packets that match this rule, and try to send an ICMP unreachable notice with code .Ar code , where .Ar code -is a number from zero to 255, or one of these aliases: -.Ar net , -.Ar host , -.Ar protocol , -.Ar port , -.Ar needfrag , -.Ar srcfail , -.Ar net-unknown , -.Ar host-unknown , -.Ar isolated , -.Ar net-prohib , -.Ar host-prohib , -.Ar tosnet , -.Ar toshost , -.Ar filter-prohib , -.Ar host-precedence , +is a number from 0 to 255, or one of these aliases: +.Cm net , host , protocol , port , +.Cm needfrag , srcfail , net-unknown , host-unknown , +.Cm isolated , net-prohib , host-prohib , tosnet , +.Cm toshost , filter-prohib , host-precedence or -.Ar precedence-cutoff . +.Cm precedence-cutoff . The search terminates. -.It Ar reset -TCP packets only. Discard packets that match this rule, -and try to send a TCP reset -.Pq RST -notice. +.It Cm reset +TCP packets only. +Discard packets that match this rule, and try to send a TCP +reset (RST) notice. The search terminates. -.It Ar count +.It Cm count Update counters for all packets that match rule. The search continues with the next rule. -.It Ar divert port +.It Cm check-state +Checks the packet against the dynamic ruleset. +If a match is found then the search terminates, otherwise +we move to the next rule. +If no +.Cm check-state +rule is found, the dynamic ruleset is checked at the first +.Cm keep-state +rule. +.It Cm divert Ar port Divert packets that match this rule to the .Xr divert 4 socket bound to port .Ar port . The search terminates. -.It Ar tee port +.It Cm tee Ar port Send a copy of packets matching this rule to the .Xr divert 4 socket bound to port .Ar port . -The search continues with the next rule. This feature is not yet implemeted. -.It Ar fwd ipaddr Op ,port +The search terminates and the original packet is accepted +(but see section +.Sx BUGS +below). +.It Cm fwd Ar ipaddr Ns Xo +.Op , Ns Ar port +.Xc Change the next-hop on matching packets to .Ar ipaddr , which can be an IP address in dotted quad or a host name. If .Ar ipaddr -is not a directly-reachable address, the route -as found in the local routing table for that IP is used -instead. +is not a directly-reachable address, the route as found in +the local routing table for that IP is used instead. If .Ar ipaddr -is a local address, then on a packet entering the system from a remote -host it will be diverted to +is a local address, then on a packet entering the system +from a remote host it will be diverted to .Ar port -on the local machine, keeping the local address of the socket set -to the original IP address the packet was destined for. This is intended -for use with transparent proxy servers. If the IP is not -a local address then the port number (if specified) is ignored and -the rule only applies to packets leaving the system. This will -also map addresses to local ports when packets are generated locally. -The search terminates if this rule matches. If the port number is not -given then the port number in the packet is used, so that a packet for -an external machine port Y would be forwarded to local port Y. The kernel -must have been compiled with optiions IPFIREWALL_FORWARD. -.It Ar skipto number +on the local machine, keeping the local address of the socket +set to the original IP address the packet was destined for. +This is intended for use with transparent proxy servers. +If the IP is not a local address then the port number +(if specified) is ignored and the rule only applies to packets +leaving the system. +This will also map addresses to local ports when packets are +generated locally. +The search terminates if this rule matches. +If the port number is not given then the port number in the +packet is used, so that a packet for an external machine port +Y would be forwarded to local port Y. +The kernel must have been compiled with the +.Dv IPFIREWALL_FORWARD +option. +.It Cm pipe Ar pipe_nr +Pass packet to a +.Xr dummynet 4 +.Dq pipe +(for bandwidth limitation, delay, etc.). +See the +.Sx TRAFFIC SHAPER CONFIGURATION +section for further information. +The search terminates; however, on exit from the pipe and if +the +.Xr sysctl 8 +variable +.Em net.inet.ip.fw.one_pass +is not set, the packet is passed again to the firewall code +starting from the next rule. +.It Cm queue Ar queue_nr +Pass packet to a +.Xr dummynet 4 +.Dq queue +(for bandwidth limitation using WF2Q). +.It Cm skipto Ar number Skip all subsequent rules numbered less than .Ar number . The search continues with the first rule numbered .Ar number or higher. .El -.Pp -If a packet matches more than one -.Ar divert -and/or -.Ar tee -rule, all but the last are ignored. -.Pp +.It Cm log Op Cm logamount Ar number If the kernel was compiled with .Dv IPFIREWALL_VERBOSE , then when a packet matches a rule with the -.Ar log -keyword a message will be printed on the console. +.Cm log +keyword a message will be +logged to +.Xr syslogd 8 +with a +.Dv LOG_SECURITY +facility. +.Em Note : +by default, they are appended to the +.Pa /var/log/security +file (see +.Xr syslog.conf 5 ) . If the kernel was compiled with the .Dv IPFIREWALL_VERBOSE_LIMIT -option, then logging will cease after the number of packets -specified by the option are received for that particular -chain entry. Logging may then be re-enabled by clearing -the packet counter for that entry. +option, then by default logging will cease after the number +of packets specified by the option are received for that +particular chain entry, and +.Em net.inet.ip.fw.verbose_limit +will be set to that number. +However, if +.Cm logamount Ar number +is used, that +.Ar number +will be the logging limit rather than +.Em net.inet.ip.fw.verbose_limit , +where the value +.Dq 0 +removes the logging limit. +Logging may then be re-enabled by clearing the logging counter +or the packet counter for that entry. .Pp Console logging and the log limit are adjustable dynamically through the .Xr sysctl 8 -interface. +interface in the MIB base of +.Em net.inet.ip.fw . +.It Ar proto +An IP protocol specified by number or name (for a complete +list see +.Pa /etc/protocols ) . +The +.Cm ip +or +.Cm all +keywords mean any protocol will match. +.It Ar src No and Ar dst : +.Cm any | me | Op Cm not +.Aq Ar address Ns / Ns Ar mask +.Op Ar ports .Pp -.Ar proto : -.Bl -hang -offset flag -width 1234567890123456 -.It Ar ip -All packets match. The alias -.Ar all -has the same effect. -.It Ar tcp -Only TCP packets match. -.It Ar udp -Only UDP packets match. -.It Ar icmp -Only ICMP packets match. -.It Ar -Only packets for the specified protocol matches (see -.Pa /etc/protocols -for a complete list). -.El +Specifying +.Cm any +makes the rule match any IP number. .Pp -.Ar src -and -.Ar dst : -.Bl -hang -offset flag -.It Ar
-.Op Ar ports -.El +Specifying +.Cm me +makes the rule match any IP number configured on an interface in the system. +This is a computationally semi-expensive check which should be used with care. .Pp The -.Em
+.Aq Ar address Ns / Ns Ar mask may be specified as: -.Bl -hang -offset flag -width 1234567890123456 +.Bl -tag -width "ipno/bits" .It Ar ipno -An ipnumber of the form 1.2.3.4. -Only this exact ip number match the rule. -.It Ar ipno/bits -An ipnumber with a mask width of the form 1.2.3.4/24. -In this case all ip numbers from 1.2.3.0 to 1.2.3.255 will match. -.It Ar ipno:mask -An ipnumber with a mask width of the form 1.2.3.4:255.255.240.0. -In this case all ip numbers from 1.2.0.0 to 1.2.15.255 will match. +An IP number of the form 1.2.3.4. +Only this exact IP number will match the rule. +.It Ar ipno Ns / Ns Ar bits +An IP number with a mask width of the form 1.2.3.4/24. +In this case all IP numbers from 1.2.3.0 to 1.2.3.255 will match. +.It Ar ipno Ns : Ns Ar mask +An IP number with a mask of the form 1.2.3.4:255.255.240.0. +In this case all IP numbers from 1.2.0.0 to 1.2.15.255 will match. .El .Pp The sense of the match can be inverted by preceding an address with the -.Dq not -modifier, causing all other addresses to be matched instead. This -does not affect the selection of port numbers. +.Cm not +modifier, causing all other addresses to be matched instead. +This does not affect the selection of port numbers. .Pp With the TCP and UDP protocols, optional .Em ports may be specified as: +.Bd -ragged -offset indent +.Sm off +.Eo \&{ +.Ar port | +.Ar port No \&- Ar port | +.Ar port : mask +.Ec \&} Op , Ar port Op , Ar ... +.Sm on +.Ed .Pp -.Bl -hang -offset flag -.It Ns {port|port-port} Ns Op ,port Ns Op ,... -.El +The +.Ql \&- +notation specifies a range of ports (including boundaries). +.Pp +The +.Ql \&: +notation specifies a port and a mask, a match is declared if +the port number in the packet matches the one in the rule, +limited to the bits which are set in the mask. .Pp -Service names (from +Service names (from .Pa /etc/services ) may be used instead of numeric port values. -A range may only be specified as the first value, -and the length of the port list is limited to +A range may only be specified as the first value, and the +length of the port list is limited to .Dv IP_FW_MAX_PORTS -(as defined in -.Pa /usr/src/sys/netinet/ip_fw.h ) -ports. +ports (as defined in +.Pa /usr/src/sys/netinet/ip_fw.h ) . +A backslash +.Pq Ql \e +can be used to escape the dash +.Pq Ql - +character in a service name: +.Pp +.Dl "ipfw add count tcp from any ftp\e\e-data-ftp to any" .Pp Fragmented packets which have a non-zero offset (i.e. not the first fragment) will never match a rule which has one or more port -specifications. See the -.Ar frag +specifications. +See the +.Cm frag option for details on matching fragmented packets. -.Pp -Rules can apply to packets when they are incoming, or outgoing, or both. -The -.Ar in -keyword indicates the rule should only match incoming packets. -The -.Ar out -keyword indicates the rule should only match outgoing packets. -.Pp -To match packets going through a certain interface, specify -the interface using -.Ar via : -.Bl -hang -offset flag -width 1234567890123456 -.It Ar via ifX +.It Ar interface-spec +Some combinations of the following specifiers are allowed: +.Bl -tag -width "via ipno" +.It Cm in +Only match incoming packets. +.It Cm out +Only match outgoing packets. +.It Cm via Ar ifX Packet must be going through interface -.Ar ifX. -.It Ar via if* +.Ar ifX . +.It Cm via Ar if Ns Cm * Packet must be going through interface .Ar ifX , -where X is any unit number. -.It Ar via any +where +.Ar X +is any unit number. +.It Cm via any Packet must be going through .Em some interface. -.It Ar via ipno +.It Cm via Ar ipno Packet must be going through the interface having IP address .Ar ipno . .El .Pp The -.Ar via +.Cm via keyword causes the interface to always be checked. If -.Ar recv +.Cm recv or -.Ar xmit +.Cm xmit is used instead of -.Ar via , -then the only receive or transmit interface (respectively) is checked. -By specifying both, it is possible to match packets based on both receive -and transmit interface, e.g.: +.Cm via , +then the only receive or transmit interface (respectively) +is checked. +By specifying both, it is possible to match packets based on +both receive and transmit interface, e.g.: .Pp .Dl "ipfw add 100 deny ip from any to any out recv ed0 xmit ed1" .Pp The -.Ar recv -interface can be tested on either incoming or outgoing packets, while the -.Ar xmit -interface can only be tested on outgoing packets. So -.Ar out +.Cm recv +interface can be tested on either incoming or outgoing packets, +while the +.Cm xmit +interface can only be tested on outgoing packets. +So +.Cm out is required (and -.Ar in -invalid) whenver -.Ar xmit -is used. Specifying -.Ar via +.Cm in +is invalid) whenever +.Cm xmit +is used. +Specifying +.Cm via together with -.Ar xmit +.Cm xmit or -.Ar recv +.Cm recv is invalid. .Pp -A packet may not have a receive or transmit interface: packets originating -from the local host have no receive interface. while packets destined for -the local host have no transmit interface. -.Pp -Additional -.Ar options : -.Bl -hang -offset flag -width 1234567890123456 -.It frag -Matches if the packet is a fragment and this is not the first fragment -of the datagram. -.Ar frag +A packet may not have a receive or transmit interface: packets +originating from the local host have no receive interface, +while packets destined for the local host have no transmit +interface. +.It Ar options : +.Bl -tag -width indent +.It Cm keep-state Op Ar method +Upon a match, the firewall will create a dynamic rule, whose +default behaviour is to matching bidirectional traffic between +source and destination IP/port using the same protocol. +The rule has a limited lifetime (controlled by a set of +.Xr sysctl 8 +variables), and the lifetime is refreshed every time a matching +packet is found. +.Pp +The actual behaviour can be modified by specifying a different +.Ar method , +although at the moment only the default one is specified. +.It Cm bridged +Matches only bridged packets. +This can be useful for multicast or broadcast traffic, which +would otherwise pass through the firewall twice: once during +bridging, and a second time when the packet is delivered to +the local stack. +.Pp +Apart from a small performance penalty, this would be a problem +when using +.Em pipes +because the same packet would be accounted for twice in terms +of bandwidth, queue occupation, and also counters. +.It Cm frag +Match if the packet is a fragment and this is not the first +fragment of the datagram. +.Cm frag may not be used in conjunction with either -.Ar tcpflags +.Cm tcpflags or TCP/UDP port specifications. -.It in -Matches if this packet was on the way in. -.It out -Matches if this packet was on the way out. -.It ipoptions Ar spec -Matches if the IP header contains the comma separated list of +.It Cm ipoptions Ar spec +Match if the IP header contains the comma separated list of options specified in .Ar spec . The supported IP options are: -.Ar ssrr +.Pp +.Cm ssrr (strict source route), -.Ar lsrr +.Cm lsrr (loose source route), -.Ar rr -(record packet route), and -.Ar ts +.Cm rr +(record packet route) and +.Cm ts (timestamp). The absence of a particular option may be denoted with a -.Dq ! . -.It established -Matches packets that have the RST or ACK bits set. +.Ql \&! . +.It Cm tcpoptions Ar spec +Match if the TCP header contains the comma separated list of +options specified in +.Ar spec . +The supported TCP options are: +.Pp +.Cm mss +(maximum segment size), +.Cm window +(tcp window advertisement), +.Cm sack +(selective ack), +.Cm ts +(rfc1323 timestamp) and +.Cm cc +(rfc1644 t/tcp connection count). +The absence of a particular option may be denoted +with a +.Ql \&! . +.It Cm established +TCP packets only. +Match packets that have the RST or ACK bits set. +.It Cm setup TCP packets only. -.It setup -Matches packets that have the SYN bit set but no ACK bit. +Match packets that have the SYN bit set but no ACK bit. +.It Cm tcpflags Ar spec TCP packets only. -.It tcpflags Ar spec -Matches if the TCP header contains the comma separated list of +Match if the TCP header contains the comma separated list of flags specified in .Ar spec . The supported TCP flags are: -.Ar fin , -.Ar syn , -.Ar rst , -.Ar psh , -.Ar ack , +.Pp +.Cm fin , +.Cm syn , +.Cm rst , +.Cm psh , +.Cm ack and -.Ar urg . +.Cm urg . The absence of a particular flag may be denoted with a -.Dq ! . +.Ql \&! . A rule which contains a -.Ar tcpflags +.Cm tcpflags specification can never match a fragmented packet which has -a non-zero offset. See the -.Ar frag +a non-zero offset. +See the +.Cm frag option for details on matching fragmented packets. -.It icmptypes Ar types -Matches if the ICMP type is in the list +.It Cm icmptypes Ar types +ICMP packets only. +Match if the ICMP type is in the list .Ar types . -The list may be specified as any combination of ranges -or individual types separated by commas. +The list may be specified as any combination of ranges or +individual types separated by commas. +The supported ICMP types are: +.Pp +echo reply +.Pq Cm 0 , +destination unreachable +.Pq Cm 3 , +source quench +.Pq Cm 4 , +redirect +.Pq Cm 5 , +echo request +.Pq Cm 8 , +router advertisement +.Pq Cm 9 , +router solicitation +.Pq Cm 10 , +time-to-live exceeded +.Pq Cm 11 , +IP header bad +.Pq Cm 12 , +timestamp request +.Pq Cm 13 , +timestamp reply +.Pq Cm 14 , +information request +.Pq Cm 15 , +information reply +.Pq Cm 16 , +address mask request +.Pq Cm 17 +and address mask reply +.Pq Cm 18 . +.It Cm uid Ar user +Match all TCP or UDP packets sent by or received for a +.Ar user . +A +.Ar user +may be matched by name or identification number. +.It Cm gid Ar group +Match all TCP or UDP packets sent by or received for a +.Ar group . +A +.Ar group +may be matched by name or identification number. +.El +.El +.Sh TRAFFIC SHAPER CONFIGURATION +The +.Nm +utility is also the user interface for the +.Xr dummynet 4 +traffic shaper. +The shaper operates by dividing packets into +.Em flows +according to a user-specified mask on different fields +of the IP header. +Packets belonging to the same flow are then passed to two +different objects, named +.Em pipe +or +.Em queue . +.Pp +A +.Em pipe +emulates a link with given bandwidth, propagation delay, +queue size and packet loss rate. +Packets transit through the pipe according to its parameters. +.Pp +A +.Em queue +is an abstraction used to implement the WF2Q+ policy. +The queue associates to each flow a weight and a reference pipe. +Then, all flows linked to the same pipe are scheduled at the +rate fixed by the pipe according to the WF2Q+ policy. +.Pp +The +.Nm +pipe configuration format is the following: +.Bd -ragged +.Cm pipe Ar number Cm config +.Op Cm bw Ar bandwidth | device +.Op Cm delay Ar ms-delay +.Oo +.Cm queue +.Es \&{ \&} +.En Ar slots | size +.Oc +.Op Cm plr Ar loss-probability +.Op Cm mask Ar mask-specifier +.Op Cm buckets Ar hash-table-size +.Oo +.Cm red | gred +.Sm off +.Ar w_q No / Xo +.Ar min_th No / +.Ar max_th No / +.Ar max_p +.Xc +.Sm on +.Oc +.Ed +.Pp +The +.Nm +queue configuration format is the following: +.Bd -ragged +.Cm queue Ar number Cm config +.Op Cm pipe Ar pipe_nr +.Op Cm weight Ar weight +.Oo +.Cm queue +.Es \&{ \&} +.En Ar slots | size +.Oc +.Op Cm plr Ar loss-probability +.Op Cm mask Ar mask-specifier +.Op Cm buckets Ar hash-table-size +.Oo +.Cm red | gred +.Sm off +.Ar w_q No / Xo +.Ar min_th No / +.Ar max_th No / +.Ar max_p +.Xc +.Sm on +.Oc +.Ed +.Pp +The following parameters can be configured for a pipe: +.Bl -tag -width indent +.It Cm bw Ar bandwidth | device +Bandwidth, measured in +.Sm off +.Oo +.Cm K | M +.Oc Eo \&{ +.Cm bit/s | Byte/s +.Ec \&} . +.Sm on +.Pp +A value of 0 (default) means unlimited bandwidth. +The unit must follow immediately the number, as in +.Pp +.Dl "ipfw pipe 1 config bw 300Kbit/s queue 50KBytes" +.Pp +If a device name is specified instead of a numeric +value, then the transmit clock is supplied by the specified +device. +At the moment only the +.Xr tun 4 +device supports this +functionality, for use in conjunction with +.Xr ppp 8 . +.It Cm delay Ar ms-delay +Propagation delay, measured in milliseconds. +The value is rounded to the next multiple of the clock tick +(typically 10ms, but it is a good practice to run kernels +with +.Dq "options HZ=1000" +to reduce +the granularity to 1ms or less). +Default value is 0, meaning no delay. +.It Cm queue Xo +.Es \&{ \&} +.En Ar slots | size Ns Cm Kbytes +.Xc +Queue size, in +.Ar slots +or +.Cm KBytes . +Default value is 50 slots, which +is the typical queue size for Ethernet devices. +Note that for slow speed links you should keep the queue +size short or your traffic might be affected by a significant +queueing delay. +E.g., 50 max-sized ethernet packets (1500 bytes) mean 600Kbit +or 20s of queue on a 30Kbit/s pipe. +Even worse effect can result if you get packets from an +interface with a much larger MTU, e.g. the loopback interface +with its 16KB packets. +.It Cm plr Ar packet-loss-rate +Packet loss rate. +Argument +.Ar packet-loss-rate +is a floating-point number between 0 and 1, with 0 meaning no +loss, 1 meaning 100% loss. +The loss rate is internally represented on 31 bits. +.It Cm mask Ar mask-specifier +The +.Xr dummynet 4 +lets you to create per-flow queues. +A flow identifier is constructed by masking the IP addresses, +ports and protocol types as specified in the pipe configuration. +Packets with the same identifier after masking fall into the +same queue. +Available mask specifiers are a combination of the following: +.Cm dst-ip Ar mask , +.Cm src-ip Ar mask , +.Cm dst-port Ar mask , +.Cm src-port Ar mask , +.Cm proto Ar mask +or +.Cm all , +where the latter means all bits in all fields are significant. +When used within a +.Ar pipe +configuration, each flow is assigned a rate equal +to the rate of the pipe. +When used within a +.Ar queue +configuration, each flow is assigned a weight equal to the +weight of the queue, and all flows insisting on the same pipe +share bandwidth proportionally to their weight. +.It Cm buckets Ar hash-table-size +Specifies the size of the hash table used for storing the +various queues. +Default value is 64 controlled by the +.Xr sysctl 8 +variable +.Em net.inet.ip.dummynet.hash_size , +allowed range is 16 to 1024. +.It Cm pipe Ar pipe_nr +Connects a queue to the specified pipe. +Multiple queues (usually +with different weights) can be connected to the same pipe, which +specifies the aggregate rate for the set of queues. +.It Cm weight Ar weight +Specifies the weight to be used for flows matching this queue. +The weight must be in the range 1..100, and defaults to 1. +.It Cm red | gred Xo +.Sm off +.Ar w_q No / +.Ar min_th No / +.Ar max_th No / +.Ar max_p +.Sm on +.Xc +Make use of the RED queue management algorithm. +.Ar w_q +and +.Ar max_p +are floating +point numbers between 0 and 1 (0 not included), while +.Ar min_th +and +.Ar max_th +are integer numbers specifying thresholds for queue management +(thresholds are computed in bytes if the queue has been defined +in bytes, in slots otherwise). +The +.Xr dummynet 4 +also supports the gentle RED variant (gred). +Three +.Xr sysctl 8 +variables can be used to control the RED behaviour: +.Bl -tag -width indent +.It Em net.inet.ip.dummynet.red_lookup_depth +specifies the accuracy in computing the average queue +when the link is idle (defaults to 256, must be greater than zero) +.It Em net.inet.ip.dummynet.red_avg_pkt_size +specifies the expected average packet size (defaults to 512, must be +greater than zero) +.It Em net.inet.ip.dummynet.red_max_pkt_size +specifies the expected maximum packet size, only used when queue +thresholds are in bytes (defaults to 1500, must be greater than zero). +.El .El .Sh CHECKLIST Here are some important points to consider when designing your rules: -.Bl -bullet -hang -offset flag -.It -Remember that you filter both packets going in and out. +.Bl -bullet +.It +Remember that you filter both packets going +.Cm in +and +.Cm out . Most connections need packets going in both directions. .It Remember to test very carefully. It is a good idea to be near the console when doing this. +If you cannot be near the console, +use an auto-recovery script such as the one in +.Pa /usr/share/examples/ipfw/change_rules.sh . .It Don't forget the loopback interface. .El .Sh FINE POINTS -There is one kind of packet that the firewall will always discard, -that is an IP fragment with a fragment offset of one. -This is a valid packet, but it only has one use, to try to circumvent -firewalls. -.Pp -If you are logged in over a network, loading the KLD version of +.Bl -bullet +.It +There is one kind of packet that the firewall will always +discard, that is a TCP packet's fragment with a fragment offset of +one. +This is a valid packet, but it only has one use, to try +to circumvent firewalls. +When logging is enabled, these packets are +reported as being dropped by rule -1. +.It +If you are logged in over a network, loading the +.Xr kld 4 +version of .Nm is probably not as straightforward as you would think. -I recommend this command line: -.Bd -literal -offset center +I recommend the following command line: +.Bd -literal -offset indent kldload /modules/ipfw.ko && \e -ipfw add 32000 allow all from any to any +ipfw add 32000 allow ip from any to any .Ed .Pp Along the same lines, doing an -.Bd -literal -offset center +.Bd -literal -offset indent ipfw flush .Ed .Pp in similar surroundings is also a bad idea. -.Pp -The IP filter list may not be modified if the system security level +.It +The +.Nm +filter list may not be modified if the system security level is set to 3 or higher -.Po -see +(see .Xr init 8 -for information on system security levels -.Pc . +for information on system security levels). +.El .Sh PACKET DIVERSION -A divert socket bound to the specified port will receive all packets diverted -to that port; see -.Xr divert 4 . +A +.Xr divert 4 +socket bound to the specified port will receive all packets +diverted to that port. If no socket is bound to the destination port, or if the kernel -wasn't compiled with divert socket support, diverted packets are dropped. +wasn't compiled with divert socket support, the packets are +dropped. +.Sh SYSCTL VARIABLES +A set of +.Xr sysctl 8 +variables controls the behaviour of the firewall. +These are shown below together with their default value and +meaning: +.Bl -tag -width indent +.It Em net.inet.ip.fw.debug : No 1 +Controls debugging messages produced by +.Nm . +.It Em net.inet.ip.fw.one_pass : No 1 +When set, the packet exiting from the +.Xr dummynet 4 +pipe is not passed though the firewall again. +Otherwise, after a pipe action, the packet is +reinjected into the firewall at the next rule. +.It Em net.inet.ip.fw.verbose : No 1 +Enables verbose messages. +.It Em net.inet.ip.fw.enable : No 1 +Enables the firewall. +Setting this variable to 0 lets you run your machine without +firewall even if compiled in. +.It Em net.inet.ip.fw.verbose_limit : No 0 +Limits the number of messages produced by a verbose firewall. +.It Em net.inet.ip.fw.dyn_buckets : No 256 +.It Em net.inet.ip.fw.curr_dyn_buckets : No 256 +The configured and current size of the hash table used to +hold dynamic rules. +This must be a power of 2. +The table can only be resized when empty, so in order to +resize it on the fly you will probably have to +.Cm flush +and reload the ruleset. +.It Em net.inet.ip.fw.dyn_count : No 3 +Current number of dynamic rules +(read-only). +.It Em net.inet.ip.fw.dyn_max : No 1000 +Maximum number of dynamic rules. +When you hit this limit, no more dynamic rules can be +installed until old ones expire. +.It Em net.inet.ip.fw.dyn_ack_lifetime : No 300 +.It Em net.inet.ip.fw.dyn_syn_lifetime : No 20 +.It Em net.inet.ip.fw.dyn_fin_lifetime : No 20 +.It Em net.inet.ip.fw.dyn_rst_lifetime : No 5 +.It Em net.inet.ip.fw.dyn_short_lifetime : No 30 +These variables control the lifetime, in seconds, of dynamic +rules. +Upon the initial SYN exchange the lifetime is kept short, +then increased after both SYN have been seen, then decreased +again during the final FIN exchange or when a RST +.El .Sh EXAMPLES This command adds an entry which denies all tcp packets from .Em cracker.evil.org @@ -661,31 +1104,172 @@ to the telnet port of .Em wolf.tambov.su from being forwarded by the host: .Pp -.Dl ipfw add deny tcp from cracker.evil.org to wolf.tambov.su 23 -.Pp -This one disallows any connection from the entire crackers network to -my host: +.Dl "ipfw add deny tcp from cracker.evil.org to wolf.tambov.su telnet" +.Pp +This one disallows any connection from the entire crackers +network to my host: +.Pp +.Dl "ipfw add deny ip from 123.45.67.0/24 to my.host.org" +.Pp +A first and efficient way to limit access (not using dynamic rules) +is the use of the following rules: .Pp -.Dl ipfw add deny all from 123.45.67.0/24 to my.host.org +.Dl "ipfw add allow tcp from any to any established" +.Dl "ipfw add allow tcp from net1 portlist1 to net2 portlist2 setup" +.Dl "ipfw add allow tcp from net3 portlist3 to net3 portlist3 setup" +.Dl "..." +.Dl "ipfw add deny tcp from any to any" +.Pp +The first rule will be a quick match for normal TCP packets, +but it will not match the initial SYN packet, which will be +matched by the +.Cm setup +rules only for selected source/destination pairs. +All other SYN packets will be rejected by the final +.Cm deny +rule. +.Pp +In order to protect a site from flood attacks involving fake +TCP packets, it is safer to use dynamic rules: +.Pp +.Dl "ipfw add check-state" +.Dl "ipfw add deny tcp from any to any established" +.Dl "ipfw add allow tcp from my-net to any setup keep-state" +.Pp +This will let the firewall install dynamic rules only for +those connection which start with a regular SYN packet coming +from the inside of our network. +Dynamic rules are checked when encountering the first +.Cm check-state +or +.Cm keep-state +rule. +A +.Cm check-state +rule should be usually placed near the beginning of the +ruleset to minimize the amount of work scanning the ruleset. +Your mileage may vary. +.Pp +.Em BEWARE : +stateful rules can be subject to denial-of-service attacks +by a SYN-flood which opens a huge number of dynamic rules. +The effects of such attacks can be partially limited by +acting on a set of +.Xr sysctl 8 +variables which control the operation of the firewall. .Pp Here is a good usage of the -.Ar list -command to see accounting records -and timestamp information: +.Cm list +command to see accounting records and timestamp information: .Pp -.Dl ipfw -at l +.Dl ipfw -at list .Pp or in short form without timestamps: .Pp -.Dl ipfw -a l +.Dl ipfw -a list +.Pp +Next rule diverts all incoming packets from 192.168.2.0/24 +to divert port 5000: +.Pp +.Dl ipfw divert 5000 ip from 192.168.2.0/24 to any in +.Pp +The following rules show some of the applications of +.Nm +and +.Xr dummynet 4 +for simulations and the like. +.Pp +This rule drops random incoming packets with a probability +of 5%: +.Pp +.Dl "ipfw add prob 0.05 deny ip from any to any in" +.Pp +A similar effect can be achieved making use of dummynet pipes: +.Pp +.Dl "ipfw add pipe 10 ip from any to any" +.Dl "ipfw pipe 10 config plr 0.05" +.Pp +We can use pipes to artificially limit bandwidth, e.g. on a +machine acting as a router, if we want to limit traffic from +local clients on 192.168.2.0/24 we do: +.Pp +.Dl "ipfw add pipe 1 ip from 192.168.2.0/24 to any out" +.Dl "ipfw pipe 1 config bw 300Kbit/s queue 50KBytes" +.Pp +note that we use the +.Cm out +modifier so that the rule is not used twice. +Remember in fact that +.Nm +rules are checked both on incoming and outgoing packets. +.Pp +Should we like to simulate a bidirectional link with bandwidth +limitations, the correct way is the following: .Pp -This rule diverts all incoming packets from 192.168.2.0/24 to divert port 5000: +.Dl "ipfw add pipe 1 ip from any to any out" +.Dl "ipfw add pipe 2 ip from any to any in" +.Dl "ipfw pipe 1 config bw 64Kbit/s queue 10Kbytes" +.Dl "ipfw pipe 2 config bw 64Kbit/s queue 10Kbytes" .Pp -.Dl ipfw divert 5000 all from 192.168.2.0/24 to any in +The above can be very useful, e.g. if you want to see how +your fancy Web page will look for a residential user which +is connected only through a slow link. +You should not use only one pipe for both directions, unless +you want to simulate a half-duplex medium (e.g. AppleTalk, +Ethernet, IRDA). +It is not necessary that both pipes have the same configuration, +so we can also simulate asymmetric links. +.Pp +Should we like to verify network performance with the RED queue +management algorithm: +.Pp +.Dl "ipfw add pipe 1 ip from any to any" +.Dl "ipfw pipe 1 config bw 500Kbit/s queue 100 red 0.002/30/80/0.1" +.Pp +Another typical application of the traffic shaper is to +introduce some delay in the communication. +This can affect a lot applications which do a lot of Remote +Procedure Calls, and where the round-trip-time of the +connection often becomes a limiting factor much more than +bandwidth: +.Pp +.Dl "ipfw add pipe 1 ip from any to any out" +.Dl "ipfw add pipe 2 ip from any to any in" +.Dl "ipfw pipe 1 config delay 250ms bw 1Mbit/s" +.Dl "ipfw pipe 2 config delay 250ms bw 1Mbit/s" +.Pp +Per-flow queueing can be useful for a variety of purposes. +A very simple one is counting traffic: +.Pp +.Dl "ipfw add pipe 1 tcp from any to any" +.Dl "ipfw add pipe 1 udp from any to any" +.Dl "ipfw add pipe 1 ip from any to any" +.Dl "ipfw pipe 1 config mask all" +.Pp +The above set of rules will create queues (and collect +statistics) for all traffic. +Because the pipes have no limitations, the only effect is +collecting statistics. +Note that we need 3 rules, not just the last one, because +when +.Nm +tries to match IP packets it will not consider ports, so we +would not see connections on separate ports as different +ones. +.Pp +A more sophisticated example is limiting the outbound traffic +on a net with per-host limits, rather than per-network limits: +.Pp +.Dl "ipfw add pipe 1 ip from 192.168.2.0/24 to any out" +.Dl "ipfw add pipe 2 ip from any to 192.168.2.0/24 in" +.Dl "ipfw pipe 1 config mask src-ip 0x000000ff bw 200Kbit/s queue 20Kbytes" +.Dl "ipfw pipe 2 config mask dst-ip 0x000000ff bw 200Kbit/s queue 20Kbytes" .Sh SEE ALSO .Xr cpp 1 , .Xr m4 1 , +.Xr bridge 4 , .Xr divert 4 , +.Xr dummynet 4 , .Xr ip 4 , .Xr ipfirewall 4 , .Xr protocols 5 , @@ -694,40 +1278,54 @@ This rule diverts all incoming packets from 192.168.2.0/24 to divert port 5000: .Xr kldload 8 , .Xr reboot 8 , .Xr sysctl 8 , -.Xr syslogd 8 . +.Xr syslogd 8 .Sh BUGS +The syntax has grown over the years and it is not very clean. .Pp .Em WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!!WARNING!! .Pp -This program can put your computer in rather unusable state. When -using it for the first time, work on the console of the computer, and -do +This program can put your computer in rather unusable state. +When using it for the first time, work on the console of the +computer, and do .Em NOT do anything you don't understand. .Pp -When manipulating/adding chain entries, service and protocol names are -not accepted. +When manipulating/adding chain entries, service and protocol names +are not accepted. .Pp Incoming packet fragments diverted by -.Ar divert -are reassembled before delivery to the socket, whereas fragments diverted via -.Ar tee -are not. -.Pp -Port aliases containing dashes cannot be first in a list. +.Cm divert +or +.Cm tee +are reassembled before delivery to the socket. .Pp -The -.Dq tee -action is unimplemented. +Packets that match a +.Cm tee +rule should not be immediately accepted, but should continue +going through the rule list. +This may be fixed in a later version. .Sh AUTHORS .An Ugen J. S. Antsilevich , .An Poul-Henning Kamp , .An Alex Nash , -.An Archie Cobbs . +.An Archie Cobbs , +.An Luigi Rizzo . +.Pp +.An -nosplit API based upon code written by .An Daniel Boulet for BSDI. +.Pp +Work on +.Xr dummynet 4 +traffic shaper supported by Akamba Corp. .Sh HISTORY +The .Nm -first appeared in +utility first appeared in .Fx 2.0 . +.Xr dummynet 4 +was introduced in +.Fx 2.2.8 . +Stateful extensions were introduced in +.Fx 4.0 . diff --git a/ipfw.tproj/ipfw.c b/ipfw.tproj/ipfw.c index 4779940..3eba9bc 100644 --- a/ipfw.tproj/ipfw.c +++ b/ipfw.tproj/ipfw.c @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ /* * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp * Copyright (c) 1994 Ugen J.S.Antsilevich @@ -16,54 +37,58 @@ * * NEW command line interface for IP firewall facility * - * $Id: ipfw.c,v 1.4 2001/07/17 22:59:33 lindak Exp $ - * */ -#include -#include + + +#include +#include #include #include +#include #include #include +#include #include #include #include +#include #include #include +#include #include #include #include #include #include -#include -#include #include +#include #include #include #include -#include #include #include #include #include /* def. of struct route */ -#include -#include +#ifdef DUMMYNET #include +#endif /* DUMMYNET */ #include #include -int lineno = -1; - -int s; /* main RAW socket */ -int do_resolv=0; /* Would try to resolve all */ -int do_acct=0; /* Show packet/byte count */ -int do_time=0; /* Show time stamps */ -int do_quiet=0; /* Be quiet in add and flush */ -int do_force=0; /* Don't ask for confirmation */ -int do_pipe=0; /* this cmd refers to a pipe */ +int s, /* main RAW socket */ + do_resolv, /* Would try to resolve all */ + do_acct, /* Show packet/byte count */ + do_time, /* Show time stamps */ + do_quiet, /* Be quiet in add and flush */ + do_force, /* Don't ask for confirmation */ + #ifdef DUMMYNET + do_pipe, /* this cmd refers to a pipe */ + #endif /* DUMMYNET */ + do_sort, /* field to sort results (0 = no) */ + verbose; struct icmpcode { int code; @@ -86,7 +111,7 @@ static struct icmpcode icmpcodes[] = { { ICMP_UNREACH_TOSHOST, "toshost" }, { ICMP_UNREACH_FILTER_PROHIB, "filter-prohib" }, { ICMP_UNREACH_HOST_PRECEDENCE, "host-precedence" }, - { ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" }, + { ICMP_UNREACH_PRECEDENCE_CUTOFF, "precedence-cutoff" }, { 0, NULL } }; @@ -95,22 +120,22 @@ static void show_usage(const char *fmt, ...); static int mask_bits(struct in_addr m_ad) { - int h_fnd=0,h_num=0,i; + int h_fnd = 0, h_num = 0, i; u_long mask; - mask=ntohl(m_ad.s_addr); - for (i=0;i>1; + mask = mask >> 1; } return h_num; -} +} static void print_port(prot, port, comma) @@ -123,6 +148,10 @@ print_port(prot, port, comma) const char *protocol; int printed = 0; + if (!strcmp(comma, ":")) { + printf("%s0x%04x", comma, port); + return; + } if (do_resolv) { pe = getprotobynumber(prot); if (pe) @@ -135,9 +164,9 @@ print_port(prot, port, comma) printf("%s%s", comma, se->s_name); printed = 1; } - } + } if (!printed) - printf("%s%d",comma,port); + printf("%s%d", comma, port); } static void @@ -147,10 +176,10 @@ print_iface(char *key, union ip_fw_if *un, int byname) if (byname) { strncpy(ifnb, un->fu_via_if.name, FW_IFNLEN); - ifnb[FW_IFNLEN]='\0'; + ifnb[FW_IFNLEN] = '\0'; if (un->fu_via_if.unit == -1) printf(" %s %s*", key, ifnb); - else + else printf(" %s %s%d", key, ifnb, un->fu_via_if.unit); } else if (un->fu_via_ip.s_addr != 0) { printf(" %s %s", key, inet_ntoa(un->fu_via_ip)); @@ -183,29 +212,36 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) int ndp = IP_FW_GETNDSTP(chain); if (do_resolv) - setservent(1/*stayopen*/); + setservent(1/*stay open*/); printf("%05u ", chain->fw_number); - if (do_acct) - printf("%*qu %*qu ",pcwidth,chain->fw_pcnt,bcwidth,chain->fw_bcnt); + if (do_acct) + printf("%*qu %*qu ", pcwidth, chain->fw_pcnt, bcwidth, chain->fw_bcnt); - if (do_time) - { - if (chain->timestamp) - { + if (do_time) { + if (chain->timestamp) { char timestr[30]; strcpy(timestr, ctime((time_t *)&chain->timestamp)); *strchr(timestr, '\n') = '\0'; printf("%s ", timestr); + } else { + printf(" "); } - else - printf(" "); + } + if (chain->fw_flg == IP_FW_F_CHECK_S) { + printf("check-state\n"); + goto done; } - switch (chain->fw_flg & IP_FW_F_COMMAND) - { + if (chain->fw_flg & IP_FW_F_RND_MATCH) { + double d = 1.0 * (int)(chain->pipe_ptr); + d = 1 - (d / 0x7fffffff); + printf("prob %f ", d); + } + + switch (chain->fw_flg & IP_FW_F_COMMAND) { case IP_FW_F_ACCEPT: printf("allow"); break; @@ -224,9 +260,13 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) case IP_FW_F_SKIPTO: printf("skipto %u", chain->fw_skipto_rule); break; - case IP_FW_F_PIPE: - printf("pipe %u", chain->fw_skipto_rule); - break ; + + case IP_FW_F_PIPE: + printf("pipe %u", chain->fw_skipto_rule); + break; + case IP_FW_F_QUEUE: + printf("queue %u", chain->fw_skipto_rule); + break; case IP_FW_F_REJECT: if (chain->fw_reject_code == IP_FW_REJECT_RST) printf("reset"); @@ -243,9 +283,12 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) default: errx(EX_OSERR, "impossible"); } - - if (chain->fw_flg & IP_FW_F_PRN) + + if (chain->fw_flg & IP_FW_F_PRN) { printf(" log"); + if (chain->fw_logamount) + printf(" logamount %d", chain->fw_logamount); + } pe = getprotobynumber(chain->fw_prot); if (pe) @@ -253,87 +296,118 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) else printf(" %u", chain->fw_prot); - printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : ""); - - adrt=ntohl(chain->fw_smsk.s_addr); - if (adrt==ULONG_MAX && do_resolv) { - adrt=(chain->fw_src.s_addr); - he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET); - if (he==NULL) { - printf(inet_ntoa(chain->fw_src)); - } else - printf("%s",he->h_name); + if (chain->fw_flg & IP_FW_F_SME) { + printf(" from me"); } else { - if (adrt!=ULONG_MAX) { - mb=mask_bits(chain->fw_smsk); - if (mb == 0) { - printf("any"); - } else { - if (mb > 0) { - printf(inet_ntoa(chain->fw_src)); - printf("/%d",mb); + printf(" from %s", chain->fw_flg & IP_FW_F_INVSRC ? "not " : ""); + + adrt = ntohl(chain->fw_smsk.s_addr); + if (adrt == ULONG_MAX && do_resolv) { + adrt = (chain->fw_src.s_addr); + he = gethostbyaddr((char *)&adrt, + sizeof(u_long), AF_INET); + if (he == NULL) { + printf("%s", inet_ntoa(chain->fw_src)); + } else + printf("%s", he->h_name); + } else { + if (adrt != ULONG_MAX) { + mb = mask_bits(chain->fw_smsk); + if (mb == 0) { + printf("any"); } else { - printf(inet_ntoa(chain->fw_src)); - printf(":"); - printf(inet_ntoa(chain->fw_smsk)); + if (mb > 0) { + printf("%s", inet_ntoa(chain->fw_src)); + printf("/%d", mb); + } else { + printf("%s", inet_ntoa(chain->fw_src)); + printf(":"); + printf("%s", inet_ntoa(chain->fw_smsk)); + } } - } - } else - printf(inet_ntoa(chain->fw_src)); + } else + printf("%s", inet_ntoa(chain->fw_src)); + } } if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) { comma = " "; for (i = 0; i < nsp; i++) { print_port(chain->fw_prot, chain->fw_uar.fw_pts[i], comma); - if (i==0 && (chain->fw_flg & IP_FW_F_SRNG)) + if (i == 0 && (chain->fw_flg & IP_FW_F_SRNG)) comma = "-"; + else if (i == 0 && (chain->fw_flg & IP_FW_F_SMSK)) + comma = ":"; else comma = ","; } } - printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : ""); - - adrt=ntohl(chain->fw_dmsk.s_addr); - if (adrt==ULONG_MAX && do_resolv) { - adrt=(chain->fw_dst.s_addr); - he=gethostbyaddr((char *)&adrt,sizeof(u_long),AF_INET); - if (he==NULL) { - printf(inet_ntoa(chain->fw_dst)); - } else - printf("%s",he->h_name); + if (chain->fw_flg & IP_FW_F_DME) { + printf(" to me"); } else { - if (adrt!=ULONG_MAX) { - mb=mask_bits(chain->fw_dmsk); - if (mb == 0) { - printf("any"); - } else { - if (mb > 0) { - printf(inet_ntoa(chain->fw_dst)); - printf("/%d",mb); + printf(" to %s", chain->fw_flg & IP_FW_F_INVDST ? "not " : ""); + + adrt = ntohl(chain->fw_dmsk.s_addr); + if (adrt == ULONG_MAX && do_resolv) { + adrt = (chain->fw_dst.s_addr); + he = gethostbyaddr((char *)&adrt, + sizeof(u_long), AF_INET); + if (he == NULL) { + printf("%s", inet_ntoa(chain->fw_dst)); + } else + printf("%s", he->h_name); + } else { + if (adrt != ULONG_MAX) { + mb = mask_bits(chain->fw_dmsk); + if (mb == 0) { + printf("any"); } else { - printf(inet_ntoa(chain->fw_dst)); - printf(":"); - printf(inet_ntoa(chain->fw_dmsk)); + if (mb > 0) { + printf("%s", inet_ntoa(chain->fw_dst)); + printf("/%d", mb); + } else { + printf("%s", inet_ntoa(chain->fw_dst)); + printf(":"); + printf("%s", inet_ntoa(chain->fw_dmsk)); + } } - } - } else - printf(inet_ntoa(chain->fw_dst)); + } else + printf("%s", inet_ntoa(chain->fw_dst)); + } } if (chain->fw_prot == IPPROTO_TCP || chain->fw_prot == IPPROTO_UDP) { comma = " "; for (i = 0; i < ndp; i++) { print_port(chain->fw_prot, chain->fw_uar.fw_pts[nsp+i], comma); - if (i==0 && (chain->fw_flg & IP_FW_F_DRNG)) + if (i == 0 && (chain->fw_flg & IP_FW_F_DRNG)) comma = "-"; + else if (i == 0 && (chain->fw_flg & IP_FW_F_DMSK)) + comma = ":"; else comma = ","; } } + if (chain->fw_flg & IP_FW_F_UID) { + struct passwd *pwd = getpwuid(chain->fw_uid); + + if (pwd) + printf(" uid %s", pwd->pw_name); + else + printf(" uid %u", chain->fw_uid); + } + + if (chain->fw_flg & IP_FW_F_KEEP_S) { + if (chain->next_rule_ptr) + printf(" keep-state %d", (int)chain->next_rule_ptr); + else + printf(" keep-state"); + } /* Direction */ + if (chain->fw_flg & IP_FW_BRIDGED) + printf(" bridged"); if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT)) printf(" in"); if (!(chain->fw_flg & IP_FW_F_IN) && (chain->fw_flg & IP_FW_F_OUT)) @@ -371,9 +445,9 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) if (chain->fw_ipnopt & IP_FW_IPOPT_RR) PRINTOPT("!rr"); if (chain->fw_ipopt & IP_FW_IPOPT_TS) PRINTOPT("ts"); if (chain->fw_ipnopt & IP_FW_IPOPT_TS) PRINTOPT("!ts"); - } + } - if (chain->fw_tcpf & IP_FW_TCPF_ESTAB) + if (chain->fw_ipflg & IP_FW_IF_TCPEST) printf(" established"); else if (chain->fw_tcpf == IP_FW_TCPF_SYN && chain->fw_tcpnf == IP_FW_TCPF_ACK) @@ -383,7 +457,7 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) #define PRINTFLG(x) {if (_flg_printed) printf(",");\ printf(x); _flg_printed = 1;} - printf(" tcpflg "); + printf(" tcpflags "); if (chain->fw_tcpf & IP_FW_TCPF_FIN) PRINTFLG("fin"); if (chain->fw_tcpnf & IP_FW_TCPF_FIN) PRINTFLG("!fin"); if (chain->fw_tcpf & IP_FW_TCPF_SYN) PRINTFLG("syn"); @@ -396,7 +470,25 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) if (chain->fw_tcpnf & IP_FW_TCPF_ACK) PRINTFLG("!ack"); if (chain->fw_tcpf & IP_FW_TCPF_URG) PRINTFLG("urg"); if (chain->fw_tcpnf & IP_FW_TCPF_URG) PRINTFLG("!urg"); - } + } + if (chain->fw_tcpopt || chain->fw_tcpnopt) { + int _opt_printed = 0; +#define PRINTTOPT(x) {if (_opt_printed) printf(",");\ + printf(x); _opt_printed = 1;} + + printf(" tcpoptions "); + if (chain->fw_tcpopt & IP_FW_TCPOPT_MSS) PRINTTOPT("mss"); + if (chain->fw_tcpnopt & IP_FW_TCPOPT_MSS) PRINTTOPT("!mss"); + if (chain->fw_tcpopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("window"); + if (chain->fw_tcpnopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("!window"); + if (chain->fw_tcpopt & IP_FW_TCPOPT_SACK) PRINTTOPT("sack"); + if (chain->fw_tcpnopt & IP_FW_TCPOPT_SACK) PRINTTOPT("!sack"); + if (chain->fw_tcpopt & IP_FW_TCPOPT_TS) PRINTTOPT("ts"); + if (chain->fw_tcpnopt & IP_FW_TCPOPT_TS) PRINTTOPT("!ts"); + if (chain->fw_tcpopt & IP_FW_TCPOPT_CC) PRINTTOPT("cc"); + if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC) PRINTTOPT("!cc"); + } + if (chain->fw_flg & IP_FW_F_ICMPBIT) { int type_index; int first = 1; @@ -404,98 +496,243 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth) printf(" icmptype"); for (type_index = 0; type_index < IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8; ++type_index) - if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] & + if (chain->fw_uar.fw_icmptypes[type_index / (sizeof(unsigned) * 8)] & (1U << (type_index % (sizeof(unsigned) * 8)))) { printf("%c%d", first == 1 ? ' ' : ',', type_index); first = 0; } } printf("\n"); +done: if (do_resolv) endservent(); } +#ifdef DUMMYNET +int +sort_q(const void *pa, const void *pb) +{ + int rev = (do_sort < 0); + int field = rev ? -do_sort : do_sort; + long long res = 0; + const struct dn_flow_queue *a = pa; + const struct dn_flow_queue *b = pb; + + switch (field) { + case 1: /* pkts */ + res = a->len - b->len; + break; + case 2 : /* bytes */ + res = a->len_bytes - b->len_bytes; + break; + + case 3 : /* tot pkts */ + res = a->tot_pkts - b->tot_pkts; + break; + + case 4 : /* tot bytes */ + res = a->tot_bytes - b->tot_bytes; + break; + } + if (res < 0) + res = -1; + if (res > 0) + res = 1; + return (int)(rev ? res : -res); +} + +static void +list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) +{ + int l; + + printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", + fs->flow_mask.proto, + fs->flow_mask.src_ip, fs->flow_mask.src_port, + fs->flow_mask.dst_ip, fs->flow_mask.dst_port); + if (fs->rq_elements == 0) + return; + + printf("BKT Prot ___Source IP/port____ " + "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); + if (do_sort != 0) + heapsort(q, fs->rq_elements, sizeof(*q), sort_q); + for (l = 0; l < fs->rq_elements; l++) { + struct in_addr ina; + struct protoent *pe; + + ina.s_addr = htonl(q[l].id.src_ip); + printf("%3d ", q[l].hash_slot); + pe = getprotobynumber(q[l].id.proto); + if (pe) + printf("%-4s ", pe->p_name); + else + printf("%4u ", q[l].id.proto); + printf("%15s/%-5d ", inet_ntoa(ina), q[l].id.src_port); + ina.s_addr = htonl(q[l].id.dst_ip); + printf("%15s/%-5d ", + inet_ntoa(ina), q[l].id.dst_port); + printf("%4qu %8qu %2u %4u %3u\n", + q[l].tot_pkts, q[l].tot_bytes, + q[l].len, q[l].len_bytes, q[l].drops); + if (verbose) + printf(" S %20qd F %20qd\n", q[l].S, q[l].F); + } +} + +static void +print_flowset_parms(struct dn_flow_set *fs, char *prefix) +{ + int l; + char qs[30]; + char plr[30]; + char red[90]; /* Display RED parameters */ + + l = fs->qsize; + if (fs->flags_fs & DN_QSIZE_IS_BYTES) { + if (l >= 8192) + sprintf(qs, "%d KB", l / 1024); + else + sprintf(qs, "%d B", l); + } else + sprintf(qs, "%3d sl.", l); + if (fs->plr) + sprintf(plr, "plr %f", 1.0*fs->plr/(double)(0x7fffffff)); + else + plr[0]='\0'; + if (fs->flags_fs & DN_IS_RED) /* RED parameters */ + sprintf(red, + "\n %cRED w_q %f min_th %d max_th %d max_p %f", + (fs->flags_fs & DN_IS_GENTLE_RED)? 'G' : ' ', + 1.0 * fs->w_q / (double)(1 << SCALE_RED), + SCALE_VAL(fs->min_th), + SCALE_VAL(fs->max_th), + 1.0 * fs->max_p / (double)(1 << SCALE_RED) ) ; + else + sprintf(red, "droptail"); + + printf("%s %s%s %d queues (%d buckets) %s\n", prefix, qs, plr, + fs->rq_elements, fs->rq_size, red); +} +#endif /* DUMMYNET */ + static void list(ac, av) int ac; char **av; { struct ip_fw *rules; + #ifdef DUMMYNET struct dn_pipe *pipes; + #endif /* DUMMYNET */ void *data = NULL; int pcwidth = 0; int bcwidth = 0; int n, num = 0; + int nbytes; /* get rules or pipes from kernel, resizing array as necessary */ { + #ifdef DUMMYNET const int unit = do_pipe ? sizeof(*pipes) : sizeof(*rules); const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; - int nalloc = 0; - int nbytes; - - while (num >= nalloc) { + #else /* DUMMYNET */ + const int unit = sizeof(*rules); + const int ocmd = IP_FW_GET; + #endif /* DUMMYNET */ + int nalloc = unit; + nbytes = nalloc; + + while (nbytes >= nalloc) { nalloc = nalloc * 2 + 200; - nbytes = nalloc * unit; + nbytes = nalloc; if ((data = realloc(data, nbytes)) == NULL) err(EX_OSERR, "realloc"); + rules = data; + rules->version = IP_FW_CURRENT_API_VERSION; if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0) + #ifdef DUMMYNET err(EX_OSERR, "getsockopt(IP_%s_GET)", do_pipe ? "DUMMYNET" : "FW"); - num = nbytes / unit; + #else /* DUMMYNET */ + err(EX_OSERR, "getsockopt(IP_FW_GET)"); + #endif /* DUMMYNET */ } } /* display requested pipes */ + #ifdef DUMMYNET if (do_pipe) { - u_long rulenum; - - pipes = (struct dn_pipe *) data; - if (ac > 0) - rulenum = strtoul(*av++, NULL, 10); - else - rulenum = 0 ; - for (n = 0; n < num; n++) { - struct dn_pipe *const p = &pipes[n]; - double b = p->bandwidth ; - char buf[30] ; - char qs[30] ; - char plr[30] ; - int l ; - - if (rulenum != 0 && rulenum != p->pipe_nr) - continue; - if (b == 0) - sprintf(buf, "unlimited"); - else if (b >= 1000000) - sprintf(buf, "%7.3f Mbit/s", b/1000000 ); - else if (b >= 1000) - sprintf(buf, "%7.3f Kbit/s", b/1000 ); - else - sprintf(buf, "%7.3f bit/s ", b ); - - if ( (l = p->queue_size_bytes) != 0 ) { - if (l >= 8192) - sprintf(qs,"%d KB", l / 1024); - else - sprintf(qs,"%d B", l); - } else - sprintf(qs,"%3d sl.", p->queue_size); - if (p->plr) - sprintf(plr,"plr %f", 1.0*p->plr/(double)(0x7fffffff)); + u_long rulenum; + void *next = data; + struct dn_pipe *p = (struct dn_pipe *) data; + struct dn_flow_set *fs; + struct dn_flow_queue *q; + int l; + + if (ac > 0) + rulenum = strtoul(*av++, NULL, 10); else - plr[0]='\0'; + rulenum = 0; + for (; nbytes >= sizeof(*p); p = (struct dn_pipe *)next) { + double b = p->bandwidth; + char buf[30]; + char prefix[80]; - printf("%05d: %s %4d ms %s %s -- %d pkts (%d B) %d drops\n", - p->pipe_nr, buf, p->delay, qs, plr, - p->r_len, p->r_len_bytes, p->r_drops); - } - free(data); - return; + if (p->next != (struct dn_pipe *)DN_IS_PIPE) + break; + l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); + next = (void *)p + l; + nbytes -= l; + q = (struct dn_flow_queue *)(p+1); + + if (rulenum != 0 && rulenum != p->pipe_nr) + continue; + if (p->if_name[0] != '\0') + sprintf(buf, "%s", p->if_name); + else if (b == 0) + sprintf(buf, "unlimited"); + else if (b >= 1000000) + sprintf(buf, "%7.3f Mbit/s", b/1000000); + else if (b >= 1000) + sprintf(buf, "%7.3f Kbit/s", b/1000); + else + sprintf(buf, "%7.3f bit/s ", b); + + sprintf(prefix, "%05d: %s %4d ms ", + p->pipe_nr, buf, p->delay); + print_flowset_parms(&(p->fs), prefix); + if (verbose) + printf(" V %20qd\n", p->V >> MY_M); + list_queues(&(p->fs), q); + } + fs = (struct dn_flow_set *) next; + for (; nbytes >= sizeof(*fs); fs = (struct dn_flow_set *)next) { + char prefix[80]; + + if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE) + break; + l = sizeof(*fs) + fs->rq_elements * sizeof(*q); + next = (void *)fs + l; + nbytes -= l; + q = (struct dn_flow_queue *)(fs+1); + sprintf(prefix, "q%05d: weight %d pipe %d ", + fs->fs_nr, fs->weight, fs->parent_nr); + print_flowset_parms(fs, prefix); + list_queues(fs, q); + } + free(data); + return; } + #endif /* DUMMYNET */ - /* if showing stats, figure out column widths ahead of time */ rules = (struct ip_fw *) data; + /* determine num more accurately */ + num = 0; + while (rules[num].fw_number < 65535) + num++; + num++; /* counting starts from 0 ... */ + /* if showing stats, figure out column widths ahead of time */ if (do_acct) { for (n = 0; n < num; n++) { struct ip_fw *const r = &rules[n]; @@ -556,6 +793,45 @@ list(ac, av) if (exitval != EX_OK) exit(exitval); } + /* + * show dynamic rules + */ + if (num * sizeof (rules[0]) != nbytes) { + struct ipfw_dyn_rule *d = + (struct ipfw_dyn_rule *)&rules[num]; + struct in_addr a; + struct protoent *pe; + + printf("## Dynamic rules:\n"); + for (;; d++) { + printf("%05d %qu %qu (T %d, # %d) ty %d", + (int)(d->chain), + d->pcnt, d->bcnt, + d->expire, + d->bucket, + d->type); + pe = getprotobynumber(d->id.proto); + if (pe) + printf(" %s,", pe->p_name); + else + printf(" %u,", d->id.proto); + a.s_addr = htonl(d->id.src_ip); + printf(" %s", inet_ntoa(a)); + printf(" %d", d->id.src_port); + switch (d->type) { + default: /* bidir, no mask */ + printf(" <->"); + break; + } + a.s_addr = htonl(d->id.dst_ip); + printf(" %s", inet_ntoa(a)); + printf(" %d", d->id.dst_port); + printf("\n"); + if (d->next == NULL) + break; + } + } + free(data); } @@ -572,20 +848,33 @@ show_usage(const char *fmt, ...) warnx("error: %s", buf); } fprintf(stderr, "usage: ipfw [options]\n" -" flush\n" +#ifdef DUMMYNET +" [pipe] flush\n" +#endif /* DUMMYNET */ " add [number] rule\n" -" delete number ...\n" -" list [number ...]\n" -" show [number ...]\n" +#ifdef DUMMYNET +" [pipe] delete number ...\n" +" [pipe] list [number ...]\n" +" [pipe] show [number ...]\n" +#endif /* DUMMYNET */ " zero [number ...]\n" -" rule: action proto src dst extras...\n" +" resetlog [number ...]\n" +#ifdef DUMMYNET +" pipe number config [pipeconfig]\n" +#endif /* DUMMYNET */ +" rule: [prob ] action proto src dst extras...\n" " action:\n" " {allow|permit|accept|pass|deny|drop|reject|unreach code|\n" -" reset|count|skipto num|divert port|tee port|fwd ip} [log]\n" +" reset|count|skipto num|divert port|tee port|fwd ip|\n" +#ifdef DUMMYNET +" pipe num" +#endif /* DUMMYNET */ +"} [log [logamount count]]\n" " proto: {ip|tcp|udp|icmp|}\n" -" src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" -" dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" +" src: from [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" +" dst: to [not] {me|any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" " extras:\n" +" uid {user id}\n" " fragment (may not be used with ports or tcpflags)\n" " in\n" " out\n" @@ -593,7 +882,21 @@ show_usage(const char *fmt, ...) " {established|setup}\n" " tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n" " ipoptions [!]{ssrr|lsrr|rr|ts},...\n" -" icmptypes {type[,type]}...\n"); +" tcpoptions [!]{mss|window|sack|ts|cc},...\n" +" icmptypes {type[,type]}...\n" +#ifdef DUMMYNET +" pipeconfig:\n" +" {bw|bandwidth} {bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n" +" {bw|bandwidth} interface_name\n" +" delay \n" +" queue {packets|Bytes|KBytes}\n" +" plr \n" +" mask {all| [dst-ip|src-ip|dst-port|src-port|proto] }\n" +" buckets }\n" +" {red|gred} ///\n" +" droptail\n" +#endif /* DUMMYNET */ +); exit(EX_USAGE); } @@ -603,16 +906,13 @@ lookup_host (host, ipaddr) char *host; struct in_addr *ipaddr; { - struct hostent *he = gethostbyname(host); - - if (!he) { - if (inet_aton(host, ipaddr)) - return(0); - else - return(-1); - } - *ipaddr = *(struct in_addr *)he->h_addr_list[0]; + struct hostent *he; + if (!inet_aton(host, ipaddr)) { + if ((he = gethostbyname(host)) == NULL) + return(-1); + *ipaddr = *(struct in_addr *)he->h_addr_list[0]; + } return(0); } @@ -626,22 +926,22 @@ fill_ip(ipno, mask, acp, avp) char **av = *avp; char *p = 0, md = 0; - if (ac && !strncmp(*av,"any",strlen(*av))) { + if (ac && !strncmp(*av, "any", strlen(*av))) { ipno->s_addr = mask->s_addr = 0; av++; ac--; } else { p = strchr(*av, '/'); - if (!p) + if (!p) p = strchr(*av, ':'); if (p) { md = *p; - *p++ = '\0'; + *p++ = '\0'; } if (lookup_host(*av, ipno) != 0) show_usage("hostname ``%s'' unknown", *av); switch (md) { case ':': - if (!inet_aton(p,mask)) + if (!inet_aton(p, mask)) show_usage("bad netmask ``%s''", p); break; case '/': @@ -697,29 +997,50 @@ add_port(cnt, ptr, off, port) } static int -lookup_port(const char *arg, int test, int nodash) +lookup_port(const char *arg, int proto, int test, int nodash) { int val; char *earg, buf[32]; struct servent *s; + char *p, *q; snprintf(buf, sizeof(buf), "%s", arg); - buf[strcspn(arg, nodash ? "-," : ",")] = 0; + + for (p = q = buf; *p; *q++ = *p++) { + if (*p == '\\') { + if (*(p+1)) + p++; + } else { + if (*p == ',' || (nodash && *p == '-')) + break; + } + } + *q = '\0'; + val = (int) strtoul(buf, &earg, 0); if (!*buf || *earg) { + char *protocol = NULL; + + if (proto != 0) { + struct protoent *pe = getprotobynumber(proto); + + if (pe) + protocol = pe->p_name; + } + setservent(1); - if ((s = getservbyname(buf, NULL))) { + if ((s = getservbyname(buf, protocol))) { val = htons(s->s_port); } else { if (!test) { - errx(EX_DATAERR, "unknown port ``%s''", arg); + errx(EX_DATAERR, "unknown port ``%s''", buf); } val = -1; } } else { if (val < 0 || val > 0xffff) { if (!test) { - errx(EX_DATAERR, "port ``%s'' out of range", arg); + errx(EX_DATAERR, "port ``%s'' out of range", buf); } val = -1; } @@ -727,25 +1048,43 @@ lookup_port(const char *arg, int test, int nodash) return(val); } +/* + * return: 0 normally, 1 if first pair is a range, + * 2 if first pair is a port+mask + */ static int -fill_port(cnt, ptr, off, arg) - u_short *cnt, *ptr, off; - char *arg; +fill_port(u_short *cnt, u_short *ptr, u_short off, char *arg, int proto) { char *s; int initial_range = 0; - s = arg + strcspn(arg, "-,"); /* first port name can't have a dash */ + for (s = arg; *s && *s != ',' && *s != '-' && *s != ':'; s++) { + if (*s == '\\' && *(s+1)) + s++; + } + if (*s == ':') { + *s++ = '\0'; + if (strchr(arg, ',')) + errx(EX_USAGE, "port/mask must be first in list"); + add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0x0000); + arg = s; + s = strchr(arg,','); + if (s) + *s++ = '\0'; + add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0xffff); + arg = s; + initial_range = 2; + } else if (*s == '-') { *s++ = '\0'; if (strchr(arg, ',')) errx(EX_USAGE, "port range must be first in list"); - add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0x0000); + add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0x0000); arg = s; s = strchr(arg,','); if (s) *s++ = '\0'; - add_port(cnt, ptr, off, *arg ? lookup_port(arg, 0, 0) : 0xffff); + add_port(cnt, ptr, off, *arg ? lookup_port(arg, proto, 0, 0) : 0xffff); arg = s; initial_range = 1; } @@ -753,16 +1092,14 @@ fill_port(cnt, ptr, off, arg) s = strchr(arg,','); if (s) *s++ = '\0'; - add_port(cnt, ptr, off, lookup_port(arg, 0, 0)); + add_port(cnt, ptr, off, lookup_port(arg, proto, 0, 0)); arg = s; } return initial_range; } static void -fill_tcpflag(set, reset, vp) - u_char *set, *reset; - char **vp; +fill_tcpflag(u_char *set, u_char *reset, char **vp) { char *p = *vp,*q; u_char *d; @@ -788,7 +1125,7 @@ fill_tcpflag(set, reset, vp) d = set; } q = strchr(p, ','); - if (q) + if (q) *q++ = '\0'; for (i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) if (!strncmp(p, flags[i].name, strlen(p))) { @@ -801,6 +1138,45 @@ fill_tcpflag(set, reset, vp) } } +static void +fill_tcpopts(u_char *set, u_char *reset, char **vp) +{ + char *p = *vp,*q; + u_char *d; + + while (p && *p) { + struct tpcopts { + char * name; + u_char value; + } opts[] = { + { "mss", IP_FW_TCPOPT_MSS }, + { "window", IP_FW_TCPOPT_WINDOW }, + { "sack", IP_FW_TCPOPT_SACK }, + { "ts", IP_FW_TCPOPT_TS }, + { "cc", IP_FW_TCPOPT_CC }, + }; + int i; + + if (*p == '!') { + p++; + d = reset; + } else { + d = set; + } + q = strchr(p, ','); + if (q) + *q++ = '\0'; + for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i) + if (!strncmp(p, opts[i].name, strlen(p))) { + *d |= opts[i].value; + break; + } + if (i == sizeof(opts) / sizeof(opts[0])) + show_usage("invalid tcp option ``%s''", p); + p = q; + } +} + static void fill_ipopt(u_char *set, u_char *reset, char **vp) { @@ -815,12 +1191,12 @@ fill_ipopt(u_char *set, u_char *reset, char **vp) d = set; } q = strchr(p, ','); - if (q) + if (q) *q++ = '\0'; - if (!strncmp(p,"ssrr",strlen(p))) *d |= IP_FW_IPOPT_SSRR; - if (!strncmp(p,"lsrr",strlen(p))) *d |= IP_FW_IPOPT_LSRR; - if (!strncmp(p,"rr",strlen(p))) *d |= IP_FW_IPOPT_RR; - if (!strncmp(p,"ts",strlen(p))) *d |= IP_FW_IPOPT_TS; + if (!strncmp(p, "ssrr", strlen(p))) *d |= IP_FW_IPOPT_SSRR; + if (!strncmp(p, "lsrr", strlen(p))) *d |= IP_FW_IPOPT_LSRR; + if (!strncmp(p, "rr", strlen(p))) *d |= IP_FW_IPOPT_RR; + if (!strncmp(p, "ts", strlen(p))) *d |= IP_FW_IPOPT_TS; p = q; } } @@ -837,57 +1213,75 @@ fill_icmptypes(types, vp, fw_flg) { unsigned long icmptype; - if ( *c == ',' ) + if (*c == ',') ++c; icmptype = strtoul(c, &c, 0); - if ( *c != ',' && *c != '\0' ) + if (*c != ',' && *c != '\0') show_usage("invalid ICMP type"); if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8) show_usage("ICMP type out of range"); - types[icmptype / (sizeof(unsigned) * 8)] |= + types[icmptype / (sizeof(unsigned) * 8)] |= 1 << (icmptype % (sizeof(unsigned) * 8)); *fw_flg |= IP_FW_F_ICMPBIT; } } static void -delete(ac,av) +delete(ac, av) int ac; char **av; { struct ip_fw rule; + #ifdef DUMMYNET struct dn_pipe pipe; + #endif /* DUMMYNET */ int i; int exitval = EX_OK; memset(&rule, 0, sizeof rule); + #ifdef DUMMYNET memset(&pipe, 0, sizeof pipe); + #endif /* DUMMYNET */ + rule.version = IP_FW_CURRENT_API_VERSION; av++; ac--; /* Rule number */ - while (ac && isdigit(**av)) { - if (do_pipe) { - pipe.pipe_nr = atoi(*av); av++; ac--; - i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL, - &pipe, sizeof pipe); - if (i) { - exitval = 1; - warn("rule %u: setsockopt(%s)", pipe.pipe_nr, "IP_DUMMYNET_DEL"); - } - } else { - rule.fw_number = atoi(*av); av++; ac--; - i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule); - if (i) { - exitval = EX_UNAVAILABLE; - warn("rule %u: setsockopt(%s)", rule.fw_number, "IP_FW_DEL"); + while (ac && isdigit(**av)) + { + i = atoi(*av); av++; ac--; + + #ifdef DUMMYNET + if (do_pipe) + { + if (do_pipe == 1) pipe.pipe_nr = i; + else pipe.fs.fs_nr = i; + + i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL, &pipe, sizeof pipe); + if (i) + { + exitval = 1; + warn("rule %u: setsockopt(%s)", do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr, + "IP_DUMMYNET_DEL"); + } + } + else + #endif /* DUMMYNET */ + { + rule.fw_number = i; + i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule); + if (i) + { + exitval = EX_UNAVAILABLE; + warn("rule %u: setsockopt(%s)", rule.fw_number, "IP_FW_DEL"); + } } } - } + if (exitval != EX_OK) exit(exitval); } @@ -901,7 +1295,7 @@ verify_interface(union ip_fw_if *ifu) * If a unit was specified, check for that exact interface. * If a wildcard was specified, check for unit 0. */ - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", ifu->fu_via_if.name, ifu->fu_via_if.unit == -1 ? 0 : ifu->fu_via_if.unit); @@ -937,71 +1331,278 @@ fill_iface(char *which, union ip_fw_if *ifu, int *byname, int ac, char *arg) *byname = 0; } +#ifdef DUMMYNET static void config_pipe(int ac, char **av) { struct dn_pipe pipe; - int i ; - char *end ; - + int i; + char *end; + memset(&pipe, 0, sizeof pipe); - + av++; ac--; /* Pipe number */ if (ac && isdigit(**av)) { - pipe.pipe_nr = atoi(*av); av++; ac--; + i = atoi(*av); av++; ac--; + if (do_pipe == 1) + pipe.pipe_nr = i; + else + pipe.fs.fs_nr = i; } while (ac > 1) { - if (!strncmp(*av,"bw",strlen(*av)) || - ! strncmp(*av,"bandwidth",strlen(*av))) { - pipe.bandwidth = strtoul(av[1], &end, 0); - if (*end == 'K') - end++, pipe.bandwidth *= 1000 ; - else if (*end == 'M') - end++, pipe.bandwidth *= 1000000 ; - if (*end == 'B') - pipe.bandwidth *= 8 ; - av+=2; ac-=2; - } else if (!strncmp(*av,"delay",strlen(*av)) ) { - pipe.delay = strtoul(av[1], NULL, 0); - av+=2; ac-=2; - } else if (!strncmp(*av,"plr",strlen(*av)) ) { - + if (!strncmp(*av, "plr", strlen(*av))) { + double d = strtod(av[1], NULL); - pipe.plr = (int)(d*0x7fffffff) ; + if (d > 1) + d = 1; + else if (d < 0) + d = 0; + pipe.fs.plr = (int)(d*0x7fffffff); av+=2; ac-=2; - } else if (!strncmp(*av,"queue",strlen(*av)) ) { - end = NULL ; - pipe.queue_size = strtoul(av[1], &end, 0); - if (*end == 'K') { - pipe.queue_size_bytes = pipe.queue_size*1024 ; - pipe.queue_size = 0 ; - } else if (*end == 'B') { - pipe.queue_size_bytes = pipe.queue_size ; - pipe.queue_size = 0 ; + } else if (!strncmp(*av, "queue", strlen(*av))) { + end = NULL; + pipe.fs.qsize = strtoul(av[1], &end, 0); + if (*end == 'K' || *end == 'k') { + pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES; + pipe.fs.qsize *= 1024; + } else if (*end == 'B' || !strncmp(end, "by", 2)) { + pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES; } av+=2; ac-=2; + } else if (!strncmp(*av, "buckets", strlen(*av))) { + pipe.fs.rq_size = strtoul(av[1], NULL, 0); + av+=2; ac-=2; + } else if (!strncmp(*av, "mask", strlen(*av))) { + /* per-flow queue, mask is dst_ip, dst_port, + * src_ip, src_port, proto measured in bits + */ + u_int32_t a; + u_int32_t *par = NULL; + + pipe.fs.flow_mask.dst_ip = 0; + pipe.fs.flow_mask.src_ip = 0; + pipe.fs.flow_mask.dst_port = 0; + pipe.fs.flow_mask.src_port = 0; + pipe.fs.flow_mask.proto = 0; + end = NULL; + av++; ac--; + if (ac >= 1 && !strncmp(*av, "all", strlen(*av))) { + /* special case -- all bits are significant */ + pipe.fs.flow_mask.dst_ip = ~0; + pipe.fs.flow_mask.src_ip = ~0; + pipe.fs.flow_mask.dst_port = ~0; + pipe.fs.flow_mask.src_port = ~0; + pipe.fs.flow_mask.proto = ~0; + pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; + av++; ac--; + } else { + for (;;) { + if (ac < 1) + break; + if (!strncmp(*av, "dst-ip", strlen(*av))) + par = &(pipe.fs.flow_mask.dst_ip); + else if (!strncmp(*av, "src-ip", strlen(*av))) + par = &(pipe.fs.flow_mask.src_ip); + else if (!strncmp(*av, "dst-port", strlen(*av))) + (u_int16_t *)par = &(pipe.fs.flow_mask.dst_port); + else if (!strncmp(*av, "src-port", strlen(*av))) + (u_int16_t *)par = &(pipe.fs.flow_mask.src_port); + else if (!strncmp(*av, "proto", strlen(*av))) + (u_int8_t *)par = &(pipe.fs.flow_mask.proto); + else + break; + if (ac < 2) + show_usage("mask: %s value missing", *av); + if (*av[1] == '/') { + a = strtoul(av[1]+1, &end, 0); + if (a == 32) /* special case... */ + a = ~0; + else + a = (1 << a) - 1; + fprintf(stderr, " mask is 0x%08x\n", a); + } else + a = strtoul(av[1], &end, 0); + if ((u_int16_t *)par == &(pipe.fs.flow_mask.src_port) || + (u_int16_t *)par == &(pipe.fs.flow_mask.dst_port)) { + if (a >= (1<<16)) + show_usage("mask: %s must be 16 bit, not 0x%08x", + *av, a); + *((u_int16_t *)par) = (u_int16_t) a; + } else if ((u_int8_t *)par == &(pipe.fs.flow_mask.proto)) { + if (a >= (1<<8)) + show_usage("mask: %s must be 8 bit, not 0x%08x", + *av, a); + *((u_int8_t *)par) = (u_int8_t) a; + } else + *par = a; + if (a != 0) + pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; + av += 2; ac -= 2; + } /* end for */ + } + } else if (!strncmp(*av, "red", strlen(*av)) || + !strncmp(*av, "gred", strlen(*av))) { /* RED enabled */ + pipe.fs.flags_fs |= DN_IS_RED; + if (*av[0] == 'g') + pipe.fs.flags_fs |= DN_IS_GENTLE_RED; + if ((end = strsep(&av[1],"/"))) { + double w_q = strtod(end, NULL); + if (w_q > 1 || w_q <= 0) + show_usage("w_q %f must be 0 < x <= 1", w_q); + pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED)); + } + if ((end = strsep(&av[1],"/"))) { + pipe.fs.min_th = strtoul(end, &end, 0); + if (*end == 'K' || *end == 'k') + pipe.fs.min_th *= 1024; + } + if ((end = strsep(&av[1],"/"))) { + pipe.fs.max_th = strtoul(end, &end, 0); + if (*end == 'K' || *end == 'k') + pipe.fs.max_th *= 1024; + } + if ((end = strsep(&av[1],"/"))) { + double max_p = strtod(end, NULL); + if (max_p > 1 || max_p <= 0) + show_usage("max_p %f must be 0 < x <= 1", max_p); + pipe.fs.max_p = (int) (max_p * (1 << SCALE_RED)); + } + av+=2; ac-=2; + } else if (!strncmp(*av, "droptail", strlen(*av))) { /* DROPTAIL */ + pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); + av+=1; ac-=1; + } else { + if (do_pipe == 1) { + /* some commands are only good for pipes. */ + if (!strncmp(*av, "bw", strlen(*av)) || + ! strncmp(*av, "bandwidth", strlen(*av))) { + if (av[1][0] >= 'a' && av[1][0] <= 'z') { + int l = sizeof(pipe.if_name)-1; + /* interface name */ + strncpy(pipe.if_name, av[1], l); + pipe.if_name[l] = '\0'; + pipe.bandwidth = 0; + } else { + pipe.if_name[0] = '\0'; + pipe.bandwidth = strtoul(av[1], &end, 0); + if (*end == 'K' || *end == 'k') + end++, pipe.bandwidth *= 1000; + else if (*end == 'M') + end++, pipe.bandwidth *= 1000000; + if (*end == 'B' || !strncmp(end, "by", 2)) + pipe.bandwidth *= 8; + } + av+=2; ac-=2; + } else if (!strncmp(*av, "delay", strlen(*av))) { + pipe.delay = strtoul(av[1], NULL, 0); + av+=2; ac-=2; + } else + show_usage("unrecognised pipe option ``%s''", *av); + } else { /* this refers to a queue */ + if (!strncmp(*av, "weight", strlen(*av))) { + pipe.fs.weight = strtoul(av[1], &end, 0); + av += 2; + ac -= 2; + } else if (!strncmp(*av, "pipe", strlen(*av))) { + pipe.fs.parent_nr = strtoul(av[1], &end, 0); + av += 2; + ac -= 2; } else show_usage("unrecognised option ``%s''", *av); } - if (pipe.pipe_nr == 0 ) - show_usage("pipe_nr %d be > 0", pipe.pipe_nr); - if (pipe.queue_size > 100 ) - show_usage("queue size %d must be 2 <= x <= 100", pipe.queue_size); - if (pipe.delay > 10000 ) + } + } + if (do_pipe == 1) { + if (pipe.pipe_nr == 0) + show_usage("pipe_nr %d must be > 0", pipe.pipe_nr); + if (pipe.delay > 10000) show_usage("delay %d must be < 10000", pipe.delay); + } else { /* do_pipe == 2, queue */ + if (pipe.fs.parent_nr == 0) + show_usage("pipe %d must be > 0", pipe.fs.parent_nr); + if (pipe.fs.weight >100) + show_usage("weight %d must be <= 100", pipe.fs.weight); + } + if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) { + if (pipe.fs.qsize > 1024*1024) + show_usage("queue size %d, must be < 1MB", + pipe.fs.qsize); + } else { + if (pipe.fs.qsize > 100) + show_usage("queue size %d, must be 2 <= x <= 100", + pipe.fs.qsize); + } + if (pipe.fs.flags_fs & DN_IS_RED) { + if (pipe.fs.min_th >= pipe.fs.max_th) + show_usage("min_th %d must be < than max_th %d", + pipe.fs.min_th, pipe.fs.max_th); + if (pipe.fs.max_th == 0) + show_usage("max_th must be > 0"); + if (pipe.bandwidth) { + size_t len; + int lookup_depth, avg_pkt_size; + double s, idle, weight, w_q; + struct clockinfo clock; + int t; + + len = sizeof(int); + if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", + &lookup_depth, &len, NULL, 0) == -1) + + errx(1, "sysctlbyname(\"%s\")", + "net.inet.ip.dummynet.red_lookup_depth"); + if (lookup_depth == 0) + show_usage("net.inet.ip.dummynet.red_lookup_depth must" + "greater than zero"); + + len = sizeof(int); + if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", + &avg_pkt_size, &len, NULL, 0) == -1) + + errx(1, "sysctlbyname(\"%s\")", + "net.inet.ip.dummynet.red_avg_pkt_size"); + if (avg_pkt_size == 0) + show_usage("net.inet.ip.dummynet.red_avg_pkt_size must" + "greater than zero"); + + len = sizeof(struct clockinfo); + if (sysctlbyname("kern.clockrate", + &clock, &len, NULL, 0) == -1) + errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); + + /* ticks needed for sending a medium-sized packet */ + s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth; + + /* + * max idle time (in ticks) before avg queue size becomes 0. + * NOTA: (3/w_q) is approx the value x so that + * (1-w_q)^x < 10^-3. + */ + w_q = ((double) pipe.fs.w_q) / (1 << SCALE_RED); + idle = s * 3. / w_q; + pipe.fs.lookup_step = (int) idle / lookup_depth; + if (!pipe.fs.lookup_step) + pipe.fs.lookup_step = 1; + weight = 1 - w_q; + for (t = pipe.fs.lookup_step; t > 0; --t) + weight *= weight; + pipe.fs.lookup_weight = (int) (weight * (1 << SCALE_RED)); + } + } #if 0 printf("configuring pipe %d bw %d delay %d size %d\n", pipe.pipe_nr, pipe.bandwidth, pipe.delay, pipe.queue_size); #endif - i = setsockopt(s,IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe,sizeof pipe); + i = setsockopt(s,IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe); if (i) err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); - + } +#endif /* DUMMYNET */ static void -add(ac,av) +add(ac, av) int ac; char **av; { @@ -1010,8 +1611,9 @@ add(ac,av) u_char proto; struct protoent *pe; int saw_xmrc = 0, saw_via = 0; - + memset(&rule, 0, sizeof rule); + rule.version = IP_FW_CURRENT_API_VERSION; av++; ac--; @@ -1021,21 +1623,42 @@ add(ac,av) } /* Action */ + if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { + double d = strtod(av[1], NULL); + if (d <= 0 || d > 1) + show_usage("illegal match prob. %s", av[1]); + if (d != 1) { /* 1 means always match */ + rule.fw_flg |= IP_FW_F_RND_MATCH; + /* we really store dont_match probability */ + (long)rule.pipe_ptr = (long)((1 - d) * 0x7fffffff); + } + av += 2; ac -= 2; + } + if (ac == 0) show_usage("missing action"); - if (!strncmp(*av,"accept",strlen(*av)) - || !strncmp(*av,"pass",strlen(*av)) - || !strncmp(*av,"allow",strlen(*av)) - || !strncmp(*av,"permit",strlen(*av))) { + if (!strncmp(*av, "accept", strlen(*av)) + || !strncmp(*av, "pass" ,strlen(*av)) + || !strncmp(*av, "allow", strlen(*av)) + || !strncmp(*av, "permit", strlen(*av))) { rule.fw_flg |= IP_FW_F_ACCEPT; av++; ac--; - } else if (!strncmp(*av,"count",strlen(*av))) { + } else if (!strncmp(*av, "count", strlen(*av))) { rule.fw_flg |= IP_FW_F_COUNT; av++; ac--; - } else if (!strncmp(*av,"pipe",strlen(*av))) { + } + #ifdef DUMMYNET + else if (!strncmp(*av, "pipe", strlen(*av))) { rule.fw_flg |= IP_FW_F_PIPE; av++; ac--; if (!ac) show_usage("missing pipe number"); rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--; - } else if (!strncmp(*av,"divert",strlen(*av))) { + } else if (!strncmp(*av, "queue", strlen(*av))) { + rule.fw_flg |= IP_FW_F_QUEUE; av++; ac--; + if (!ac) + show_usage("missing queue number"); + rule.fw_divert_port = strtoul(*av, NULL, 0); av++; ac--; + } + #endif /* DUMMYNET */ + else if (!strncmp(*av, "divert", strlen(*av))) { rule.fw_flg |= IP_FW_F_DIVERT; av++; ac--; if (!ac) show_usage("missing %s port", "divert"); @@ -1049,7 +1672,7 @@ add(ac,av) else show_usage("illegal %s port", "divert"); } - } else if (!strncmp(*av,"tee",strlen(*av))) { + } else if (!strncmp(*av, "tee", strlen(*av))) { rule.fw_flg |= IP_FW_F_TEE; av++; ac--; if (!ac) show_usage("missing %s port", "tee divert"); @@ -1063,11 +1686,8 @@ add(ac,av) else show_usage("illegal %s port", "tee divert"); } -#ifndef IPFW_TEE_IS_FINALLY_IMPLEMENTED - err(EX_USAGE, "the ``tee'' action is not implemented"); -#endif - } else if (!strncmp(*av,"fwd",strlen(*av)) || - !strncmp(*av,"forward",strlen(*av))) { + } else if (!strncmp(*av, "fwd", strlen(*av)) || + !strncmp(*av, "forward", strlen(*av))) { struct in_addr dummyip; char *pp; rule.fw_flg |= IP_FW_F_FWD; av++; ac--; @@ -1082,46 +1702,64 @@ add(ac,av) if(pp != NULL) { *(pp++) = '\0'; - rule.fw_fwd_ip.sin_port = lookup_port(pp, 1, 1); - if(rule.fw_fwd_ip.sin_port == (unsigned int)-1) - show_usage("illegal forwarding port"); + i = lookup_port(pp, 0, 1, 0); + if (i == -1) + show_usage("illegal forwarding port ``%s''", pp); + else + rule.fw_fwd_ip.sin_port = (u_short)i; } fill_ip(&(rule.fw_fwd_ip.sin_addr), &dummyip, &ac, &av); if (rule.fw_fwd_ip.sin_addr.s_addr == 0) show_usage("illegal forwarding IP address"); - } else if (!strncmp(*av,"skipto",strlen(*av))) { + } else if (!strncmp(*av, "skipto", strlen(*av))) { rule.fw_flg |= IP_FW_F_SKIPTO; av++; ac--; if (!ac) show_usage("missing skipto rule number"); rule.fw_skipto_rule = strtoul(*av, NULL, 0); av++; ac--; - } else if ((!strncmp(*av,"deny",strlen(*av)) - || !strncmp(*av,"drop",strlen(*av)))) { + } else if ((!strncmp(*av, "deny", strlen(*av)) + || !strncmp(*av, "drop", strlen(*av)))) { rule.fw_flg |= IP_FW_F_DENY; av++; ac--; - } else if (!strncmp(*av,"reject",strlen(*av))) { + } else if (!strncmp(*av, "reject", strlen(*av))) { rule.fw_flg |= IP_FW_F_REJECT; av++; ac--; rule.fw_reject_code = ICMP_UNREACH_HOST; - } else if (!strncmp(*av,"reset",strlen(*av))) { + } else if (!strncmp(*av, "reset", strlen(*av))) { rule.fw_flg |= IP_FW_F_REJECT; av++; ac--; rule.fw_reject_code = IP_FW_REJECT_RST; /* check TCP later */ - } else if (!strncmp(*av,"unreach",strlen(*av))) { + } else if (!strncmp(*av, "unreach", strlen(*av))) { rule.fw_flg |= IP_FW_F_REJECT; av++; ac--; fill_reject_code(&rule.fw_reject_code, *av); av++; ac--; + } else if (!strncmp(*av, "check-state", strlen(*av))) { + rule.fw_flg |= IP_FW_F_CHECK_S; av++; ac--; + goto done; } else { show_usage("invalid action ``%s''", *av); } /* [log] */ - if (ac && !strncmp(*av,"log",strlen(*av))) { + if (ac && !strncmp(*av, "log", strlen(*av))) { rule.fw_flg |= IP_FW_F_PRN; av++; ac--; } + if (ac && !strncmp(*av, "logamount", strlen(*av))) { + if (!(rule.fw_flg & IP_FW_F_PRN)) + show_usage("``logamount'' not valid without ``log''"); + ac--; av++; + if (!ac) + show_usage("``logamount'' requires argument"); + rule.fw_logamount = atoi(*av); + if (rule.fw_logamount < 0) + show_usage("``logamount'' argument must be positive"); + if (rule.fw_logamount == 0) + rule.fw_logamount = -1; + ac--; av++; + } /* protocol */ if (ac == 0) show_usage("missing protocol"); if ((proto = atoi(*av)) > 0) { rule.fw_prot = proto; av++; ac--; - } else if (!strncmp(*av,"all",strlen(*av))) { + } else if (!strncmp(*av, "all", strlen(*av))) { rule.fw_prot = IPPROTO_IP; av++; ac--; } else if ((pe = getprotobyname(*av)) != NULL) { rule.fw_prot = pe->p_proto; av++; ac--; @@ -1135,48 +1773,66 @@ add(ac,av) show_usage("``reset'' is only valid for tcp packets"); /* from */ - if (ac && !strncmp(*av,"from",strlen(*av))) { av++; ac--; } + if (ac && !strncmp(*av, "from", strlen(*av))) { av++; ac--; } else show_usage("missing ``from''"); - if (ac && !strncmp(*av,"not",strlen(*av))) { + if (ac && !strncmp(*av, "not", strlen(*av))) { rule.fw_flg |= IP_FW_F_INVSRC; av++; ac--; } if (!ac) show_usage("missing arguments"); - fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av); + if (ac && !strncmp(*av, "me", strlen(*av))) { + rule.fw_flg |= IP_FW_F_SME; + av++; ac--; + } else { + fill_ip(&rule.fw_src, &rule.fw_smsk, &ac, &av); + } - if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) { + if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) { u_short nports = 0; + int retval; - if (fill_port(&nports, rule.fw_uar.fw_pts, 0, *av)) + retval = fill_port(&nports, rule.fw_uar.fw_pts, 0, *av, rule.fw_prot); + if (retval == 1) rule.fw_flg |= IP_FW_F_SRNG; + else if (retval == 2) + rule.fw_flg |= IP_FW_F_SMSK; IP_FW_SETNSRCP(&rule, nports); av++; ac--; } /* to */ - if (ac && !strncmp(*av,"to",strlen(*av))) { av++; ac--; } + if (ac && !strncmp(*av, "to", strlen(*av))) { av++; ac--; } else show_usage("missing ``to''"); - if (ac && !strncmp(*av,"not",strlen(*av))) { + if (ac && !strncmp(*av, "not", strlen(*av))) { rule.fw_flg |= IP_FW_F_INVDST; av++; ac--; } if (!ac) show_usage("missing arguments"); - fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av); + if (ac && !strncmp(*av, "me", strlen(*av))) { + rule.fw_flg |= IP_FW_F_DME; + av++; ac--; + } else { + fill_ip(&rule.fw_dst, &rule.fw_dmsk, &ac, &av); + } - if (ac && (isdigit(**av) || lookup_port(*av, 1, 1) >= 0)) { + if (ac && (isdigit(**av) || lookup_port(*av, rule.fw_prot, 1, 1) >= 0)) { u_short nports = 0; + int retval; - if (fill_port(&nports, - rule.fw_uar.fw_pts, IP_FW_GETNSRCP(&rule), *av)) + retval = fill_port(&nports, + rule.fw_uar.fw_pts, IP_FW_GETNSRCP(&rule), *av, rule.fw_prot); + if (retval == 1) rule.fw_flg |= IP_FW_F_DRNG; + else if (retval == 2) + rule.fw_flg |= IP_FW_F_DMSK; IP_FW_SETNDSTP(&rule, nports); av++; ac--; } @@ -1188,15 +1844,51 @@ add(ac,av) } while (ac) { - if (!strncmp(*av,"in",strlen(*av))) { + if (!strncmp(*av, "uid", strlen(*av))) { + struct passwd *pwd; + char *end; + uid_t uid; + + rule.fw_flg |= IP_FW_F_UID; + ac--; av++; + if (!ac) + show_usage("``uid'' requires argument"); + + uid = strtoul(*av, &end, 0); + if (*end == '\0') + pwd = getpwuid(uid); + else + pwd = getpwnam(*av); + if (pwd == NULL) + show_usage("uid \"%s\" is nonexistant", *av); + rule.fw_uid = pwd->pw_uid; + ac--; av++; + continue; + } + if (!strncmp(*av, "in", strlen(*av))) { rule.fw_flg |= IP_FW_F_IN; av++; ac--; continue; } - if (!strncmp(*av,"out",strlen(*av))) { + if (!strncmp(*av, "keep-state", strlen(*av))) { + u_long type; + rule.fw_flg |= IP_FW_F_KEEP_S; + + av++; ac--; + if (ac > 0 && (type = atoi(*av)) != 0) { + (int)rule.next_rule_ptr = type; + av++; ac--; + } + continue; + } + if (!strncmp(*av, "bridged", strlen(*av))) { + rule.fw_flg |= IP_FW_BRIDGED; + av++; ac--; continue; + } + if (!strncmp(*av, "out", strlen(*av))) { rule.fw_flg |= IP_FW_F_OUT; av++; ac--; continue; } - if (ac && !strncmp(*av,"xmit",strlen(*av))) { + if (ac && !strncmp(*av, "xmit", strlen(*av))) { union ip_fw_if ifu; int byname; @@ -1206,7 +1898,7 @@ badviacombo: " with ``xmit'' and ``recv''"); } saw_xmrc = 1; - av++; ac--; + av++; ac--; fill_iface("xmit", &ifu, &byname, ac, *av); rule.fw_out_if = ifu; rule.fw_flg |= IP_FW_F_OIFACE; @@ -1214,14 +1906,14 @@ badviacombo: rule.fw_flg |= IP_FW_F_OIFNAME; av++; ac--; continue; } - if (ac && !strncmp(*av,"recv",strlen(*av))) { + if (ac && !strncmp(*av, "recv", strlen(*av))) { union ip_fw_if ifu; int byname; if (saw_via) goto badviacombo; saw_xmrc = 1; - av++; ac--; + av++; ac--; fill_iface("recv", &ifu, &byname, ac, *av); rule.fw_in_if = ifu; rule.fw_flg |= IP_FW_F_IIFACE; @@ -1229,14 +1921,14 @@ badviacombo: rule.fw_flg |= IP_FW_F_IIFNAME; av++; ac--; continue; } - if (ac && !strncmp(*av,"via",strlen(*av))) { + if (ac && !strncmp(*av, "via", strlen(*av))) { union ip_fw_if ifu; int byname = 0; if (saw_xmrc) goto badviacombo; saw_via = 1; - av++; ac--; + av++; ac--; fill_iface("via", &ifu, &byname, ac, *av); rule.fw_out_if = rule.fw_in_if = ifu; if (byname) @@ -1244,12 +1936,12 @@ badviacombo: (IP_FW_F_IIFNAME | IP_FW_F_OIFNAME); av++; ac--; continue; } - if (!strncmp(*av,"fragment",strlen(*av))) { + if (!strncmp(*av, "fragment", strlen(*av))) { rule.fw_flg |= IP_FW_F_FRAG; av++; ac--; continue; } - if (!strncmp(*av,"ipoptions",strlen(*av))) { - av++; ac--; + if (!strncmp(*av, "ipoptions", strlen(*av))) { + av++; ac--; if (!ac) show_usage("missing argument" " for ``ipoptions''"); @@ -1257,26 +1949,36 @@ badviacombo: av++; ac--; continue; } if (rule.fw_prot == IPPROTO_TCP) { - if (!strncmp(*av,"established",strlen(*av))) { - rule.fw_tcpf |= IP_FW_TCPF_ESTAB; + if (!strncmp(*av, "established", strlen(*av))) { + rule.fw_ipflg |= IP_FW_IF_TCPEST; av++; ac--; continue; } - if (!strncmp(*av,"setup",strlen(*av))) { + if (!strncmp(*av, "setup", strlen(*av))) { rule.fw_tcpf |= IP_FW_TCPF_SYN; rule.fw_tcpnf |= IP_FW_TCPF_ACK; av++; ac--; continue; } - if (!strncmp(*av,"tcpflags",strlen(*av))) { - av++; ac--; + if (!strncmp(*av, "tcpflags", strlen(*av)) || + !strncmp(*av, "tcpflgs", strlen(*av))) { + av++; ac--; if (!ac) show_usage("missing argument" " for ``tcpflags''"); fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av); av++; ac--; continue; } + if (!strncmp(*av, "tcpoptions", strlen(*av)) || + !strncmp(*av, "tcpopts", strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing argument" + " for ``tcpoptions''"); + fill_tcpopts(&rule.fw_tcpopt, &rule.fw_tcpnopt, av); + av++; ac--; continue; + } } if (rule.fw_prot == IPPROTO_ICMP) { - if (!strncmp(*av,"icmptypes",strlen(*av))) { + if (!strncmp(*av, "icmptypes", strlen(*av))) { av++; ac--; if (!ac) show_usage("missing argument" @@ -1310,12 +2012,24 @@ badviacombo: if (rule.fw_nports) show_usage("can't mix 'frag' and port specifications"); } - + if (rule.fw_flg & IP_FW_F_PRN) { + if (!rule.fw_logamount) { + size_t len = sizeof(int); + + if (sysctlbyname("net.inet.ip.fw.verbose_limit", + &rule.fw_logamount, &len, NULL, 0) == -1) + errx(1, "sysctlbyname(\"%s\")", + "net.inet.ip.fw.verbose_limit"); + } else if (rule.fw_logamount == -1) + rule.fw_logamount = 0; + rule.fw_loghighest = rule.fw_logamount; + } +done: + i = sizeof(rule); + if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, &i) == -1) + err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); if (!do_quiet) show_ipfw(&rule, 10, 10); - i = setsockopt(s, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); - if (i) - err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ADD"); } static void @@ -1323,19 +2037,21 @@ zero (ac, av) int ac; char **av; { + struct ip_fw rule; + memset(&rule, 0, sizeof rule); + rule.version = IP_FW_CURRENT_API_VERSION; + av++; ac--; if (!ac) { /* clear all entries */ - if (setsockopt(s,IPPROTO_IP,IP_FW_ZERO,NULL,0)<0) + if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, &rule, sizeof rule) < 0) err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO"); if (!do_quiet) printf("Accounting cleared.\n"); } else { - struct ip_fw rule; int failed = EX_OK; - memset(&rule, 0, sizeof rule); while (ac) { /* Rule number */ if (isdigit(**av)) { @@ -1357,16 +2073,56 @@ zero (ac, av) } } +static void +resetlog (ac, av) + int ac; + char **av; +{ + struct ip_fw rule; + memset(&rule, 0, sizeof rule); + rule.version = IP_FW_CURRENT_API_VERSION; + + av++; ac--; + + if (!ac) { + /* clear all entries */ + if (setsockopt(s, IPPROTO_IP, IP_FW_RESETLOG, &rule, sizeof rule) < 0) + err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_RESETLOG"); + if (!do_quiet) + printf("Logging counts reset.\n"); + } else { + int failed = EX_OK; + + while (ac) { + /* Rule number */ + if (isdigit(**av)) { + rule.fw_number = atoi(*av); av++; ac--; + if (setsockopt(s, IPPROTO_IP, + IP_FW_RESETLOG, &rule, sizeof rule)) { + warn("rule %u: setsockopt(%s)", rule.fw_number, + "IP_FW_RESETLOG"); + failed = EX_UNAVAILABLE; + } + else if (!do_quiet) + printf("Entry %d logging count reset\n", + rule.fw_number); + } else + show_usage("invalid rule number ``%s''", *av); + } + if (failed != EX_OK) + exit(failed); + } +} + static int -ipfw_main(ac,av) +ipfw_main(ac, av) int ac; char **av; { int ch; - extern int optreset; /* XXX should be declared in */ - if ( ac == 1 ) { + if (ac == 1) { show_usage(NULL); } @@ -1374,22 +2130,28 @@ ipfw_main(ac,av) do_force = !isatty(STDIN_FILENO); optind = optreset = 1; - while ((ch = getopt(ac, av, "afqtN")) != -1) + while ((ch = getopt(ac, av, "s:afqtvN")) != -1) switch(ch) { + case 's': /* sort */ + do_sort= atoi(optarg); + break; case 'a': - do_acct=1; + do_acct = 1; break; case 'f': - do_force=1; + do_force = 1; break; case 'q': - do_quiet=1; + do_quiet = 1; break; case 't': - do_time=1; + do_time = 1; + break; + case 'v': /* verbose */ + verbose++; break; case 'N': - do_resolv=1; + do_resolv = 1; break; default: show_usage(NULL); @@ -1397,72 +2159,111 @@ ipfw_main(ac,av) ac -= optind; if (*(av+=optind)==NULL) { - show_usage("Bad arguments"); + show_usage("bad arguments"); } - if (!strncmp(*av, "pipe", strlen(*av))) { - do_pipe = 1 ; - ac-- ; - av++ ; - } + #ifdef DUMMYNET + if (!strncmp(*av, "pipe", strlen(*av))) { + do_pipe = 1; + ac--; + av++; + } else if (!strncmp(*av, "queue", strlen(*av))) { + do_pipe = 2; + ac--; + av++; + } if (!ac) { show_usage("pipe requires arguments"); } - /* allow argument swapping */ - if (ac > 1 && *av[0]>='0' && *av[0]<='9') { - char *p = av[0] ; - av[0] = av[1] ; - av[1] = p ; - } + #endif /* DUMMYNET */ + + /* allow argument swapping */ + if (ac > 1 && *av[0] >= '0' && *av[0] <= '9') { + char *p = av[0]; + av[0] = av[1]; + av[1] = p; + } if (!strncmp(*av, "add", strlen(*av))) { - add(ac,av); - } else if (do_pipe && !strncmp(*av, "config", strlen(*av))) { - config_pipe(ac,av); - } else if (!strncmp(*av, "delete", strlen(*av))) { - delete(ac,av); + add(ac, av); + } + #ifdef DUMMYNET + else if (do_pipe && !strncmp(*av, "config", strlen(*av))) { + config_pipe(ac, av); + } + #endif /* DUMMYNET */ + else if (!strncmp(*av, "delete", strlen(*av))) { + delete(ac, av); } else if (!strncmp(*av, "flush", strlen(*av))) { int do_flush = 0; - if ( do_force || do_quiet ) + if (do_force || do_quiet) do_flush = 1; else { int c; /* Ask the user */ printf("Are you sure? [yn] "); + fflush(stdout); do { - fflush(stdout); c = toupper(getc(stdin)); while (c != '\n' && getc(stdin) != '\n') if (feof(stdin)) return (0); } while (c != 'Y' && c != 'N'); printf("\n"); - if (c == 'Y') + if (c == 'Y') do_flush = 1; } - if ( do_flush ) { - if (setsockopt(s,IPPROTO_IP,IP_FW_FLUSH,NULL,0) < 0) - err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_FLUSH"); + if (do_flush) { + int error = 0; + + #ifdef DUMMYNET + if (do_pipe) + { + error = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_FLUSH, NULL, 0); + } + else + #endif /* DUMMYNET */ + { + struct ip_fw rule; + memset(&rule, 0, sizeof rule); + rule.version = IP_FW_CURRENT_API_VERSION; + error = setsockopt(s, IPPROTO_IP, IP_FW_FLUSH, &rule, sizeof rule); + } + + if (error < 0) + #ifdef DUMMYNET + err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", + do_pipe ? "DUMMYNET" : "FW"); + #else /* DUMMYNET */ + err(EX_UNAVAILABLE, "setsockopt(IP_FW_FLUSH)"); + #endif /* DUMMYNET */ if (!do_quiet) + #ifdef DUMMYNET + printf("Flushed all %s.\n", + do_pipe ? "pipes" : "rules"); + #else /* DUMMYNET */ printf("Flushed all rules.\n"); + #endif /* DUMMYNET */ } } else if (!strncmp(*av, "zero", strlen(*av))) { - zero(ac,av); + zero(ac, av); + } else if (!strncmp(*av, "resetlog", strlen(*av))) { + resetlog(ac, av); } else if (!strncmp(*av, "print", strlen(*av))) { - list(--ac,++av); + list(--ac, ++av); } else if (!strncmp(*av, "list", strlen(*av))) { - list(--ac,++av); + list(--ac, ++av); } else if (!strncmp(*av, "show", strlen(*av))) { do_acct++; - list(--ac,++av); + list(--ac, ++av); } else { - show_usage("Bad arguments"); + show_usage("bad arguments"); } return 0; } -int +int main(ac, av) int ac; char **av; @@ -1472,17 +2273,23 @@ main(ac, av) char buf[BUFSIZ]; char *a, *p, *args[MAX_ARGS], *cmd = NULL; char linename[10]; - int i, c, qflag, pflag, status; + int i, c, lineno, qflag, pflag, status; FILE *f = NULL; pid_t preproc = 0; - s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW ); - if ( s < 0 ) + s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + if (s < 0) err(EX_UNAVAILABLE, "socket"); - setbuf(stdout,0); + setbuf(stdout, 0); - if (ac > 1 && access(av[ac - 1], R_OK) == 0) { + /* + * this is a nasty check on the last argument!!! + * If there happens to be a filename matching a keyword in the current + * directory, things will fail miserably. + */ + + if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) { qflag = pflag = i = 0; lineno = 0; @@ -1546,8 +2353,8 @@ main(ac, av) case 0: /* child */ - if (dup2(fileno(f), 0) == -1 || - dup2(pipedes[1], 1) == -1) + if (dup2(fileno(f), 0) == -1 + || dup2(pipedes[1], 1) == -1) err(EX_OSERR, "dup2()"); fclose(f); close(pipedes[1]); @@ -1578,36 +2385,36 @@ main(ac, av) continue; if ((p = strchr(buf, '#')) != NULL) *p = '\0'; - i=1; - if (qflag) args[i++]="-q"; + i = 1; + if (qflag) + args[i++] = "-q"; for (a = strtok(buf, WHITESP); a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++) args[i] = a; if (i == (qflag? 2: 1)) continue; if (i == MAX_ARGS) - errx(EX_USAGE, "%s: too many arguments", linename); + errx(EX_USAGE, "%s: too many arguments", + linename); args[i] = NULL; - ipfw_main(i, args); + ipfw_main(i, args); } fclose(f); if (pflag) { - if (waitpid(preproc, &status, 0) != -1) { - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) != EX_OK) - errx(EX_UNAVAILABLE, - "preprocessor exited with status %d", - WEXITSTATUS(status)); - } else if (WIFSIGNALED(status)) { - errx(EX_UNAVAILABLE, - "preprocessor exited with signal %d", - WTERMSIG(status)); - } - } + if (waitpid(preproc, &status, 0) == -1) + errx(EX_OSERR, "waitpid()"); + if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) + errx(EX_UNAVAILABLE, + "preprocessor exited with status %d", + WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + errx(EX_UNAVAILABLE, + "preprocessor exited with signal %d", + WTERMSIG(status)); } - - } else - ipfw_main(ac,av); + } else { + ipfw_main(ac, av); + } return EX_OK; } diff --git a/ipsec/Makefile b/ipsec/Makefile new file mode 100644 index 0000000..5bb77a0 --- /dev/null +++ b/ipsec/Makefile @@ -0,0 +1,61 @@ +# +# Generated by the Apple Project Builder. +# +# NOTE: Do NOT change this file -- Project Builder maintains it. +# +# Put all of your customizations in files called Makefile.preamble +# and Makefile.postamble (both optional), and Makefile will include them. +# + +NAME = ipsec + +PROJECTVERSION = 2.8 +PROJECT_TYPE = Library + +HFILES = ipsec_strerror.h libpfkey.h key_debug.h + +OTHERLINKED = policy_parse.y policy_token.l + +CFILES = ipsec_dump_policy.c ipsec_get_policylen.c ipsec_strerror.c + +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble\ + ipsec_set_policy.3 ipsec_strerror.3 + +OTHERLINKEDOFILES = policy_parse.o policy_token.o + +MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles +CURRENTLY_ACTIVE_VERSION = YES +DEPLOY_WITH_VERSION_NAME = A +CODE_GEN_STYLE = DYNAMIC +MAKEFILE = library.make +NEXTSTEP_INSTALLDIR = /usr/lib +WINDOWS_INSTALLDIR = /Developer/Libraries +PDO_UNIX_INSTALLDIR = /lib +LIBS = +DEBUG_LIBS = $(LIBS) +PROF_LIBS = $(LIBS) + + + +NEXTSTEP_PUBLIC_HEADERS_DIR = /Developer/Headers/$(NAME) + +WINDOWS_PUBLIC_HEADERS_DIR = /Developer/Headers/$(NAME) + +PDO_UNIX_PUBLIC_HEADERS_DIR = /Developer/Headers/$(NAME) + +NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc +WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc +PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc +NEXTSTEP_JAVA_COMPILER = /usr/bin/javac +WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe +PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac + +include $(MAKEFILEDIR)/platform.make + +-include Makefile.preamble + +include $(MAKEFILEDIR)/$(MAKEFILE) + +-include Makefile.postamble + +-include Makefile.dependencies diff --git a/ipsec/Makefile.postamble b/ipsec/Makefile.postamble new file mode 100644 index 0000000..1fc2bf3 --- /dev/null +++ b/ipsec/Makefile.postamble @@ -0,0 +1,104 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGES: langages in which the project is written (default "English") +# English_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man3" + install -c -m 644 ipsec_set_policy.3 "$(DSTROOT)/usr/share/man/man3/ipsec_set_policy.3" + install -c -m 644 ipsec_strerror.3 "$(DSTROOT)/usr/share/man/man3/ipsec_strerror.3" diff --git a/ipsec/Makefile.preamble b/ipsec/Makefile.preamble new file mode 100644 index 0000000..87c2727 --- /dev/null +++ b/ipsec/Makefile.preamble @@ -0,0 +1,141 @@ +############################################################################### +# Makefile.preamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile for configuring the standard application makefiles +# associated with ProjectBuilder. It is included before the main makefile. +# In Makefile.preamble you set attributes for a project, so they are available +# to the project's makefiles. In contrast, you typically write additional rules or +# override built-in behavior in the Makefile.postamble. +# +# Each directory in a project tree (main project plus subprojects) should +# have its own Makefile.preamble and Makefile.postamble. +############################################################################### +# +# Before the main makefile is included for this project, you may set: +# +# MAKEFILEDIR: Directory in which to find $(MAKEFILE) +# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make) + +# Compiler/linker flags added to the defaults: The OTHER_* variables will be +# inherited by all nested sub-projects, but the LOCAL_ versions of the same +# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's +# Build Attributes inspector if at all possible. To override the default flags +# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The +# variables below are *inputs* to the build process and distinct from the override +# settings done (less often) in the Makefile.postamble. +# +# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler +# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m, +# .cc, .cxx, .C, and .M files. There is no need to respecify the +# flags in OTHER_MFLAGS, etc. +# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files +# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files +# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files +# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when +# precompiling header files +# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool +# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap +# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen +# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc +# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex +LOCAL_CFLAGS=-g -DIPSEC_DEBUG -DIPSEC -DINET6 +LOCAL_YFLAGS=-d -p __libipsecyy +LOCAL_LFLAGS=-P__libipsecyy -olex.yy.c + +# These variables provide hooks enabling you to add behavior at almost every +# stage of the make: +# +# BEFORE_PREBUILD: targets to build before installing headers for a subproject +# AFTER_PREBUILD: targets to build after installing headers for a subproject +# BEFORE_BUILD_RECURSION: targets to make before building subprojects +# BEFORE_BUILD: targets to make before a build, but after subprojects +# AFTER_BUILD: targets to make after a build +# +# BEFORE_INSTALL: targets to build before installing the product +# AFTER_INSTALL: targets to build after installing the product +# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject +# AFTER_POSTINSTALL: targts to build after postinstalling every subproject +# +# BEFORE_INSTALLHDRS: targets to build before installing headers for a +# subproject +# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject +# BEFORE_INSTALLSRC: targets to build before installing source for a subproject +# AFTER_INSTALLSRC: targets to build after installing source for a subproject +# +# BEFORE_DEPEND: targets to build before building dependencies for a +# subproject +# AFTER_DEPEND: targets to build after building dependencies for a +# subproject +# +# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is +# updated every time the project is built. If NO, the dependency +# file is only built when the depend target is invoked. +AFTER_INSTALL += install-man-page + +# Framework-related variables: +# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the framework's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables + +# Library-related variables: +# PUBLIC_HEADER_DIR: Determines where public exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. For library projects you should +# set this to something like /Developer/Headers/$(NAME). Do not set +# this variable for framework projects unless you do not want the +# header files included in the framework. +# PRIVATE_HEADER_DIR: Determines where private exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. +# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines +# whether the libraries produced are statically linked when they +# are used or if they are dynamically loadable. This defaults to +# DYNAMIC. +# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the library's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables +# +# INSTALL_AS_USER: owner of the intalled products (default root) +# INSTALL_AS_GROUP: group of the installed products (default wheel) +# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX) +# +# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be +# passed on the command line to recursive invocations of make. Note that +# the values in OTHER_*FLAGS are inherited by subprojects automatically -- +# you do not have to (and shouldn't) add OTHER_*FLAGS to +# OTHER_RECURSIVE_VARIABLES. + +# Additional headers to export beyond those in the PB.project: +# OTHER_PUBLIC_HEADERS +# OTHER_PROJECT_HEADERS +# OTHER_PRIVATE_HEADERS + +# Additional files for the project's product: <> +# OTHER_RESOURCES: (non-localized) resources for this project +# OTHER_OFILES: relocatables to be linked into this project +# OTHER_LIBS: more libraries to link against +# OTHER_PRODUCT_DEPENDS: other dependencies of this project +# OTHER_SOURCEFILES: other source files maintained by .pre/postamble +# OTHER_GARBAGE: additional files to be removed by `make clean' + +# Set this to YES if you don't want a final libtool call for a library/framework. +# BUILD_OFILES_LIST_ONLY + +# To include a version string, project source must exist in a directory named +# $(NAME).%d[.%d][.%d] and the following line must be uncommented. +# OTHER_GENERATED_OFILES = $(VERS_OFILE) + +# This definition will suppress stripping of debug symbols when an executable +# is installed. By default it is YES. +# STRIP_ON_INSTALL = NO + +# Uncomment to suppress generation of a KeyValueCoding index when installing +# frameworks (This index is used by WOB and IB to determine keys available +# for an object). Set to YES by default. +# PREINDEX_FRAMEWORK = NO + +# Change this definition to install projects somewhere other than the +# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems +# and "" on other systems. +DSTROOT = $(HOME) diff --git a/ipsec/PB.project b/ipsec/PB.project new file mode 100644 index 0000000..cf372f6 --- /dev/null +++ b/ipsec/PB.project @@ -0,0 +1,43 @@ +{ + CURRENTLY_ACTIVE_VERSION = YES; + DEPLOY_WITH_VERSION_NAME = A; + DYNAMIC_CODE_GEN = YES; + FILESTABLE = { + FRAMEWORKS = (); + H_FILES = (ipsec_strerror.h, libpfkey.h, key_debug.h); + OTHER_LINKED = ( + ipsec_dump_policy.c, + ipsec_get_policylen.c, + ipsec_strerror.c, + policy_parse.y, + policy_token.l + ); + OTHER_SOURCES = ( + Makefile.preamble, + Makefile, + Makefile.postamble, + ipsec_set_policy.3, + ipsec_strerror.3 + ); + }; + LANGUAGE = English; + MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; + NEXTSTEP_BUILDTOOL = /bin/gnumake; + NEXTSTEP_INSTALLDIR = /lib; + NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; + NEXTSTEP_PUBLICHEADERSDIR = "/Developer/Headers/$(NAME)"; + PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; + PDO_UNIX_INSTALLDIR = /lib; + PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac"; + PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; + PDO_UNIX_PUBLICHEADERSDIR = "/Developer/Headers/$(NAME)"; + PROJECTNAME = ipsec; + PROJECTTYPE = Library; + PROJECTVERSION = 2.8; + WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; + WINDOWS_INSTALLDIR = /Developer/Libraries; + WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; + WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; + WINDOWS_PUBLICHEADERSDIR = "/Developer/Headers/$(NAME)"; +} diff --git a/ipsec/ipsec_dump_policy.c b/ipsec/ipsec_dump_policy.c new file mode 100644 index 0000000..390852f --- /dev/null +++ b/ipsec/ipsec_dump_policy.c @@ -0,0 +1,307 @@ +/* $FreeBSD: src/lib/libipsec/ipsec_dump_policy.c,v 1.1.2.1 2000/07/15 07:24:04 kris Exp $ */ +/* $KAME: ipsec_dump_policy.c,v 1.11 2000/05/07 05:29:47 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "ipsec_strerror.h" + +static const char *ipsp_dir_strs[] = { + "any", "in", "out", +}; + +static const char *ipsp_policy_strs[] = { + "discard", "none", "ipsec", "entrust", "bypass", +}; + +static char *ipsec_dump_ipsecrequest __P((char *, size_t, + struct sadb_x_ipsecrequest *, size_t)); +static int set_addresses __P((char *, size_t, struct sockaddr *, + struct sockaddr *)); +static char *set_address __P((char *, size_t, struct sockaddr *)); + +/* + * policy is sadb_x_policy buffer. + * Must call free() later. + * When delimiter == NULL, alternatively ' '(space) is applied. + */ +char * +ipsec_dump_policy(policy, delimiter) + caddr_t policy; + char *delimiter; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy; + struct sadb_x_ipsecrequest *xisr; + size_t off, buflen; + char *buf; + char isrbuf[1024]; + char *newbuf; + + /* sanity check */ + if (policy == NULL) + return NULL; + if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return NULL; + } + + /* set delimiter */ + if (delimiter == NULL) + delimiter = " "; + + switch (xpl->sadb_x_policy_dir) { + case IPSEC_DIR_ANY: + case IPSEC_DIR_INBOUND: + case IPSEC_DIR_OUTBOUND: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_DIR; + return NULL; + } + + switch (xpl->sadb_x_policy_type) { + case IPSEC_POLICY_DISCARD: + case IPSEC_POLICY_NONE: + case IPSEC_POLICY_IPSEC: + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_ENTRUST: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_POLICY; + return NULL; + } + + buflen = strlen(ipsp_dir_strs[xpl->sadb_x_policy_dir]) + + 1 /* space */ + + strlen(ipsp_policy_strs[xpl->sadb_x_policy_type]) + + 1; /* NUL */ + + if ((buf = malloc(buflen)) == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + return NULL; + } + snprintf(buf, buflen, "%s %s", ipsp_dir_strs[xpl->sadb_x_policy_dir], + ipsp_policy_strs[xpl->sadb_x_policy_type]); + + if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { + __ipsec_errcode = EIPSEC_NO_ERROR; + return buf; + } + + /* count length of buffer for use */ + off = sizeof(*xpl); + while (off < PFKEY_EXTLEN(xpl)) { + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); + off += xisr->sadb_x_ipsecrequest_len; + } + + /* validity check */ + if (off != PFKEY_EXTLEN(xpl)) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + free(buf); + return NULL; + } + + off = sizeof(*xpl); + while (off < PFKEY_EXTLEN(xpl)) { + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xpl + off); + + if (ipsec_dump_ipsecrequest(isrbuf, sizeof(isrbuf), xisr, + PFKEY_EXTLEN(xpl) - off) == NULL) { + free(buf); + return NULL; + } + + buflen = strlen(buf) + strlen(delimiter) + strlen(isrbuf) + 1; + newbuf = (char *)realloc(buf, buflen); + if (newbuf == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + free(buf); + return NULL; + } + buf = newbuf; + snprintf(buf, buflen, "%s%s%s", buf, delimiter, isrbuf); + + off += xisr->sadb_x_ipsecrequest_len; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return buf; +} + +static char * +ipsec_dump_ipsecrequest(buf, len, xisr, bound) + char *buf; + size_t len; + struct sadb_x_ipsecrequest *xisr; + size_t bound; /* boundary */ +{ + const char *proto, *mode, *level; + char abuf[NI_MAXHOST * 2 + 2]; + + if (xisr->sadb_x_ipsecrequest_len > bound) { + __ipsec_errcode = EIPSEC_INVAL_PROTO; + return NULL; + } + + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + proto = "esp"; + break; + case IPPROTO_AH: + proto = "ah"; + break; + case IPPROTO_IPCOMP: + proto = "ipcomp"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_PROTO; + return NULL; + } + + switch (xisr->sadb_x_ipsecrequest_mode) { + case IPSEC_MODE_ANY: + mode = "any"; + break; + case IPSEC_MODE_TRANSPORT: + mode = "transport"; + break; + case IPSEC_MODE_TUNNEL: + mode = "tunnel"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_MODE; + return NULL; + } + + abuf[0] = '\0'; + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + struct sockaddr *sa1, *sa2; + caddr_t p; + + p = (caddr_t)(xisr + 1); + sa1 = (struct sockaddr *)p; + sa2 = (struct sockaddr *)(p + sa1->sa_len); + if (sizeof(*xisr) + sa1->sa_len + sa2->sa_len != + xisr->sadb_x_ipsecrequest_len) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; + return NULL; + } + if (set_addresses(abuf, sizeof(abuf), sa1, sa2) != 0) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; + return NULL; + } + } + + switch (xisr->sadb_x_ipsecrequest_level) { + case IPSEC_LEVEL_DEFAULT: + level = "default"; + break; + case IPSEC_LEVEL_USE: + level = "use"; + break; + case IPSEC_LEVEL_REQUIRE: + level = "require"; + break; + case IPSEC_LEVEL_UNIQUE: + level = "unique"; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_LEVEL; + return NULL; + } + + if (xisr->sadb_x_ipsecrequest_reqid == 0) + snprintf(buf, len, "%s/%s/%s/%s", proto, mode, abuf, level); + else { + int ch; + + if (xisr->sadb_x_ipsecrequest_reqid > IPSEC_MANUAL_REQID_MAX) + ch = '#'; + else + ch = ':'; + snprintf(buf, len, "%s/%s/%s/%s%c%d", proto, mode, abuf, level, + ch, xisr->sadb_x_ipsecrequest_reqid); + } + + return buf; +} + +static int +set_addresses(buf, len, sa1, sa2) + char *buf; + size_t len; + struct sockaddr *sa1; + struct sockaddr *sa2; +{ + char tmp1[NI_MAXHOST], tmp2[NI_MAXHOST]; + + if (set_address(tmp1, sizeof(tmp1), sa1) == NULL || + set_address(tmp2, sizeof(tmp2), sa2) == NULL) + return -1; + if (strlen(tmp1) + 1 + strlen(tmp2) + 1 > len) + return -1; + snprintf(buf, len, "%s-%s", tmp1, tmp2); + return 0; +} + +static char * +set_address(buf, len, sa) + char *buf; + size_t len; + struct sockaddr *sa; +{ +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; +#endif + + if (len < 1) + return NULL; + buf[0] = '\0'; + if (getnameinfo(sa, sa->sa_len, buf, len, NULL, 0, niflags) != 0) + return NULL; + return buf; +} diff --git a/ipsec/ipsec_get_policylen.c b/ipsec/ipsec_get_policylen.c new file mode 100644 index 0000000..3713cb8 --- /dev/null +++ b/ipsec/ipsec_get_policylen.c @@ -0,0 +1,47 @@ +/* $FreeBSD: src/lib/libipsec/ipsec_get_policylen.c,v 1.1.2.1 2000/07/15 07:24:04 kris Exp $ */ +/* $KAME: ipsec_get_policylen.c,v 1.5 2000/05/07 05:25:03 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include + +#include + +#include + +#include "ipsec_strerror.h" + +int +ipsec_get_policylen(policy) + caddr_t policy; +{ + return policy ? PFKEY_EXTLEN(policy) : -1; +} diff --git a/ipsec/ipsec_set_policy.3 b/ipsec/ipsec_set_policy.3 new file mode 100644 index 0000000..a13c30a --- /dev/null +++ b/ipsec/ipsec_set_policy.3 @@ -0,0 +1,274 @@ +.\" $KAME: ipsec_set_policy.3,v 1.14 2001/04/06 07:00:46 itojun Exp $ +.\" $FreeBSD: src/lib/libipsec/ipsec_set_policy.3,v 1.3.2.7 2001/08/17 15:42:59 ru Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. +.\" +.Dd May 5, 1998 +.Dt IPSEC_SET_POLICY 3 +.Os +.Sh NAME +.Nm ipsec_set_policy , +.Nm ipsec_get_policylen , +.Nm ipsec_dump_policy +.Nd manipulate IPsec policy specification structure from readable string +.\" +.Sh LIBRARY +.Lb libipsec +.Sh SYNOPSIS +.Fd #include +.Ft "char *" +.Fn ipsec_set_policy "char *policy" "int len" +.Ft int +.Fn ipsec_get_policylen "char *buf" +.Ft "char *" +.Fn ipsec_dump_policy "char *buf" "char *delim" +.Sh DESCRIPTION +.Fn ipsec_set_policy +generates IPsec policy specification structure, namely +.Li struct sadb_x_policy +and/or +.Li struct sadb_x_ipsecrequest +from human-readable policy specification. +Policy specification must be given as C string +.Fa policy +and length +.Fa len +of +.Fa policy . +.Fn ipsec_set_policy +will return the buffer of IPsec policy specification structure. +.Pp +You may want the length of the generated buffer such when calling +.Xr setsockopt 2 . +.Fn ipsec_get_policylen +will return the length. +.Pp +.Fn ipsec_dump_policy +converts IPsec policy structure into readable form. +Therefore, +.Fn ipsec_dump_policy +can be regarded as inverse conversion of +.Fn ipsec_set_policy . +.Fa buf +points to a IPsec policy structure, +.Li struct sadb_x_policy . +.Fa delim +is a delimiter string, which is usually a blank character. +If you set +.Fa delim +to +.Dv NULL , +single whitespace is assumed. +.Fn ipsec_dump_policy +returns pointer to dynamically allocated string. +It is caller's responsibility to reclaim the region, by using +.Xr free 3 . +.Pp +.Fa policy +is formatted as either of the following: +.Bl -tag -width "discard" +.It Ar direction Li discard +.Ar direction +must be +.Li in +or +.Li out . +.Ar direction +specifies which direction the policy needs to be applied. +With +.Li discard +policy, packets will be dropped if they match the policy. +.It Ar direction Li entrust +.Li entrust +means to consult to SPD defined by +.Xr setkey 8 . +.It Ar direction Li bypass +.Li bypass +means to be bypassed the IPsec processing. +(packet will be transmitted in clear). +This is for privileged socket. +.It Xo +.Ar direction +.Li ipsec +.Ar request ... +.Xc +.Li ipsec +means that the matching packets are subject to IPsec processing. +.Li ipsec +can be followed by one or more +.Ar request +string, which is formatted as below: +.Bl -tag -width "discard" +.It Xo +.Ar protocol +.Li / +.Ar mode +.Li / +.Ar src +.Li - +.Ar dst +.Op Ar /level +.Xc +.Ar protocol +is either +.Li ah , +.Li esp +or +.Li ipcomp . +.Pp +.Ar mode +is either +.Li transport +or +.Li tunnel . +.Pp +.Ar src +and +.Ar dst +specifies IPsec endpoint. +.Ar src +always means +.Dq sending node +and +.Ar dst +always means +.Dq receiving node . +Therefore, when +.Ar direction +is +.Li in , +.Ar dst +is this node +and +.Ar src +is the other node +(peer). +If +.Ar mode +is +.Li transport , +Both +.Ar src +and +.Ar dst +can be omited. +.Pp +.Ar level +must be set to one of the following: +.Li default , use , require +or +.Li unique . +.Li default +means that the kernel should consult the system default policy +defined by +.Xr sysctl 8 , +such as +.Li net.inet.ipsec.esp_trans_deflev . +See +.Xr ipsec 4 +regarding the system default. +.Li use +means that a relevant SA can be used when available, +since the kernel may perform IPsec operation against packets when possible. +In this case, packets can be transmitted in clear +(when SA is not available), +or encrypted +(when SA is available). +.Li require +means that a relevant SA is required, +since the kernel must perform IPsec operation against packets. +.Li unique +is the same as +.Li require , +but adds the restriction that the SA for outbound traffic is used +only for this policy. +You may need the identifier in order to relate the policy and the SA +when you define the SA by manual keying. +You can put the decimal number as the identifier after +.Li unique +like +.Li unique : number . +.Li number +must be between 1 and 32767 . +If the +.Ar request +string is kept unambiguous, +.Ar level +and slash prior to +.Ar level +can be omitted. +However, it is encouraged to specify them explicitly +to avoid unintended behaviors. +If +.Ar level +is omitted, it will be interpreted as +.Li default . +.El +.El +.Pp +Note that there is a bit difference of specification from +.Xr setkey 8 . +In specification by +.Xr setkey 8 , +both entrust and bypass are not used. +Refer to +.Xr setkey 8 +for detail. +.Pp +Here are several examples +(long lines are wrapped for readability): +.Bd -literal -offset indent +in discard +out ipsec esp/transport//require +in ipsec ah/transport//require +out ipsec esp/tunnel/10.1.1.2-10.1.1.1/use +in ipsec ipcomp/transport//use + esp/transport//use +.Ed +.Sh RETURN VALUES +.Fn ipsec_set_policy +returns a pointer to the allocated buffer of policy specification if successful; otherwise a NULL pointer is returned. +.Fn ipsec_get_policylen +returns with positive value +(meaning the buffer size) +on success, and negative value on errors. +.Fn ipsec_dump_policy +returns a pointer to dynamically allocated region on success, +and +.Dv NULL +on errors. +.Sh SEE ALSO +.Xr ipsec_strerror 3 , +.Xr ipsec 4 , +.Xr setkey 8 +.Sh HISTORY +The functions first appeared in WIDE/KAME IPv6 protocol stack kit. +.Pp +IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack +was initially integrated into +.Fx 4.0 diff --git a/ipsec/ipsec_strerror.3 b/ipsec/ipsec_strerror.3 new file mode 100644 index 0000000..3d3a9f1 --- /dev/null +++ b/ipsec/ipsec_strerror.3 @@ -0,0 +1,82 @@ +.\" $KAME: ipsec_strerror.3,v 1.8 2000/11/20 00:35:14 sakane Exp $ +.\" $FreeBSD: src/lib/libipsec/ipsec_strerror.3,v 1.2.2.5 2001/07/03 11:01:14 ume Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. +.\" +.Dd May 6, 1998 +.Dt IPSEC_STRERROR 3 +.Os +.\" +.Sh NAME +.Nm ipsec_strerror +.Nd error message for IPsec policy manipulation library +.\" +.Sh SYNOPSIS +.Fd #include +.Ft "const char *" +.Fn ipsec_strerror +.\" +.Sh DESCRIPTION +.Pa netinet6/ipsec.h +declares +.Pp +.Dl extern int ipsec_errcode; +.Pp +which is used to pass an error code from IPsec policy manipulation library +to an user program. +.Fn ipsec_strerror +can be used to obtain the error message string for the error code. +.Pp +The array pointed to is not to be modified by the program. +Since +.Fn ipsec_strerror +uses +.Xr strerror 3 +as underlying function, calling +.Xr strerror 3 +after +.Fn ipsec_strerror +would make the return value from +.Fn ipsec_strerror +invalid, or overwritten. +.\" +.Sh RETURN VALUES +.Fn ipsec_strerror +always return a pointer to C string. +The C string must not be overwritten by user programs. +.\" +.Sh SEE ALSO +.Xr ipsec_set_policy 3 +.\" +.Sh HISTORY +.Fn ipsec_strerror +first appeared in WIDE/KAME IPv6 protocol stack kit. +.\" +.Sh BUGS +.Fn ipsec_strerror +will return its result which may be overwritten by subsequent calls. diff --git a/ipsec/ipsec_strerror.c b/ipsec/ipsec_strerror.c new file mode 100644 index 0000000..a4fa9b7 --- /dev/null +++ b/ipsec/ipsec_strerror.c @@ -0,0 +1,88 @@ +/* $FreeBSD: src/lib/libipsec/ipsec_strerror.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: ipsec_strerror.c,v 1.7 2000/07/30 00:45:12 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include + +#include +#include + +#include "ipsec_strerror.h" + +int __ipsec_errcode; + +static const char *ipsec_errlist[] = { +"Success", /*EIPSEC_NO_ERROR*/ +"Not supported", /*EIPSEC_NOT_SUPPORTED*/ +"Invalid argument", /*EIPSEC_INVAL_ARGUMENT*/ +"Invalid sadb message", /*EIPSEC_INVAL_SADBMSG*/ +"Invalid version", /*EIPSEC_INVAL_VERSION*/ +"Invalid security policy", /*EIPSEC_INVAL_POLICY*/ +"Invalid address specification", /*EIPSEC_INVAL_ADDRESS*/ +"Invalid ipsec protocol", /*EIPSEC_INVAL_PROTO*/ +"Invalid ipsec mode", /*EIPSEC_INVAL_MODE*/ +"Invalid ipsec level", /*EIPSEC_INVAL_LEVEL*/ +"Invalid SA type", /*EIPSEC_INVAL_SATYPE*/ +"Invalid message type", /*EIPSEC_INVAL_MSGTYPE*/ +"Invalid extension type", /*EIPSEC_INVAL_EXTTYPE*/ +"Invalid algorithm type", /*EIPSEC_INVAL_ALGS*/ +"Invalid key length", /*EIPSEC_INVAL_KEYLEN*/ +"Invalid address family", /*EIPSEC_INVAL_FAMILY*/ +"Invalid prefix length", /*EIPSEC_INVAL_PREFIXLEN*/ +"Invalid direciton", /*EIPSEC_INVAL_DIR*/ +"SPI range violation", /*EIPSEC_INVAL_SPI*/ +"No protocol specified", /*EIPSEC_NO_PROTO*/ +"No algorithm specified", /*EIPSEC_NO_ALGS*/ +"No buffers available", /*EIPSEC_NO_BUFS*/ +"Must get supported algorithms list first", /*EIPSEC_DO_GET_SUPP_LIST*/ +"Protocol mismatch", /*EIPSEC_PROTO_MISMATCH*/ +"Family mismatch", /*EIPSEC_FAMILY_MISMATCH*/ +"Too few arguments", /*EIPSEC_FEW_ARGUMENTS*/ +NULL, /*EIPSEC_SYSTEM_ERROR*/ +"Unknown error", /*EIPSEC_MAX*/ +}; + +const char *ipsec_strerror(void) +{ + if (__ipsec_errcode < 0 || __ipsec_errcode > EIPSEC_MAX) + __ipsec_errcode = EIPSEC_MAX; + + return ipsec_errlist[__ipsec_errcode]; +} + +void __ipsec_set_strerror(const char *str) +{ + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + ipsec_errlist[EIPSEC_SYSTEM_ERROR] = str; + + return; +} diff --git a/ipsec/ipsec_strerror.h b/ipsec/ipsec_strerror.h new file mode 100644 index 0000000..da87324 --- /dev/null +++ b/ipsec/ipsec_strerror.h @@ -0,0 +1,63 @@ +/* $FreeBSD: src/lib/libipsec/ipsec_strerror.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +extern int __ipsec_errcode; +extern void __ipsec_set_strerror __P((const char *)); + +#define EIPSEC_NO_ERROR 0 /*success*/ +#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ +#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/ +#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/ +#define EIPSEC_INVAL_VERSION 4 /*invalid version*/ +#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/ +#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/ +#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/ +#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/ +#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/ +#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/ +#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/ +#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/ +#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/ +#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/ +#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/ +#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/ +#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/ +#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/ +#define EIPSEC_NO_PROTO 19 /*no protocol specified*/ +#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/ +#define EIPSEC_NO_BUFS 21 /*no buffers available*/ +#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/ +#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/ +#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/ +#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/ +#define EIPSEC_SYSTEM_ERROR 26 /*system error*/ +#define EIPSEC_MAX 27 /*unknown error*/ diff --git a/ipsec/key_debug.h b/ipsec/key_debug.h new file mode 100644 index 0000000..7620da5 --- /dev/null +++ b/ipsec/key_debug.h @@ -0,0 +1,95 @@ +/* $FreeBSD: src/sys/netkey/key_debug.h,v 1.5.2.2 2001/07/03 11:01:59 ume Exp $ */ +/* $KAME: key_debug.h,v 1.7 2000/07/04 04:08:16 itojun 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. 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. + */ + +#ifndef _NETKEY_KEY_DEBUG_H_ +#define _NETKEY_KEY_DEBUG_H_ + +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) + +/* debug flags */ +#define KEYDEBUG_STAMP 0x00000001 /* path */ +#define KEYDEBUG_DATA 0x00000002 /* data */ +#define KEYDEBUG_DUMP 0x00000004 /* dump */ + +#define KEYDEBUG_KEY 0x00000010 /* key processing */ +#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */ +#define KEYDEBUG_IPSEC 0x00000040 /* ipsec processing */ + +#define KEYDEBUG_KEY_STAMP (KEYDEBUG_KEY | KEYDEBUG_STAMP) +#define KEYDEBUG_KEY_DATA (KEYDEBUG_KEY | KEYDEBUG_DATA) +#define KEYDEBUG_KEY_DUMP (KEYDEBUG_KEY | KEYDEBUG_DUMP) +#define KEYDEBUG_ALG_STAMP (KEYDEBUG_ALG | KEYDEBUG_STAMP) +#define KEYDEBUG_ALG_DATA (KEYDEBUG_ALG | KEYDEBUG_DATA) +#define KEYDEBUG_ALG_DUMP (KEYDEBUG_ALG | KEYDEBUG_DUMP) +#define KEYDEBUG_IPSEC_STAMP (KEYDEBUG_IPSEC | KEYDEBUG_STAMP) +#define KEYDEBUG_IPSEC_DATA (KEYDEBUG_IPSEC | KEYDEBUG_DATA) +#define KEYDEBUG_IPSEC_DUMP (KEYDEBUG_IPSEC | KEYDEBUG_DUMP) + +#define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; } + +#ifdef _KERNEL +extern u_int32_t key_debug_level; +#endif /*_KERNEL*/ + +struct sadb_msg; +struct sadb_ext; +extern void kdebug_sadb __P((struct sadb_msg *)); +extern void kdebug_sadb_x_policy __P((struct sadb_ext *)); + +#ifdef _KERNEL +struct secpolicy; +struct secpolicyindex; +struct secasindex; +struct secasvar; +struct secreplay; +struct mbuf; +extern void kdebug_secpolicy __P((struct secpolicy *)); +extern void kdebug_secpolicyindex __P((struct secpolicyindex *)); +extern void kdebug_secasindex __P((struct secasindex *)); +extern void kdebug_secasv __P((struct secasvar *)); +extern void kdebug_mbufhdr __P((struct mbuf *)); +extern void kdebug_mbuf __P((struct mbuf *)); +#endif /*_KERNEL*/ + +struct sockaddr; +extern void kdebug_sockaddr __P((struct sockaddr *)); + +extern void ipsec_hexdump __P((caddr_t, int)); +extern void ipsec_bindump __P((caddr_t, int)); + +#else + +#define KEYDEBUG(lev,arg) + +#endif /*!defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))*/ + +#endif /* _NETKEY_KEY_DEBUG_H_ */ diff --git a/ipsec/libpfkey.h b/ipsec/libpfkey.h new file mode 100644 index 0000000..28adea7 --- /dev/null +++ b/ipsec/libpfkey.h @@ -0,0 +1,90 @@ +/* $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej 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. 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. + */ + +struct sadb_msg; +extern void pfkey_sadump __P((struct sadb_msg *)); +extern void pfkey_spdump __P((struct sadb_msg *)); + +struct sockaddr; +struct sadb_alg; +int ipsec_check_keylen __P((u_int, u_int, u_int)); +int ipsec_check_keylen2 __P((u_int, u_int, u_int)); +int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *)); +u_int pfkey_set_softrate __P((u_int, u_int)); +u_int pfkey_get_softrate __P((u_int)); +int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); +int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_delete __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_delete_all __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *)); +int pfkey_send_get __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_register __P((int, u_int)); +int pfkey_recv_register __P((int)); +int pfkey_set_supported __P((struct sadb_msg *, int)); +int pfkey_send_flush __P((int, u_int)); +int pfkey_send_dump __P((int, u_int)); +int pfkey_send_promisc_toggle __P((int, int)); +int pfkey_send_spdadd __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spddelete __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spddelete2 __P((int, u_int32_t)); +int pfkey_send_spdget __P((int, u_int32_t)); +int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdflush __P((int)); +int pfkey_send_spddump __P((int)); + +int pfkey_open __P((void)); +void pfkey_close __P((int)); +struct sadb_msg *pfkey_recv __P((int)); +int pfkey_send __P((int, struct sadb_msg *, int)); +int pfkey_align __P((struct sadb_msg *, caddr_t *)); +int pfkey_check __P((caddr_t *)); diff --git a/ipsec/policy_parse.y b/ipsec/policy_parse.y new file mode 100644 index 0000000..65e7929 --- /dev/null +++ b/ipsec/policy_parse.y @@ -0,0 +1,432 @@ +/* $FreeBSD: src/lib/libipsec/policy_parse.y,v 1.1.2.1 2000/07/15 07:24:04 kris Exp $ */ +/* $KAME: policy_parse.y,v 1.10 2000/05/07 05:25:03 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +/* + * IN/OUT bound policy configuration take place such below: + * in + * out + * + * is one of following: + * "discard", "none", "ipsec ", "entrust", "bypass", + * + * The following requests are accepted as : + * + * protocol/mode/src-dst/level + * protocol/mode/src-dst parsed as protocol/mode/src-dst/default + * protocol/mode/src-dst/ parsed as protocol/mode/src-dst/default + * protocol/transport parsed as protocol/mode/any-any/default + * protocol/transport//level parsed as protocol/mode/any-any/level + * + * You can concatenate these requests with either ' '(single space) or '\n'. + */ + +%{ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "ipsec_strerror.h" + +#define ATOX(c) \ + (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) + +static caddr_t pbuf = NULL; /* sadb_x_policy buffer */ +static int tlen = 0; /* total length of pbuf */ +static int offset = 0; /* offset of pbuf */ +static int p_dir, p_type, p_protocol, p_mode, p_level, p_reqid; +static struct sockaddr *p_src = NULL; +static struct sockaddr *p_dst = NULL; + +struct _val; +extern void yyerror __P((char *msg)); +static struct sockaddr *parse_sockaddr __P((struct _val *buf)); +static int rule_check __P((void)); +static int init_x_policy __P((void)); +static int set_x_request __P((struct sockaddr *src, struct sockaddr *dst)); +static int set_sockaddr __P((struct sockaddr *addr)); +static void policy_parse_request_init __P((void)); +static caddr_t policy_parse __P((char *msg, int msglen)); + +extern void __policy__strbuffer__init__ __P((char *msg)); +extern int yyparse __P((void)); +extern int yylex __P((void)); + +%} + +%union { + u_int num; + struct _val { + int len; + char *buf; + } val; +} + +%token DIR ACTION PROTOCOL MODE LEVEL LEVEL_SPECIFY +%token IPADDRESS +%token ME ANY +%token SLASH HYPHEN +%type DIR ACTION PROTOCOL MODE LEVEL +%type IPADDRESS LEVEL_SPECIFY + +%% +policy_spec + : DIR ACTION + { + p_dir = $1; + p_type = $2; + + if (init_x_policy()) + return -1; + } + rules + | DIR + { + p_dir = $1; + p_type = 0; /* ignored it by kernel */ + + if (init_x_policy()) + return -1; + } + ; + +rules + : /*NOTHING*/ + | rules rule { + if (rule_check() < 0) + return -1; + + if (set_x_request(p_src, p_dst) < 0) + return -1; + + policy_parse_request_init(); + } + ; + +rule + : protocol SLASH mode SLASH addresses SLASH level + | protocol SLASH mode SLASH addresses SLASH + | protocol SLASH mode SLASH addresses + | protocol SLASH mode SLASH + | protocol SLASH mode SLASH SLASH level + | protocol SLASH mode + | protocol SLASH { + __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; + return -1; + } + | protocol { + __ipsec_errcode = EIPSEC_FEW_ARGUMENTS; + return -1; + } + ; + +protocol + : PROTOCOL { p_protocol = $1; } + ; + +mode + : MODE { p_mode = $1; } + ; + +level + : LEVEL { + p_level = $1; + p_reqid = 0; + } + | LEVEL_SPECIFY { + p_level = IPSEC_LEVEL_UNIQUE; + p_reqid = atol($1.buf); /* atol() is good. */ + } + ; + +addresses + : IPADDRESS { + p_src = parse_sockaddr(&$1); + if (p_src == NULL) + return -1; + } + HYPHEN + IPADDRESS { + p_dst = parse_sockaddr(&$4); + if (p_dst == NULL) + return -1; + } + | ME HYPHEN ANY { + if (p_dir != IPSEC_DIR_OUTBOUND) { + __ipsec_errcode = EIPSEC_INVAL_DIR; + return -1; + } + } + | ANY HYPHEN ME { + if (p_dir != IPSEC_DIR_INBOUND) { + __ipsec_errcode = EIPSEC_INVAL_DIR; + return -1; + } + } + /* + | ME HYPHEN ME + */ + ; + +%% + +void +yyerror(msg) + char *msg; +{ + extern char *__libipsecyytext; /*XXX*/ + + fprintf(stderr, "libipsec: %s while parsing \"%s\"\n", + msg, __libipsecyytext); + + return; +} + +static struct sockaddr * +parse_sockaddr(buf) + struct _val *buf; +{ + struct addrinfo hints, *res; + char *serv = NULL; + int error; + struct sockaddr *newaddr = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(buf->buf, serv, &hints, &res); + if (error != 0) { + yyerror("invalid IP address"); + __ipsec_set_strerror(gai_strerror(error)); + return NULL; + } + + if (res->ai_addr == NULL) { + yyerror("invalid IP address"); + __ipsec_set_strerror(gai_strerror(error)); + return NULL; + } + + newaddr = malloc(res->ai_addr->sa_len); + if (newaddr == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + freeaddrinfo(res); + return NULL; + } + memcpy(newaddr, res->ai_addr, res->ai_addr->sa_len); + + freeaddrinfo(res); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return newaddr; +} + +static int +rule_check() +{ + if (p_type == IPSEC_POLICY_IPSEC) { + if (p_protocol == IPPROTO_IP) { + __ipsec_errcode = EIPSEC_NO_PROTO; + return -1; + } + + if (p_mode != IPSEC_MODE_TRANSPORT + && p_mode != IPSEC_MODE_TUNNEL) { + __ipsec_errcode = EIPSEC_INVAL_MODE; + return -1; + } + + if (p_src == NULL && p_dst == NULL) { + if (p_mode != IPSEC_MODE_TRANSPORT) { + __ipsec_errcode = EIPSEC_INVAL_ADDRESS; + return -1; + } + } + else if (p_src->sa_family != p_dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static int +init_x_policy() +{ + struct sadb_x_policy *p; + + tlen = sizeof(struct sadb_x_policy); + + pbuf = malloc(tlen); + if (pbuf == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + return -1; + } + p = (struct sadb_x_policy *)pbuf; + p->sadb_x_policy_len = 0; /* must update later */ + p->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + p->sadb_x_policy_type = p_type; + p->sadb_x_policy_dir = p_dir; + p->sadb_x_policy_reserved = 0; + offset = tlen; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static int +set_x_request(src, dst) + struct sockaddr *src, *dst; +{ + struct sadb_x_ipsecrequest *p; + int reqlen; + + reqlen = sizeof(*p) + + (src ? src->sa_len : 0) + + (dst ? dst->sa_len : 0); + tlen += reqlen; /* increment to total length */ + + pbuf = realloc(pbuf, tlen); + if (pbuf == NULL) { + __ipsec_errcode = EIPSEC_NO_BUFS; + return -1; + } + p = (struct sadb_x_ipsecrequest *)&pbuf[offset]; + p->sadb_x_ipsecrequest_len = reqlen; + p->sadb_x_ipsecrequest_proto = p_protocol; + p->sadb_x_ipsecrequest_mode = p_mode; + p->sadb_x_ipsecrequest_level = p_level; + p->sadb_x_ipsecrequest_reqid = p_reqid; + offset += sizeof(*p); + + if (set_sockaddr(src) || set_sockaddr(dst)) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static int +set_sockaddr(addr) + struct sockaddr *addr; +{ + if (addr == NULL) { + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; + } + + /* tlen has already incremented */ + + memcpy(&pbuf[offset], addr, addr->sa_len); + + offset += addr->sa_len; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +static void +policy_parse_request_init() +{ + p_protocol = IPPROTO_IP; + p_mode = IPSEC_MODE_ANY; + p_level = IPSEC_LEVEL_DEFAULT; + p_reqid = 0; + if (p_src != NULL) { + free(p_src); + p_src = NULL; + } + if (p_dst != NULL) { + free(p_dst); + p_dst = NULL; + } + + return; +} + +static caddr_t +policy_parse(msg, msglen) + char *msg; + int msglen; +{ + int error; + pbuf = NULL; + tlen = 0; + + /* initialize */ + p_dir = IPSEC_DIR_INVALID; + p_type = IPSEC_POLICY_DISCARD; + policy_parse_request_init(); + __policy__strbuffer__init__(msg); + + error = yyparse(); /* it must be set errcode. */ + if (error) { + if (pbuf != NULL) + free(pbuf); + return NULL; + } + + /* update total length */ + ((struct sadb_x_policy *)pbuf)->sadb_x_policy_len = PFKEY_UNIT64(tlen); + + __ipsec_errcode = EIPSEC_NO_ERROR; + + return pbuf; +} + +caddr_t +ipsec_set_policy(msg, msglen) + char *msg; + int msglen; +{ + caddr_t policy; + + policy = policy_parse(msg, msglen); + if (policy == NULL) { + if (__ipsec_errcode == EIPSEC_NO_ERROR) + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return policy; +} + diff --git a/ipsec/policy_token.l b/ipsec/policy_token.l new file mode 100644 index 0000000..3dee127 --- /dev/null +++ b/ipsec/policy_token.l @@ -0,0 +1,148 @@ +/* $FreeBSD: src/lib/libipsec/policy_token.l,v 1.2.2.2 2001/07/03 11:01:15 ume Exp $ */ +/* $KAME: policy_token.l,v 1.11 2000/12/01 10:08:29 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +%{ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef __NetBSD__ +#include "y.tab.h" +#else +#include "policy_parse.h" +#endif +#define yylval __libipsecyylval /* XXX */ + +int yylex __P((void)); +%} + +%option noyywrap +%option nounput + +/* common section */ +nl \n +ws [ \t]+ +digit [0-9] +hexdigit [0-9A-Fa-f] +special [()+\|\?\*,] +dot \. +comma \, +hyphen \- +colon \: +slash \/ +bcl \{ +ecl \} +blcl \[ +elcl \] +percent \% +semi \; +usec {dot}{digit}{1,6} +comment \#.* +ccomment "/*" +bracketstring \<[^>]*\> +quotedstring \"[^"]*\" +decstring {digit}+ +hexpair {hexdigit}{hexdigit} +hexstring 0[xX]{hexdigit}+ +octetstring {octet}({dot}{octet})+ +ipaddress [a-zA-Z0-9:\._][a-zA-Z0-9:\._]*(%[a-zA-Z0-9]+)? + +%% + +in { yylval.num = IPSEC_DIR_INBOUND; return(DIR); } +out { yylval.num = IPSEC_DIR_OUTBOUND; return(DIR); } + +discard { yylval.num = IPSEC_POLICY_DISCARD; return(ACTION); } +none { yylval.num = IPSEC_POLICY_NONE; return(ACTION); } +ipsec { yylval.num = IPSEC_POLICY_IPSEC; return(ACTION); } +bypass { yylval.num = IPSEC_POLICY_BYPASS; return(ACTION); } +entrust { yylval.num = IPSEC_POLICY_ENTRUST; return(ACTION); } + +esp { yylval.num = IPPROTO_ESP; return(PROTOCOL); } +ah { yylval.num = IPPROTO_AH; return(PROTOCOL); } +ipcomp { yylval.num = IPPROTO_IPCOMP; return(PROTOCOL); } + +transport { yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); } +tunnel { yylval.num = IPSEC_MODE_TUNNEL; return(MODE); } + +me { return(ME); } +any { return(ANY); } + +default { yylval.num = IPSEC_LEVEL_DEFAULT; return(LEVEL); } +use { yylval.num = IPSEC_LEVEL_USE; return(LEVEL); } +require { yylval.num = IPSEC_LEVEL_REQUIRE; return(LEVEL); } +unique{colon}{decstring} { + yylval.val.len = strlen(yytext + 7); + yylval.val.buf = yytext + 7; + return(LEVEL_SPECIFY); + } +unique { yylval.num = IPSEC_LEVEL_UNIQUE; return(LEVEL); } +{slash} { return(SLASH); } + +{ipaddress} { + yylval.val.len = strlen(yytext); + yylval.val.buf = yytext; + return(IPADDRESS); + } + +{hyphen} { return(HYPHEN); } + +{ws} { ; } +{nl} { ; } + +%% + +void __policy__strbuffer__init__ __P((char *)); + +void +__policy__strbuffer__init__(msg) + char *msg; +{ + YY_BUFFER_STATE yyb; + + yyb = (YY_BUFFER_STATE)yy_scan_string(msg); + yy_switch_to_buffer(yyb); + + return; +} + diff --git a/makedbm.tproj/db.c b/makedbm.tproj/db.c index 9d5396d..b5562b4 100644 --- a/makedbm.tproj/db.c +++ b/makedbm.tproj/db.c @@ -59,7 +59,6 @@ static char rcsid[] = "$OpenBSD: db.c,v 1.1 1997/07/22 10:52:59 maja Exp $"; #endif #include -#include #include #include #include diff --git a/natd.tproj/icmp.c b/natd.tproj/icmp.c index 10d3bda..4e62d3f 100644 --- a/natd.tproj/icmp.c +++ b/natd.tproj/icmp.c @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ /* * natd - Network Address Translation Daemon for FreeBSD. * @@ -9,7 +30,8 @@ * * Ari Suutari * - * $Id: icmp.c,v 1.1.1.1 2000/01/11 01:48:51 wsanchez Exp $ + * Based upon: + * $FreeBSD: src/sbin/natd/icmp.c,v 1.6 1999/08/28 00:13:45 peter Exp $ */ #include diff --git a/natd.tproj/natd.8 b/natd.tproj/natd.8 index 1d1cb7f..c6f8e8e 100644 --- a/natd.tproj/natd.8 +++ b/natd.tproj/natd.8 @@ -1,156 +1,264 @@ .\" manual page [] for natd 1.4 -.\" $Id: natd.8,v 1.1.1.1 2000/01/11 01:48:51 wsanchez Exp $ -.Dd 15 April 1997 -.Os FreeBSD +.\" $Id: natd.8,v 1.4 2002/05/10 00:51:01 mscopp Exp $ +.Dd June 27, 2000 +.Os Darwin .Dt NATD 8 .Sh NAME .Nm natd -.Nd -Network Address Translation Daemon +.Nd Network Address Translation daemon .Sh SYNOPSIS .Nm -.Op Fl ldsmvu +.Bk -words +.Op Fl unregistered_only | u +.Op Fl log | l +.Op Fl proxy_only +.Op Fl reverse +.Op Fl deny_incoming | d +.Op Fl use_sockets | s +.Op Fl same_ports | m +.Op Fl verbose | v .Op Fl dynamic -.Op Fl i Ar inport -.Op Fl o Ar outport -.Op Fl p Ar port -.Op Fl a Ar address -.Op Fl n Ar interface -.Op Fl f Ar configfile - -.Nm -.Op Fl log -.Op Fl deny_incoming +.Op Fl in_port | i Ar port +.Op Fl out_port | o Ar port +.Op Fl port | p Ar port +.Op Fl alias_address | a Ar address +.Op Fl target_address | t Ar address +.Op Fl interface | n Ar interface +.Op Fl proxy_rule Ar proxyspec +.Op Fl redirect_port Ar linkspec +.Op Fl redirect_proto Ar linkspec +.Op Fl redirect_address Ar linkspec +.Op Fl config | f Ar configfile .Op Fl log_denied -.Op Fl use_sockets -.Op Fl same_ports -.Op Fl verbose .Op Fl log_facility Ar facility_name -.Op Fl unregistered_only -.Op Fl dynamic -.Op Fl inport Ar inport -.Op Fl outport Ar outport -.Op Fl port Ar port -.Op Fl alias_address Ar address -.Op Fl interface Ar interface -.Op Fl config Ar configfile -.Op Fl redirect_port Ar linkspec -.Op Fl redirect_address Ar localIP publicIP -.Op Fl reverse -.Op Fl proxy_only -.Op Fl proxy_rule Ar proxyspec -.Op Fl pptpalias Ar localIP - +.Op Fl punch_fw Ar firewall_range +.Ek .Sh DESCRIPTION This program provides a Network Address Translation facility for use with .Xr divert 4 -sockets under FreeBSD. It is intended for use with NICs - if you want -to do NAT on a PPP link, use the -alias switch to +sockets under +.Fx . +It is intended for use with NICs - if you want to do NAT on a PPP link, +use the +.Fl nat +switch to .Xr ppp 8 . - -.Pp -.Nm Natd -normally runs in the background as a daemon. It is passed raw IP packets -as they travel into and out of the machine, and will possibly change these -before re-injecting them back into the IP packet stream. - -.Pp -.Nm Natd -changes all packets destined for another host so that their source -IP number is that of the current machine. For each packet changed -in this manner, an internal table entry is created to record this -fact. The source port number is also changed to indicate the -table entry applying to the packet. Packets that are received with -a target IP of the current host are checked against this internal -table. If an entry is found, it is used to determine the correct -target IP number and port to place in the packet. - -.Pp -The following command line options are available. +.Pp +The +.Nm +normally runs in the background as a daemon. +It is passed raw IP packets as they travel into and out of the machine, +and will possibly change these before re-injecting them back into the +IP packet stream. +.Pp +It changes all packets destined for another host so that their source +IP number is that of the current machine. +For each packet changed in this manner, an internal table entry is +created to record this fact. +The source port number is also changed to indicate the table entry +applying to the packet. +Packets that are received with a target IP of the current host are +checked against this internal table. +If an entry is found, it is used to determine the correct target IP +number and port to place in the packet. +.Pp +The following command line options are available: .Bl -tag -width Fl - .It Fl log | l Log various aliasing statistics and information to the file .Pa /var/log/alias.log . -This file is truncated each time natd is started. - +This file is truncated each time +.Nm +is started. .It Fl deny_incoming | d -Reject packets destined for the current IP number that have no entry -in the internal translation table. - +Do not pass incoming packets that have no +entry in the internal translation table. +.Pp +If this option is not used, then such a packet will be altered +using the rules in +.Fl target_address +below, and the entry will be made in the internal translation table. .It Fl log_denied -Log denied incoming packets via syslog (see also log_facility) - +Log denied incoming packets via +.Xr syslog 3 +.Po +see also +.Fl log_facility +.Pc . .It Fl log_facility Ar facility_name -Use specified log facility when logging information via syslog. -Facility names are as in -.Xr syslog.conf 5 - +Use specified log facility when logging information via +.Xr syslog 3 . +Argument +.Ar facility_name +is one of the keywords specified in +.Xr syslog.conf 5 . .It Fl use_sockets | s Allocate a .Xr socket 2 -in order to establish an FTP data or IRC DCC send connection. This -option uses more system resources, but guarantees successful connections -when port numbers conflict. - +in order to establish an FTP data or IRC DCC send connection. +This option uses more system resources, but guarantees successful +connections when port numbers conflict. .It Fl same_ports | m Try to keep the same port number when altering outgoing packets. With this option, protocols such as RPC will have a better chance -of working. If it is not possible to maintain the port number, it -will be silently changed as per normal. - +of working. +If it is not possible to maintain the port number, it will be silently +changed as per normal. .It Fl verbose | v -Don't call -.Xr fork 2 -or +Do not call .Xr daemon 3 -on startup. Instead, stay attached to the controling terminal and +on startup. Instead, stay attached to the controlling terminal and display all packet alterations to the standard output. This option should only be used for debugging purposes. - .It Fl unregistered_only | u -Only alter outgoing packets with an unregistered source address. -According to rfc 1918, unregistered source addresses are 10.0.0.0/8, +Only alter outgoing packets with an +.Em unregistered +source address. +According to RFC 1918, unregistered source addresses are 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. - -.It Fl redirect_port Ar proto targetIP:targetPORT [aliasIP:]aliasPORT [remoteIP[:remotePORT]] -Redirect incoming connections arriving to given port to another host and port. -Proto is either tcp or udp, targetIP is the desired target IP -number, targetPORT is the desired target PORT number, aliasPORT -is the requested PORT number and aliasIP is the aliasing address. -RemoteIP and remotePORT can be used to specify the connection -more accurately if necessary. +.It Fl redirect_port Ar proto Xo +.Ar targetIP Ns : Ns Xo +.Ar targetPORT Ns Op - Ns Ar targetPORT Xc +.Op Ar aliasIP Ns : Ns Xo +.Ar aliasPORT Ns Op - Ns Ar aliasPORT Xc +.Oo Ar remoteIP Ns Oo : Ns +.Ar remotePORT Ns Op - Ns Ar remotePORT +.Oc Oc +.Xc +Redirect incoming connections arriving to given port(s) to another host +and port(s). +Argument +.Ar proto +is either +.Ar tcp +or +.Ar udp , +.Ar targetIP +is the desired target IP number, +.Ar targetPORT +is the desired target port number or range, +.Ar aliasPORT +is the requested port number or range, and +.Ar aliasIP +is the aliasing address. +Arguments +.Ar remoteIP +and +.Ar remotePORT +can be used to specify the connection more accurately if necessary. +The +.Ar targetPORT +range and +.Ar aliasPORT +range need not be the same numerically, but must have the same size. +If +.Ar remotePORT +is not specified, it is assumed to be all ports. +If +.Ar remotePORT +is specified, it must match the size of +.Ar targetPORT , +or be 0 (all ports). For example, the argument - -.Ar tcp inside1:telnet 6666 - -means that tcp packets destined for port 6666 on this machine will -be sent to the telnet port on the inside1 machine. - +.Pp +.Dl Ar tcp inside1:telnet 6666 +.Pp +means that incoming TCP packets destined for port 6666 on this machine +will be sent to the telnet port on the inside1 machine. +.Pp +.Dl Ar tcp inside2:2300-2399 3300-3399 +.Pp +will redirect incoming connections on ports 3300-3399 to host +inside2, ports 2300-2399. +The mapping is 1:1 meaning port 3300 maps to 2300, 3301 maps to 2301, etc. +.It Fl redirect_proto Ar proto localIP Oo +.Ar publicIP Op Ar remoteIP +.Oc +Redirect incoming IP packets of protocol +.Ar proto +.Po see Xr protocols 5 +.Pc +destined for +.Ar publicIP +address to a +.Ar localIP +address and vice versa. +.Pp +If +.Ar publicIP +is not specified, then the default aliasing address is used. +If +.Ar remoteIP +is specified, then only packets coming from/to +.Ar remoteIP +will match the rule. .It Fl redirect_address Ar localIP publicIP Redirect traffic for public IP address to a machine on the local -network. This function is known as "static NAT". Normally static NAT -is useful if your ISP has allocated a small block of IP addresses to you, -but it can even be used in the case of single address: - - redirect_address 10.0.0.8 0.0.0.0 - +network. +This function is known as +.Em static NAT . +Normally static NAT is useful if your ISP has allocated a small block +of IP addresses to you, but it can even be used in the case of single +address: +.Pp +.Dl Ar redirect_address 10.0.0.8 0.0.0.0 +.Pp The above command would redirect all incoming traffic to machine 10.0.0.8. - +.Pp If several address aliases specify the same public address as follows - - redirect_address 192.168.0.2 public_addr - redirect_address 192.168.0.3 public_addr - redirect_address 192.168.0.4 public_addr - +.Bd -literal -offset indent +.Ar redirect_address 192.168.0.2 public_addr +.Ar redirect_address 192.168.0.3 public_addr +.Ar redirect_address 192.168.0.4 public_addr +.Ed +.Pp the incoming traffic will be directed to the last translated local address (192.168.0.4), but outgoing -traffic to the first two addresses will still be aliased -to specified public address. - +traffic from the first two addresses will still be aliased +to appear from the specified +.Ar public_addr . +.It Fl redirect_port Ar proto Xo +.Ar targetIP Ns : Ns Xo +.Ar targetPORT Ns Oo , Ns +.Ar targetIP Ns : Ns Xo +.Ar targetPORT Ns Oo , Ns +.Ar ...\& +.Oc Oc +.Xc +.Xc +.Op Ar aliasIP Ns : Ns Xo +.Ar aliasPORT +.Xc +.Oo Ar remoteIP Ns +.Op : Ns Ar remotePORT +.Oc +.Xc +.It Fl redirect_address Xo +.Ar localIP Ns Oo , Ns +.Ar localIP Ns Oo , Ns +.Ar ...\& +.Oc Oc +.Ar publicIP +.Xc +These forms of +.Fl redirect_port +and +.Fl redirect_address +are used to transparently offload network load on a single server and +distribute the load across a pool of servers. +This function is known as +.Em LSNAT +(RFC 2391). +For example, the argument +.Pp +.Dl Ar tcp www1:http,www2:http,www3:http www:http +.Pp +means that incoming HTTP requests for host www will be transparently +redirected to one of the www1, www2 or www3, where a host is selected +simply on a round-robin basis, without regard to load on the net. .It Fl dynamic If the .Fl n @@ -160,267 +268,331 @@ option is used, .Nm will monitor the routing socket for alterations to the .Ar interface -passed. If the interfaces IP number is changed, +passed. +If the interface's IP number is changed, .Nm will dynamically alter its concept of the alias address. - -.It Fl i | inport Ar inport +.It Fl in_port | i Ar port Read from and write to -.Ar inport , -treating all packets as packets coming into the machine. - -.It Fl o | outport Ar outport +.Xr divert 4 +port +.Ar port , +treating all packets as +.Dq incoming . +.It Fl out_port | o Ar port Read from and write to -.Ar outport , -treating all packets as packets going out of the machine. - -.It Fl p | port Ar port +.Xr divert 4 +port +.Ar port , +treating all packets as +.Dq outgoing . +.It Fl port | p Ar port Read from and write to +.Xr divert 4 +port .Ar port , -distinguishing packets as incoming our outgoing using the rules specified in +distinguishing packets as +.Dq incoming +or +.Dq outgoing +using the rules specified in .Xr divert 4 . If .Ar port is not numeric, it is searched for in the -.Pa /etc/services -database using the -.Xr getservbyname 3 -function. If this flag is not specified, the divert port named natd will -be used as a default. An example entry in the -.Pa /etc/services -database would be: - - natd 8668/divert # Network Address Translation socket - -Refer to .Xr services 5 -for further details. - -.It Fl a | alias_address Ar address +database. +If this option is not specified, the divert port named +.Ar natd +will be used as a default. +.It Fl alias_address | a Ar address Use .Ar address -as the alias address. If this option is not specified, the -.Fl n -or +as the aliasing address. +If this option is not specified, the .Fl interface -option must be used. The specified address should be the address assigned -to the public network interface. +option must be used. +The specified address is usually the address assigned to the +.Dq public +network interface. .Pp -All data passing out through this addresses interface will be rewritten -with a source address equal to +All data passing +.Em out +will be rewritten with a source address equal to .Ar address . -All data arriving at the interface from outside will be checked to -see if it matches any already-aliased outgoing connection. If it does, -the packet is altered accordingly. If not, all -.Fl redirect_port +All data coming +.Em in +will be checked to see if it matches any already-aliased outgoing +connection. +If it does, the packet is altered accordingly. +If not, all +.Fl redirect_port , +.Fl redirect_proto and .Fl redirect_address -assignments are checked and actioned. If no other action can be made, -and if +assignments are checked and actioned. +If no other action can be made and if .Fl deny_incoming -is not specified, the packet is delivered to the local machine and port -as specified in the packet. - -.It Fl n | interface Ar interface +is not specified, the packet is delivered to the local machine +using the rules specified in +.Fl target_address +option below. +.It Fl t | target_address Ar address +Set the target address. +When an incoming packet not associated with any pre-existing link +arrives at the host machine, it will be sent to the specified +.Ar address . +.Pp +The target address may be set to +.Ar 255.255.255.255 , +in which case all new incoming packets go to the alias address set by +.Fl alias_address +or +.Fl interface . +.Pp +If this option is not used, or called with the argument +.Ar 0.0.0.0 , +then all new incoming packets go to the address specified in +the packet. +This allows external machines to talk directly to internal machines if +they can route packets to the machine in question. +.It Fl interface | n Ar interface Use .Ar interface -to determine the alias address. If there is a possibility that the -IP number associated with +to determine the aliasing address. +If there is a possibility that the IP number associated with .Ar interface may change, the .Fl dynamic -flag should also be used. If this option is not specified, the -.Fl a -or +option should also be used. +If this option is not specified, the .Fl alias_address -flag must be used. +option must be used. .Pp The specified .Ar interface -must be the public network interface. -.It Fl f | config Ar configfile +is usually the +.Dq public +(or +.Dq external ) +network interface. +.It Fl config | f Ar file Read configuration from -.Ar configfile . -.Ar Configfile -contains a list of options, one per line in the same form as the -long form of the above command line flags. For example, the line - - alias_address 158.152.17.1 - -would specify an alias address of 158.152.17.1. Options that don't -take an argument are specified with an option of +.Ar file . +A +.Ar file +should contain a list of options, one per line, in the same form +as the long form of the above command line options. +For example, the line +.Pp +.Dl alias_address 158.152.17.1 +.Pp +would specify an alias address of 158.152.17.1. +Options that do not take an argument are specified with an argument of .Ar yes or .Ar no in the configuration file. For example, the line - log yes - -is synonomous with +is synonymous with .Fl log . -Empty lines and lines beginning with '#' are ignored. - +.Pp +Trailing spaces and empty lines are ignored. +A +.Ql \&# +sign will mark the rest of the line as a comment. .It Fl reverse -Reverse operation of natd. This can be useful in some -transparent proxying situations when outgoing traffic -is redirected to the local machine and natd is running on the -incoming interface (it usually runs on the outgoing interface). - +This option makes +.Nm +reverse the way it handles +.Dq incoming +and +.Dq outgoing +packets, allowing it to operate on the +.Dq internal +network interface rather than the +.Dq external +one. +.Pp +This can be useful in some transparent proxying situations +when outgoing traffic is redirected to the local machine +and +.Nm +is running on the internal interface (it usually runs on the +external interface). .It Fl proxy_only -Force natd to perform transparent proxying -only. Normal address translation is not performed. - -.It Fl proxy_rule Ar [type encode_ip_hdr|encode_tcp_stream] port xxxx server a.b.c.d:yyyy -Enable transparent proxying. Packets with the given port going through this +Force +.Nm +to perform transparent proxying only. +Normal address translation is not performed. +.It Fl proxy_rule Xo +.Op Ar type encode_ip_hdr | encode_tcp_stream +.Ar port xxxx +.Ar server a.b.c.d:yyyy +.Xc +Enable transparent proxying. +Outgoing TCP packets with the given port going through this host to any other host are redirected to the given server and port. -Optionally, the original target address can be encoded into the packet. Use -.Dq encode_ip_hdr +Optionally, the original target address can be encoded into the packet. +Use +.Ar encode_ip_hdr to put this information into the IP option field or -.Dq encode_tcp_stream +.Ar encode_tcp_stream to inject the data into the beginning of the TCP stream. - -.It Fl pptpalias Ar localIP -Allow PPTP packets to go to the defined localIP address. PPTP is a VPN or secure -IP tunneling technology being developed primarily by Microsoft. For its encrypted traffic, -it uses an old IP encapsulation protocol called GRE (47). This -natd option will translate any traffic of this protocol to a -single, specified IP address. This would allow either one client or one server -to be serviced with natd. If you are setting up a server, don't forget to allow the TCP traffic -for the PPTP setup. For a client or server, you must allow GRE (protocol 47) if you have firewall lists active. - +.It Fl punch_fw Xo +.Ar basenumber Ns : Ns Ar count +.Xc +This option directs +.Nm +to +.Dq punch holes +in an +.Xr ipfirewall 4 +based firewall for FTP/IRC DCC connections. +This is done dynamically by installing temporary firewall rules which +allow a particular connection (and only that connection) to go through +the firewall. +The rules are removed once the corresponding connection terminates. +.Pp +A maximum of +.Ar count +rules starting from the rule number +.Ar basenumber +will be used for punching firewall holes. +The range will be cleared for all rules on startup. .El - .Sh RUNNING NATD The following steps are necessary before attempting to run -.Nm natd : - +.Nm : .Bl -enum -.It -Get FreeBSD version 2.2 or higher. Versions before this do not support -.Xr divert 4 -sockets. - .It Build a custom kernel with the following options: - - options IPFIREWALL - options IPDIVERT - +.Bd -literal -offset indent +options IPFIREWALL +options IPDIVERT +.Ed +.Pp Refer to the handbook for detailed instructions on building a custom kernel. - .It -Ensure that your machine is acting as a gateway. This can be done by -specifying the line - - gateway_enable=YES - -in -.Pa /etc/rc.conf , -or using the command - - sysctl -w net.inet.ip.forwarding=1 - +Ensure that your machine is acting as a gateway. +This can be done by specifying the line +.Pp +.Dl gateway_enable=YES +.Pp +in the +.Pa /etc/rc.conf +file or using the command +.Pp +.Dl sysctl -w net.inet.ip.forwarding=1 +.Pp .It -If you wish to use the -.Fl n -or +If you use the .Fl interface -flags, make sure that your interface is already configured. If, for -example, you wish to specify tun0 as your +option, make sure that your interface is already configured. +If, for example, you wish to specify +.Ql tun0 +as your .Ar interface , -and you're using +and you are using .Xr ppp 8 on that interface, you must make sure that you start .Nm ppp prior to starting -.Nm natd . - -.It -Create an entry in -.Pa /etc/services : - - natd 8668/divert # Network Address Translation socket - -This gives a default for the -.Fl p -or -.Fl port -flag. - +.Nm . .El .Pp Running .Nm -is fairly straight forward. The line - - natd -interface ed0 - -should suffice in most cases (substituting the correct interface name). Once +is fairly straight forward. +The line +.Pp +.Dl natd -interface en0 +.Pp +should suffice in most cases (substituting the correct interface name). +Please check +.Xr rc.conf 5 +on how to configure it to be started automatically during boot. +Once .Nm -is running, you must ensure that traffic is diverted to natd: - +is running, you must ensure that traffic is diverted to +.Nm : .Bl -enum .It You will need to adjust the .Pa /etc/rc.firewall -script to taste. If you're not interested in having a firewall, the +script to taste. +If you are not interested in having a firewall, the following lines will do: - - /sbin/ipfw -f flush - /sbin/ipfw add divert natd all from any to any via ed0 - /sbin/ipfw add pass all from any to any - -The second line depends on your interface (change ed0 as appropriate) -and assumes that you've updated -.Pa /etc/services -with the natd entry as above. If you specify real firewall rules, it's -best to specify line 2 at the start of the script so that +.Bd -literal -offset indent +/sbin/ipfw -f flush +/sbin/ipfw add divert natd all from any to any via ed0 +/sbin/ipfw add pass all from any to any +.Ed +.Pp +The second line depends on your interface (change +.Ql en0 +as appropriate). +.Pp +You should be aware of the fact that, with these firewall settings, +everyone on your local network can fake his source-address using your +host as gateway. +If there are other hosts on your local network, you are strongly +encouraged to create firewall rules that only allow traffic to and +from trusted hosts. +.Pp +If you specify real firewall rules, it is best to specify line 2 at +the start of the script so that .Nm -sees all packets before they are dropped by the firewall. The firewall -rules will be run again on each packet after translation by -.Nm natd , -minus any divert rules. - +sees all packets before they are dropped by the firewall. +.Pp +After translation by +.Nm , +packets re-enter the firewall at the rule number following the rule number +that caused the diversion (not the next rule if there are several at the +same number). .It Enable your firewall by setting - - firewall_enable=YES - +.Pp +.Dl firewall_enable=YES +.Pp in .Pa /etc/rc.conf . This tells the system startup scripts to run the .Pa /etc/rc.firewall -script. If you don't wish to reboot now, just run this by hand from the -console. NEVER run this from a virtual session unless you put it into -the background. If you do, you'll lock yourself out after the flush -takes place, and execution of +script. +If you do not wish to reboot now, just run this by hand from the console. +NEVER run this from a remote session unless you put it into the background. +If you do, you will lock yourself out after the flush takes place, and +execution of .Pa /etc/rc.firewall -will stop at this point - blocking all accesses permanently. Running -the script in the background should be enough to prevent this disaster. - +will stop at this point - blocking all accesses permanently. +Running the script in the background should be enough to prevent this +disaster. .El - .Sh SEE ALSO -.Xr getservbyname 2 , -.Xr socket 2 , .Xr divert 4 , +.Xr protocols 5 , +.Xr rc.conf 5 , .Xr services 5 , -.Xr ipfw 8 - +.Xr syslog.conf 5 , +.Xr ipfw 8 , +.Xr ppp 8 .Sh AUTHORS This program is the result of the efforts of many people at different times: - +.Pp .An Archie Cobbs Aq archie@whistle.com (divert sockets) -.An Charles Mott Aq cmott@srv.net +.An Charles Mott Aq cmott@scientech.com (packet aliasing) .An Eivind Eklund Aq perhaps@yes.no (IRC support & misc additions) .An Ari Suutari Aq suutari@iki.fi (natd) .An Dru Nelson Aq dnelson@redwoodsoft.com -(PPTP support) +(early PPTP support) .An Brian Somers Aq brian@awfulhak.org (glue) +.An Ruslan Ermilov Aq ru@FreeBSD.org +(natd, packet aliasing, glue) diff --git a/natd.tproj/natd.c b/natd.tproj/natd.c index bbb8678..bea14a9 100644 --- a/natd.tproj/natd.c +++ b/natd.tproj/natd.c @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ /* * natd - Network Address Translation Daemon for FreeBSD. * @@ -9,13 +30,15 @@ * * Ari Suutari * - * $Id: natd.c,v 1.1.1.1 2000/01/11 01:48:51 wsanchez Exp $ + * Based upon: + * $FreeBSD: src/sbin/natd/natd.c,v 1.25.2.3 2000/07/11 20:00:57 ru Exp $ */ #define SYSLOG_NAMES #include #include +#include #include #include @@ -24,8 +47,8 @@ #include #include #include -#include #include +#include #include #include @@ -80,15 +103,15 @@ static void Usage (void); static char* FormatPacket (struct ip*); static void PrintPacket (struct ip*); static void SyslogPacket (struct ip*, int priority, const char *label); -static void SetAliasAddressFromIfName (char* ifName); +static void SetAliasAddressFromIfName (const char *ifName); static void InitiateShutdown (int); static void Shutdown (int); static void RefreshAddr (int); -static void ParseOption (const char* option, const char* parms, int cmdLine); +static void ParseOption (const char* option, const char* parms); static void ReadConfigFile (const char* fileName); static void SetupPortRedirect (const char* parms); +static void SetupProtoRedirect(const char* parms); static void SetupAddressRedirect (const char* parms); -static void SetupPptpAlias (const char* parms); static void StrToAddr (const char* str, struct in_addr* addr); static u_short StrToPort (const char* str, const char* proto); static int StrToPortRange (const char* str, const char* proto, port_range *portRange); @@ -96,6 +119,7 @@ static int StrToProto (const char* str); static int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, port_range *portRange); static void ParseArgs (int argc, char** argv); static void FlushPacketBuffer (int fd); +static void SetupPunchFW(const char *strValue); /* * Globals. @@ -167,7 +191,8 @@ int main (int argc, char** argv) /* * Open syslog channel. */ - openlog ("natd", LOG_CONS | LOG_PID, logFacility); + openlog ("natd", LOG_CONS | LOG_PID | (verbose ? LOG_PERROR : 0), + logFacility); /* * Check that valid aliasing address has been given. */ @@ -185,7 +210,7 @@ int main (int argc, char** argv) errx (1, "both input and output ports are required"); if (inPort == 0 && outPort == 0 && inOutPort == 0) - ParseOption ("port", DEFAULT_SERVICE, 0); + ParseOption ("port", DEFAULT_SERVICE); /* * Check if ignored packets should be dropped. @@ -253,16 +278,21 @@ int main (int argc, char** argv) Quit ("Unable to bind outgoing divert socket."); } /* - * Create routing socket if interface name specified. + * Create routing socket if interface name specified and in dynamic mode. */ - if (ifName && dynamicMode) { + routeSock = -1; + if (ifName) { + if (dynamicMode) { - routeSock = socket (PF_ROUTE, SOCK_RAW, 0); - if (routeSock == -1) - Quit ("Unable to create routing info socket."); + routeSock = socket (PF_ROUTE, SOCK_RAW, 0); + if (routeSock == -1) + Quit ("Unable to create routing info socket."); + + assignAliasAddr = 1; + } + else + SetAliasAddressFromIfName (ifName); } - else - routeSock = -1; /* * Create socket for sending ICMP messages. */ @@ -285,6 +315,8 @@ int main (int argc, char** argv) * Catch signals to manage shutdown and * refresh of interface address. */ + siginterrupt(SIGTERM, 1); + siginterrupt(SIGHUP, 1); signal (SIGTERM, InitiateShutdown); signal (SIGHUP, RefreshAddr); /* @@ -411,9 +443,9 @@ static void DaemonMode () static void ParseArgs (int argc, char** argv) { int arg; - char* parm; char* opt; char parmBuf[256]; + int len; /* bounds checking */ for (arg = 1; arg < argc; arg++) { @@ -424,23 +456,27 @@ static void ParseArgs (int argc, char** argv) Usage (); } - parm = NULL; parmBuf[0] = '\0'; + len = 0; while (arg < argc - 1) { if (argv[arg + 1][0] == '-') break; - if (parm) - strcat (parmBuf, " "); + if (len) { + strncat (parmBuf, " ", sizeof(parmBuf) - (len + 1)); + len += strlen(parmBuf + len); + } ++arg; - parm = parmBuf; - strcat (parmBuf, argv[arg]); + strncat (parmBuf, argv[arg], sizeof(parmBuf) - (len + 1)); + len += strlen(parmBuf + len); + } - ParseOption (opt + 1, parm, 1); + ParseOption (opt + 1, (len ? parmBuf : NULL)); + } } @@ -479,14 +515,14 @@ static void DoAliasing (int fd, int direction) * This is a IP packet. */ ip = (struct ip*) packetBuf; - if (direction == DONT_KNOW) + if (direction == DONT_KNOW) { if (packetAddr.sin_addr.s_addr == INADDR_ANY) direction = OUTPUT; else direction = INPUT; + } if (verbose) { - /* * Print packet direction and protocol type. */ @@ -630,16 +666,14 @@ static void HandleRoutingInfo (int fd) } if (verbose) - printf ("Routing message %X received.\n", ifMsg.ifm_type); - - if (ifMsg.ifm_type != RTM_NEWADDR) - return; - - if (verbose && ifMsg.ifm_index == ifIndex) - printf ("Interface address has changed.\n"); + printf ("Routing message %#x received.\n", ifMsg.ifm_type); - if (ifMsg.ifm_index == ifIndex) + if ((ifMsg.ifm_type == RTM_NEWADDR || ifMsg.ifm_type == RTM_IFINFO) && + ifMsg.ifm_index == ifIndex) { + if (verbose) + printf("Interface address/MTU has probably changed.\n"); assignAliasAddr = 1; + } } static void PrintPacket (struct ip* ip) @@ -700,101 +734,102 @@ static char* FormatPacket (struct ip* ip) return buf; } -static void SetAliasAddressFromIfName (char* ifn) +static void +SetAliasAddressFromIfName(const char *ifn) { - struct ifconf cf; - struct ifreq buf[32]; - char msg[80]; - struct ifreq* ifPtr; - int extra; - int helperSock; - int bytes; - struct sockaddr_in* addr; - int found; - struct ifreq req; - char last[10]; -/* - * Create a dummy socket to access interface information. - */ - helperSock = socket (AF_INET, SOCK_DGRAM, 0); - if (helperSock == -1) { - - Quit ("Failed to create helper socket."); - exit (1); - } - - cf.ifc_len = sizeof (buf); - cf.ifc_req = buf; + size_t needed; + int mib[6]; + char *buf, *lim, *next; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + struct sockaddr_dl *sdl; + struct sockaddr_in *sin; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; /* Only IP addresses please */ + mib[4] = NET_RT_IFLIST; + mib[5] = 0; /* ifIndex??? */ /* * Get interface data. */ - if (ioctl (helperSock, SIOCGIFCONF, &cf) == -1) { - - Quit ("Ioctl SIOCGIFCONF failed."); - exit (1); - } - - ifIndex = 0; - ifPtr = buf; - bytes = cf.ifc_len; - found = 0; - last[0] = '\0'; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) + err(1, "iflist-sysctl-estimate"); + if ((buf = malloc(needed)) == NULL) + errx(1, "malloc failed"); + if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) + err(1, "iflist-sysctl-get"); + lim = buf + needed; /* * Loop through interfaces until one with * given name is found. This is done to * find correct interface index for routing * message processing. */ - while (bytes) { - - if (ifPtr->ifr_addr.sa_family == AF_INET && - !strcmp (ifPtr->ifr_name, ifn)) { - - found = 1; - break; + ifIndex = 0; + next = buf; + while (next < lim) { + ifm = (struct if_msghdr *)next; + next += ifm->ifm_msglen; + if (ifm->ifm_version != RTM_VERSION) { + if (verbose) + warnx("routing message version %d " + "not understood", ifm->ifm_version); + continue; } - - if (strcmp (last, ifPtr->ifr_name)) { - - strcpy (last, ifPtr->ifr_name); - ++ifIndex; + if (ifm->ifm_type == RTM_IFINFO) { + sdl = (struct sockaddr_dl *)(ifm + 1); + if (strlen(ifn) == sdl->sdl_nlen && + strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { + ifIndex = ifm->ifm_index; + ifMTU = ifm->ifm_data.ifi_mtu; + break; + } } - - extra = ifPtr->ifr_addr.sa_len - sizeof (struct sockaddr); - - ifPtr++; - ifPtr = (struct ifreq*) ((char*) ifPtr + extra); - bytes -= sizeof (struct ifreq) + extra; } - - if (!found) { - - close (helperSock); - sprintf (msg, "Unknown interface name %s.\n", ifn); - Quit (msg); - } -/* - * Get MTU size. - */ - strcpy (req.ifr_name, ifn); - - if (ioctl (helperSock, SIOCGIFMTU, &req) == -1) - Quit ("Cannot get interface mtu size."); - - ifMTU = req.ifr_mtu; + if (!ifIndex) + errx(1, "unknown interface name %s", ifn); /* * Get interface address. */ - if (ioctl (helperSock, SIOCGIFADDR, &req) == -1) - Quit ("Cannot get interface address."); + sin = NULL; + while (next < lim) { + ifam = (struct ifa_msghdr *)next; + next += ifam->ifam_msglen; + if (ifam->ifam_version != RTM_VERSION) { + if (verbose) + warnx("routing message version %d " + "not understood", ifam->ifam_version); + continue; + } + if (ifam->ifam_type != RTM_NEWADDR) + break; + if (ifam->ifam_addrs & RTA_IFA) { + int i; + char *cp = (char *)(ifam + 1); + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + + for (i = 1; i < RTA_IFA; i <<= 1) + if (ifam->ifam_addrs & i) + ADVANCE(cp, (struct sockaddr *)cp); + if (((struct sockaddr *)cp)->sa_family == AF_INET) { + sin = (struct sockaddr_in *)cp; + break; + } + } + } + if (sin == NULL) + errx(1, "%s: cannot get interface address", ifn); - addr = (struct sockaddr_in*) &req.ifr_addr; - PacketAliasSetAddress (addr->sin_addr); - syslog (LOG_INFO, "Aliasing to %s, mtu %d bytes", - inet_ntoa (addr->sin_addr), - ifMTU); + PacketAliasSetAddress(sin->sin_addr); + syslog(LOG_INFO, "Aliasing to %s, mtu %d bytes", + inet_ntoa(sin->sin_addr), ifMTU); - close (helperSock); + free(buf); } void Quit (const char* msg) @@ -808,12 +843,11 @@ void Warn (const char* msg) if (background) syslog (LOG_ALERT, "%s (%m)", msg); else - warn (msg); + warn ("%s", msg); } static void RefreshAddr (int sig) { - signal (SIGHUP, RefreshAddr); if (ifName) assignAliasAddr = 1; } @@ -825,6 +859,7 @@ static void InitiateShutdown (int sig) * shutdown existing connections when system * is shut down. */ + siginterrupt(SIGALRM, 1); signal (SIGALRM, Shutdown); alarm (10); } @@ -846,15 +881,17 @@ enum Option { OutPort, Port, AliasAddress, + TargetAddress, InterfaceName, RedirectPort, + RedirectProto, RedirectAddress, ConfigFile, DynamicMode, - PptpAlias, ProxyRule, LogDenied, - LogFacility + LogFacility, + PunchFW }; enum Param { @@ -992,6 +1029,14 @@ static struct OptionInfo optionTable[] = { "alias_address", "a" }, + { TargetAddress, + 0, + Address, + "x.x.x.x", + "address to use for incoming sessions", + "target_address", + "t" }, + { InterfaceName, 0, String, @@ -1012,26 +1057,26 @@ static struct OptionInfo optionTable[] = { { RedirectPort, 0, String, - "tcp|udp local_addr:local_port_range [public_addr:]public_port_range" + "tcp|udp local_addr:local_port_range[,...] [public_addr:]public_port_range" " [remote_addr[:remote_port_range]]", "redirect a port (or ports) for incoming traffic", "redirect_port", NULL }, - { RedirectAddress, + { RedirectProto, 0, String, - "local_addr public_addr", - "define mapping between local and public addresses", - "redirect_address", + "proto local_addr [public_addr] [remote_addr]", + "redirect packets of a given proto", + "redirect_proto", NULL }, - { PptpAlias, + { RedirectAddress, 0, String, - "src", - "define inside machine for PPTP traffic", - "pptpalias", + "local_addr[,...] public_addr", + "define mapping between local and public addresses", + "redirect_address", NULL }, { ConfigFile, @@ -1056,11 +1101,18 @@ static struct OptionInfo optionTable[] = { "facility", "name of syslog facility to use for logging", "log_facility", - NULL } + NULL }, + { PunchFW, + 0, + String, + "basenumber:count", + "punch holes in the firewall for incoming FTP/IRC DCC connections", + "punch_fw", + NULL } }; -static void ParseOption (const char* option, const char* parms, int cmdLine) +static void ParseOption (const char* option, const char* parms) { int i; struct OptionInfo* info; @@ -1183,16 +1235,20 @@ static void ParseOption (const char* option, const char* parms, int cmdLine) memcpy (&aliasAddr, &addrValue, sizeof (struct in_addr)); break; + case TargetAddress: + PacketAliasSetTarget(addrValue); + break; + case RedirectPort: SetupPortRedirect (strValue); break; - case RedirectAddress: - SetupAddressRedirect (strValue); + case RedirectProto: + SetupProtoRedirect(strValue); break; - case PptpAlias: - SetupPptpAlias (strValue); + case RedirectAddress: + SetupAddressRedirect (strValue); break; case ProxyRule: @@ -1204,7 +1260,6 @@ static void ParseOption (const char* option, const char* parms, int cmdLine) free (ifName); ifName = strdup (strValue); - assignAliasAddr = 1; break; case ConfigFile: @@ -1234,42 +1289,45 @@ static void ParseOption (const char* option, const char* parms, int cmdLine) errx(1, "Unknown log facility name: %s", strValue); break; + + case PunchFW: + SetupPunchFW(strValue); + break; } } void ReadConfigFile (const char* fileName) { FILE* file; - char buf[128]; - char* ptr; + char *buf; + size_t len; + char *ptr, *p; char* option; file = fopen (fileName, "r"); - if (!file) { - - sprintf (buf, "Cannot open config file %s.\n", fileName); - Quit (buf); - } - - while (fgets (buf, sizeof (buf), file)) { - - ptr = strchr (buf, '\n'); - if (!ptr) - errx (1, "config line too long: %s", buf); + if (!file) + err(1, "cannot open config file %s", fileName); - *ptr = '\0'; - if (buf[0] == '#') - continue; + while ((buf = fgetln(file, &len)) != NULL) { + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + else + errx(1, "config file format error: " + "last line should end with newline"); - ptr = buf; /* - * Skip white space at beginning of line. + * Check for comments, strip off trailing spaces. */ - while (*ptr && isspace (*ptr)) - ++ptr; - + if ((ptr = strchr(buf, '#'))) + *ptr = '\0'; + for (ptr = buf; isspace(*ptr); ++ptr) + continue; if (*ptr == '\0') continue; + for (p = strchr(buf, '\0'); isspace(*--p);) + continue; + *++p = '\0'; + /* * Extract option name. */ @@ -1288,7 +1346,7 @@ void ReadConfigFile (const char* fileName) while (*ptr && isspace (*ptr)) ++ptr; - ParseOption (option, *ptr ? ptr : NULL, 0); + ParseOption (option, *ptr ? ptr : NULL); } fclose (file); @@ -1318,29 +1376,11 @@ static void Usage () exit (1); } -void SetupPptpAlias (const char* parms) -{ - char buf[128]; - char* ptr; - struct in_addr srcAddr; - - strcpy (buf, parms); - -/* - * Extract source address. - */ - ptr = strtok (buf, " \t"); - if (!ptr) - errx(1, "pptpalias: missing src address"); - - StrToAddr (ptr, &srcAddr); - PacketAliasPptp (srcAddr); -} - void SetupPortRedirect (const char* parms) { char buf[128]; char* ptr; + char* serverPool; struct in_addr localAddr; struct in_addr publicAddr; struct in_addr remoteAddr; @@ -1355,6 +1395,7 @@ void SetupPortRedirect (const char* parms) char* protoName; char* separator; int i; + struct alias_link *link = NULL; strcpy (buf, parms); /* @@ -1372,14 +1413,23 @@ void SetupPortRedirect (const char* parms) if (!ptr) errx (1, "redirect_port: missing local address"); - if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) - errx (1, "redirect_port: invalid local port range"); - - localPort = GETLOPORT(portRange); - numLocalPorts = GETNUMPORTS(portRange); + separator = strchr(ptr, ','); + if (separator) { /* LSNAT redirection syntax. */ + localAddr.s_addr = INADDR_NONE; + localPort = ~0; + numLocalPorts = 1; + serverPool = ptr; + } else { + if ( StrToAddrAndPortRange (ptr, &localAddr, protoName, &portRange) != 0 ) + errx (1, "redirect_port: invalid local port range"); + + localPort = GETLOPORT(portRange); + numLocalPorts = GETNUMPORTS(portRange); + serverPool = NULL; + } /* - * Extract public port and optinally address. + * Extract public port and optionally address. */ ptr = strtok (NULL, " \t"); if (!ptr) @@ -1405,10 +1455,10 @@ void SetupPortRedirect (const char* parms) ptr = strtok (NULL, " \t"); if (ptr) { separator = strchr (ptr, ':'); - if (separator) + if (separator) { if (StrToAddrAndPortRange (ptr, &remoteAddr, protoName, &portRange) != 0) errx (1, "redirect_port: invalid remote port range"); - else { + } else { SETLOPORT(portRange, 0); SETNUMPORTS(portRange, 1); StrToAddr (ptr, &remoteAddr); @@ -1430,7 +1480,7 @@ void SetupPortRedirect (const char* parms) errx (1, "redirect_port: port ranges must be equal in size"); /* Remote port range is allowed to be '0' which means all ports. */ - if (numRemotePorts != numLocalPorts && numRemotePorts != 1 && remotePort != 0) + if (numRemotePorts != numLocalPorts && (numRemotePorts != 1 || remotePort != 0)) errx (1, "redirect_port: remote port must be 0 or equal to local port range in size"); for (i = 0 ; i < numPublicPorts ; ++i) { @@ -1439,22 +1489,98 @@ void SetupPortRedirect (const char* parms) if (numRemotePorts == 1 && remotePort == 0) remotePortCopy = 0; - PacketAliasRedirectPort (localAddr, - htons(localPort + i), - remoteAddr, - htons(remotePortCopy), - publicAddr, - htons(publicPort + i), - proto); + link = PacketAliasRedirectPort (localAddr, + htons(localPort + i), + remoteAddr, + htons(remotePortCopy), + publicAddr, + htons(publicPort + i), + proto); } + +/* + * Setup LSNAT server pool. + */ + if (serverPool != NULL && link != NULL) { + ptr = strtok(serverPool, ","); + while (ptr != NULL) { + if (StrToAddrAndPortRange(ptr, &localAddr, protoName, &portRange) != 0) + errx(1, "redirect_port: invalid local port range"); + + localPort = GETLOPORT(portRange); + if (GETNUMPORTS(portRange) != 1) + errx(1, "redirect_port: local port must be single in this context"); + PacketAliasAddServer(link, localAddr, htons(localPort)); + ptr = strtok(NULL, ","); + } + } +} + +void +SetupProtoRedirect(const char* parms) +{ + char buf[128]; + char* ptr; + struct in_addr localAddr; + struct in_addr publicAddr; + struct in_addr remoteAddr; + int proto; + char* protoName; + struct protoent *protoent; + + strcpy (buf, parms); +/* + * Extract protocol. + */ + protoName = strtok(buf, " \t"); + if (!protoName) + errx(1, "redirect_proto: missing protocol"); + + protoent = getprotobyname(protoName); + if (protoent == NULL) + errx(1, "redirect_proto: unknown protocol %s", protoName); + else + proto = protoent->p_proto; +/* + * Extract local address. + */ + ptr = strtok(NULL, " \t"); + if (!ptr) + errx(1, "redirect_proto: missing local address"); + else + StrToAddr(ptr, &localAddr); +/* + * Extract optional public address. + */ + ptr = strtok(NULL, " \t"); + if (ptr) + StrToAddr(ptr, &publicAddr); + else + publicAddr.s_addr = INADDR_ANY; +/* + * Extract optional remote address. + */ + ptr = strtok(NULL, " \t"); + if (ptr) + StrToAddr(ptr, &remoteAddr); + else + remoteAddr.s_addr = INADDR_ANY; +/* + * Create aliasing link. + */ + (void)PacketAliasRedirectProto(localAddr, remoteAddr, publicAddr, + proto); } void SetupAddressRedirect (const char* parms) { char buf[128]; char* ptr; + char* separator; struct in_addr localAddr; struct in_addr publicAddr; + char* serverPool; + struct alias_link *link; strcpy (buf, parms); /* @@ -1464,7 +1590,14 @@ void SetupAddressRedirect (const char* parms) if (!ptr) errx (1, "redirect_address: missing local address"); - StrToAddr (ptr, &localAddr); + separator = strchr(ptr, ','); + if (separator) { /* LSNAT redirection syntax. */ + localAddr.s_addr = INADDR_NONE; + serverPool = ptr; + } else { + StrToAddr (ptr, &localAddr); + serverPool = NULL; + } /* * Extract public address. */ @@ -1473,7 +1606,19 @@ void SetupAddressRedirect (const char* parms) errx (1, "redirect_address: missing public address"); StrToAddr (ptr, &publicAddr); - PacketAliasRedirectAddr (localAddr, publicAddr); + link = PacketAliasRedirectAddr(localAddr, publicAddr); + +/* + * Setup LSNAT server pool. + */ + if (serverPool != NULL && link != NULL) { + ptr = strtok(serverPool, ","); + while (ptr != NULL) { + StrToAddr(ptr, &localAddr); + PacketAliasAddServer(link, localAddr, htons(~0)); + ptr = strtok(NULL, ","); + } + } } void StrToAddr (const char* str, struct in_addr* addr) @@ -1576,3 +1721,15 @@ int StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, p StrToAddr (str, addr); return StrToPortRange (ptr, proto, portRange); } + +static void +SetupPunchFW(const char *strValue) +{ + unsigned int base, num; + + if (sscanf(strValue, "%u:%u", &base, &num) != 2) + errx(1, "punch_fw: basenumber:count parameter required"); + + PacketAliasSetFWBase(base, num); + (void)PacketAliasSetMode(PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); +} diff --git a/natd.tproj/natd.h b/natd.tproj/natd.h index f179cb5..f2c1f26 100644 --- a/natd.tproj/natd.h +++ b/natd.tproj/natd.h @@ -1,3 +1,24 @@ +/* + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * The contents of this file constitute Original Code as defined in and + * are subject to the Apple Public Source License Version 1.1 (the + * "License"). You may not use this file except in compliance with the + * License. Please obtain a copy of the License at + * http://www.apple.com/publicsource and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ /* * natd - Network Address Translation Daemon for FreeBSD. * @@ -9,7 +30,8 @@ * * Ari Suutari * - * $Id: natd.h,v 1.1.1.1 2000/01/11 01:48:51 wsanchez Exp $ + * Based upon: + * $FreeBSD: src/sbin/natd/natd.h,v 1.4 1999/08/28 00:13:46 peter Exp $ */ #define PIDFILE "/var/run/natd.pid" diff --git a/sliplogin.tproj/Makefile b/ndp.tproj/Makefile similarity index 84% rename from sliplogin.tproj/Makefile rename to ndp.tproj/Makefile index b106e74..dfd22fd 100644 --- a/sliplogin.tproj/Makefile +++ b/ndp.tproj/Makefile @@ -7,17 +7,15 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = sliplogin +NAME = ndp PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -HFILES = pathnames.h +CFILES = ndp.c +HFILES = gnuc.h -CFILES = sliplogin.c - -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble sliplogin.8\ - slip.hosts slip.login +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble ndp.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles @@ -26,13 +24,15 @@ MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /usr/sbin WINDOWS_INSTALLDIR = /usr/sbin PDO_UNIX_INSTALLDIR = /usr/sbin -LIBS = +LIBS = -lipsec DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) +NEXTSTEP_BUILD_OUTPUT_DIR = /$(USER)/BUILD + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc diff --git a/ndp.tproj/Makefile.postamble b/ndp.tproj/Makefile.postamble new file mode 100644 index 0000000..630f726 --- /dev/null +++ b/ndp.tproj/Makefile.postamble @@ -0,0 +1,4 @@ +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 ndp.8 "$(DSTROOT)/usr/share/man/man8/ndp.8" + diff --git a/ndp.tproj/Makefile.preamble b/ndp.tproj/Makefile.preamble new file mode 100644 index 0000000..604fd2a --- /dev/null +++ b/ndp.tproj/Makefile.preamble @@ -0,0 +1,4 @@ +OTHER_GENERATED_OFILES = $(VERS_OFILE) +-include ../Makefile.include +LOCAL_CFLAGS= -DINET6 -DIPSEC_DEBUG -DKAME_SCOPEID +AFTER_INSTALL += install-man-page diff --git a/newclient.tproj/PB.project b/ndp.tproj/PB.project similarity index 58% rename from newclient.tproj/PB.project rename to ndp.tproj/PB.project index 08d2bf1..858340b 100644 --- a/newclient.tproj/PB.project +++ b/ndp.tproj/PB.project @@ -1,10 +1,12 @@ { + APPCLASS = NSApplication; FILESTABLE = { - C_FILES = (); - H_FILES = (); + FRAMEWORKS = (); + H_FILES = (gnuc.h); M_FILES = (); - OTHER_LINKED = (); - OTHER_SOURCES = (Makefile, Makefile.preamble, newclient.csh); + OTHER_LIBS = (); + OTHER_LINKED = (ndp.c); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, ndp.8); SUBPROJECTS = (); }; LANGUAGE = English; @@ -13,22 +15,17 @@ NEXTSTEP_BUILDTOOL = /bin/gnumake; NEXTSTEP_INSTALLDIR = /usr/sbin; NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; + NEXTSTEP_MAINNIB = ping6; NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; PDO_UNIX_INSTALLDIR = /usr/sbin; PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; + PDO_UNIX_MAINNIB = ndp; PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = newclient; - PROJECTTYPE = Legacy; + PROJECTNAME = ndp; + PROJECTTYPE = Tool; PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; WINDOWS_INSTALLDIR = /usr/sbin; WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; + WINDOWS_MAINNIB = ndp; WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; } diff --git a/ndp.tproj/gnuc.h b/ndp.tproj/gnuc.h new file mode 100644 index 0000000..5c6b29e --- /dev/null +++ b/ndp.tproj/gnuc.h @@ -0,0 +1,2 @@ +/* $FreeBSD: src/usr.sbin/ndp/gnuc.h,v 1.1 2000/01/06 12:40:40 shin Exp $ */ +/* this is dummy to pacify gmt2local.c. */ diff --git a/ndp.tproj/ndp.8 b/ndp.tproj/ndp.8 new file mode 100644 index 0000000..2ff0c34 --- /dev/null +++ b/ndp.tproj/ndp.8 @@ -0,0 +1,182 @@ +.\" $FreeBSD: src/usr.sbin/ndp/ndp.8,v 1.1.2.6 2001/08/16 15:56:09 ru Exp $ +.\" $KAME: ndp.8,v 1.15 2001/02/08 07:17:03 itojun 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. 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. +.\" +.Dd May 17, 1998 +.Dt NDP 8 +.Os +.\" +.Sh NAME +.Nm ndp +.Nd control/diagnose IPv6 neighbor discovery protocol +.\" +.Sh SYNOPSIS +.Nm +.Fl a +.Op Fl nt +.Nm +.Fl A Ar wait +.Op Fl nt +.Nm +.Fl c +.Op Fl nt +.Nm +.Fl d +.Op Fl nt +.Ar hostname +.Nm +.Fl f +.Op Fl nt +.Ar filename +.Nm +.Fl H +.Nm +.Fl I +.Op Cm delete | Ar interface +.Nm +.Fl i +.Ar interface +.Op Ar flags... +.Nm +.Fl p +.Nm +.Fl P +.Nm +.Fl r +.Nm +.Fl R +.Nm +.Fl s +.Op Fl nt +.Ar nodename +.Ar ether_addr +.Op Li temp +.Op Li proxy +.\" +.Sh DESCRIPTION +The +.Nm +command manipulates the address mapping table +used by Neighbor Discovery Protocol (NDP). +.Bl -tag -width Ds +.It Fl a +Dump the currently existing NDP entries. +.It Fl A Ar wait +Repeat +.Fl a +(dump NDP entries) +every +.Ar wait +seconds. +.It Fl c +Erase all the NDP entries. +.It Fl d +Delete specified NDP entry. +.It Fl f +Parse the file specified by +.Ar filename . +.It Fl H +Harmonize consistency between the routing table and the default router +list; install the top entry of the list into the kernel routing table. +.It Fl I Op Cm delete | Ar interface +Shows or specifies the default interface used as the default route when +there is no default router. +If no argument is given to the option, +the current default interface will be shown. +If an +.Ar interface +is specified, the interface will be used as the default. +If a special keyword +.Ic delete +is specified, the current default interface will be deleted from the kernel. +.It Fl i Ar interface Op Ar flags... +View ND information for the specified interface. +If additional arguments +.Ar flags +are given, +.Nm +sets or clears the specified flags for the interface. +Possible flags are as follows. +All of the flags can begin with the +special character +.Ql - , +which means the flag should be cleared. +.\" +.Bl -tag -width Ds -compact +.It Xo +.Ic nud +.Xc +turn on or off NUD (Neighbor Unreachability Detection) on the +interface. +NUD is usually turned on by default. +.El +.It Fl n +Do not try to resolve numeric address to hostname. +.It Fl p +Show prefix list. +.It Fl P +Flush all the entries in the prefix list. +.It Fl r +Show default router list. +.It Fl R +Flush all the entries in the default router list. +.It Fl s +Register an NDP entry for a node. +The entry will be permanent unless the word +.Li temp +is given in the command. +If the word +.Li proxy +is given, this system will act as an proxy NDP server, +responding to requests for +.Ar hostname +even though the host address is not its own. +.It Fl t +Print timestamp on each entries, +to make it possible to merge output with +.Xr tcpdump 1 . +Most useful when used with +.Fl A . +.El +.\" +.Sh RETURN VALUES +The +.Nm +command will exit with 0 on success, and non-zero on errors. +.\" +.Sh SEE ALSO +.Xr arp 8 +.\" +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" +.\" .Sh BUGS +.\" (to be written) diff --git a/ndp.tproj/ndp.c b/ndp.tproj/ndp.c new file mode 100644 index 0000000..d1a55b7 --- /dev/null +++ b/ndp.tproj/ndp.c @@ -0,0 +1,1528 @@ +/* $FreeBSD: src/usr.sbin/ndp/ndp.c,v 1.2.2.5 2001/08/13 02:58:26 sumikawa Exp $ */ +/* $KAME: ndp.c,v 1.65 2001/05/08 04:36:34 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ +/* + * Copyright (c) 1984, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Sun Microsystems, Inc. + * + * 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. + */ + +/* + * Based on: + * "@(#) Copyright (c) 1984, 1993\n\ + * The Regents of the University of California. All rights reserved.\n"; + * + * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; + */ + +/* + * ndp - display, set, delete and flush neighbor cache + */ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "gmt2local.h" + +#ifndef NI_WITHSCOPEID +#define NI_WITHSCOPEID 0 +#endif + +/* packing rule for routing socket */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + +static int pid; +static int cflag; +static int nflag; +static int tflag; +static int32_t thiszone =0 ; /* time difference with gmt */ +static int s = -1; +static int repeat = 0; + +char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ +char host_buf[NI_MAXHOST]; /* getnameinfo() */ +char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ + +int main __P((int, char **)); +int file __P((char *)); +void getsocket __P((void)); +int set __P((int, char **)); +void get __P((char *)); +int delete __P((char *)); +void dump __P((struct in6_addr *)); +static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, + int ifindex, int)); +static char *ether_str __P((struct sockaddr_dl *)); +int ndp_ether_aton __P((char *, u_char *)); +void usage __P((void)); +int rtmsg __P((int)); +void ifinfo __P((int, char **)); +void rtrlist __P((void)); +void plist __P((void)); +void pfx_flush __P((void)); +void rtrlist __P((void)); +void rtr_flush __P((void)); +void harmonize_rtr __P((void)); +#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ +static void getdefif __P((void)); +static void setdefif __P((char *)); +#endif +static char *sec2str __P((time_t t)); +static char *ether_str __P((struct sockaddr_dl *sdl)); +static void ts_print __P((const struct timeval *)); + +static char *rtpref_str[] = { + "medium", /* 00 */ + "high", /* 01 */ + "rsv", /* 10 */ + "low" /* 11 */ +}; + +int +main(argc, argv) + int argc; + char **argv; +{ + int ch; + int aflag = 0, dflag = 0, sflag = 0, Hflag = 0, + pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; + + pid = getpid(); +// thiszone = gmt2local(0); + while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != -1) + switch ((char)ch) { + case 'a': + aflag = 1; + break; + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'I': +#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ + if (argc > 2) + setdefif(argv[2]); + getdefif(); /* always call it to print the result */ + exit(0); +#else + errx(1, "not supported yet"); + /*NOTREACHED*/ +#endif + case 'i' : + argc -= optind; + argv += optind; + if (argc < 1) + usage(); + ifinfo(argc, argv); + exit(0); + case 'n': + nflag = 1; + continue; + case 'p': + pflag = 1; + break; + case 'f' : + if (argc != 3) + usage(); + file(argv[2]); + exit(0); + case 'l' : + /* obsolete, ignored */ + break; + case 'r' : + rflag = 1; + break; + case 's': + sflag = 1; + break; + case 't': + tflag = 1; + break; + case 'A': + aflag = 1; + repeat = atoi(optarg); + if (repeat < 0) + usage(); + break; + case 'H' : + Hflag = 1; + break; + case 'P': + Pflag = 1; + break; + case 'R': + Rflag = 1; + break; + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (aflag || cflag) { + dump(0); + exit(0); + } + if (dflag) { + if (argc != 1) + usage(); + delete(argv[0]); + exit(0); + } + if (pflag) { + plist(); + exit(0); + } + if (rflag) { + rtrlist(); + exit(0); + } + if (sflag) { + if (argc < 2 || argc > 4) + usage(); + exit(set(argc, argv) ? 1 : 0); + } + if (Hflag) { + harmonize_rtr(); + exit(0); + } + if (Pflag) { + pfx_flush(); + exit(0); + } + if (Rflag) { + rtr_flush(); + exit(0); + } + + if (argc != 1) + usage(); + get(argv[0]); + exit(0); +} + +/* + * Process a file to set standard ndp entries + */ +int +file(name) + char *name; +{ + FILE *fp; + int i, retval; + char line[100], arg[5][50], *args[5]; + + if ((fp = fopen(name, "r")) == NULL) { + fprintf(stderr, "ndp: cannot open %s\n", name); + exit(1); + } + args[0] = &arg[0][0]; + args[1] = &arg[1][0]; + args[2] = &arg[2][0]; + args[3] = &arg[3][0]; + args[4] = &arg[4][0]; + retval = 0; + while(fgets(line, 100, fp) != NULL) { + i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], + arg[3], arg[4]); + if (i < 2) { + fprintf(stderr, "ndp: bad line: %s\n", line); + retval = 1; + continue; + } + if (set(i, args)) + retval = 1; + } + fclose(fp); + return (retval); +} + +void +getsocket() +{ + if (s < 0) { + s = socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) { + perror("ndp: socket"); + exit(1); + } + } +} + +struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; +struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; +struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; +int expire_time, flags, found_entry; +struct { + struct rt_msghdr m_rtm; + char m_space[512]; +} m_rtmsg; + +/* + * Set an individual neighbor cache entry + */ +int +set(argc, argv) + int argc; + char **argv; +{ + register struct sockaddr_in6 *sin = &sin_m; + register struct sockaddr_dl *sdl; + register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); + struct addrinfo hints, *res; + int gai_error; + u_char *ea; + char *host = argv[0], *eaddr = argv[1]; + + getsocket(); + argc -= 2; + argv += 2; + sdl_m = blank_sdl; + sin_m = blank_sin; + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_INET6; + gai_error = getaddrinfo(host, NULL, &hints, &res); + if (gai_error) { + fprintf(stderr, "ndp: %s: %s\n", host, + gai_strerror(gai_error)); + return 1; + } + sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = + htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); + } +#endif + ea = (u_char *)LLADDR(&sdl_m); + if (ndp_ether_aton(eaddr, ea) == 0) + sdl_m.sdl_alen = 6; + flags = expire_time = 0; + while (argc-- > 0) { + if (strncmp(argv[0], "temp", 4) == 0) { + struct timeval time; + gettimeofday(&time, 0); + expire_time = time.tv_sec + 20 * 60; + } else if (strncmp(argv[0], "proxy", 5) == 0) + flags |= RTF_ANNOUNCE; + argv++; + } + if (rtmsg(RTM_GET) < 0) { + perror(host); + return (1); + } + sin = (struct sockaddr_in6 *)(rtm + 1); + sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { + if (sdl->sdl_family == AF_LINK && + (rtm->rtm_flags & RTF_LLINFO) && + !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { + case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: + case IFT_ISO88024: case IFT_ISO88025: + goto overwrite; + } + /* + * IPv4 arp command retries with sin_other = SIN_PROXY here. + */ + fprintf(stderr, "set: cannot configure a new entry\n"); + return 1; + } + +overwrite: + if (sdl->sdl_family != AF_LINK) { + printf("cannot intuit interface index and type for %s\n", host); + return (1); + } + sdl_m.sdl_type = sdl->sdl_type; + sdl_m.sdl_index = sdl->sdl_index; + return (rtmsg(RTM_ADD)); +} + +/* + * Display an individual neighbor cache entry + */ +void +get(host) + char *host; +{ + struct sockaddr_in6 *sin = &sin_m; + struct addrinfo hints, *res; + int gai_error; + + sin_m = blank_sin; + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_INET6; + gai_error = getaddrinfo(host, NULL, &hints, &res); + if (gai_error) { + fprintf(stderr, "ndp: %s: %s\n", host, + gai_strerror(gai_error)); + return; + } + sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = + htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); + } +#endif + dump(&sin->sin6_addr); + if (found_entry == 0) { + getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, + sizeof(host_buf), NULL ,0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + printf("%s (%s) -- no entry\n", host, host_buf); + exit(1); + } +} + +/* + * Delete a neighbor cache entry + */ +int +delete(host) + char *host; +{ + struct sockaddr_in6 *sin = &sin_m; + register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; + struct sockaddr_dl *sdl; + struct addrinfo hints, *res; + int gai_error; + + getsocket(); + sin_m = blank_sin; + + bzero(&hints, sizeof(hints)); + hints.ai_family = AF_INET6; + gai_error = getaddrinfo(host, NULL, &hints, &res); + if (gai_error) { + fprintf(stderr, "ndp: %s: %s\n", host, + gai_strerror(gai_error)); + return 1; + } + sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = + htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); + } +#endif + if (rtmsg(RTM_GET) < 0) { + perror(host); + return (1); + } + sin = (struct sockaddr_in6 *)(rtm + 1); + sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); + if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { + if (sdl->sdl_family == AF_LINK && + (rtm->rtm_flags & RTF_LLINFO) && + !(rtm->rtm_flags & RTF_GATEWAY)) { + goto delete; + } + /* + * IPv4 arp command retries with sin_other = SIN_PROXY here. + */ + fprintf(stderr, "delete: cannot delete non-NDP entry\n"); + return 1; + } + +delete: + if (sdl->sdl_family != AF_LINK) { + printf("cannot locate %s\n", host); + return (1); + } + if (rtmsg(RTM_DELETE) == 0) { + struct sockaddr_in6 s6 = *sin; /* XXX: for safety */ + +#ifdef __KAME__ + if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { + s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]); + *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0; + } +#endif + getnameinfo((struct sockaddr *)&s6, + s6.sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + printf("%s (%s) deleted\n", host, host_buf); + } + + return 0; +} + +#define W_ADDR 31 +#define W_LL 17 +#define W_IF 6 + +/* + * Dump the entire neighbor cache + */ +void +dump(addr) + struct in6_addr *addr; +{ + int mib[6]; + size_t needed; + char *lim, *buf, *next; + struct rt_msghdr *rtm; + struct sockaddr_in6 *sin; + struct sockaddr_dl *sdl; + extern int h_errno; + struct in6_nbrinfo *nbi; + struct timeval time; + int addrwidth; + int llwidth; + int ifwidth; + char flgbuf[8]; + char *ifname; + + /* Print header */ + if (!tflag && !cflag) + printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n", + W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", + W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs"); + +again:; + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET6; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + err(1, "sysctl(PF_ROUTE estimate)"); + if (needed > 0) { + if ((buf = malloc(needed)) == NULL) + errx(1, "malloc"); + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); + lim = buf + needed; + } else + buf = lim = NULL; + + for (next = buf; next && next < lim; next += rtm->rtm_msglen) { + int isrouter = 0, prbs = 0; + + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_in6 *)(rtm + 1); + sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); + + /* + * Some OSes can produce a route that has the LINK flag but + * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD + * and BSD/OS, where xx is not the interface identifier on + * lo0). Such routes entry would annoy getnbrinfo() below, + * so we skip them. + * XXX: such routes should have the GATEWAY flag, not the + * LINK flag. However, there are rotten routing software + * that advertises all routes that have the GATEWAY flag. + * Thus, KAME kernel intentionally does not set the LINK flag. + * What is to be fixed is not ndp, but such routing software + * (and the kernel workaround)... + */ + if (sdl->sdl_family != AF_LINK) + continue; + + if (addr) { + if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) + continue; + found_entry = 1; + } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) + continue; + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { + /* XXX: should scope id be filled in the kernel? */ + if (sin->sin6_scope_id == 0) + sin->sin6_scope_id = sdl->sdl_index; +#ifdef __KAME__ + /* KAME specific hack; removed the embedded id */ + *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; +#endif + } + getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + if (cflag == 1) { +#ifdef RTF_WASCLONED + if (rtm->rtm_flags & RTF_WASCLONED) + delete(host_buf); +#else + delete(host_buf); +#endif + continue; + } + gettimeofday(&time, 0); + if (tflag) + ts_print(&time); + + addrwidth = strlen(host_buf); + if (addrwidth < W_ADDR) + addrwidth = W_ADDR; + llwidth = strlen(ether_str(sdl)); + if (W_ADDR + W_LL - addrwidth > llwidth) + llwidth = W_ADDR + W_LL - addrwidth; + ifname = if_indextoname(sdl->sdl_index, ifix_buf); + if (!ifname) + ifname = "?"; + ifwidth = strlen(ifname); + if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) + ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; + + printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf, + llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); + + /* Print neighbor discovery specific informations */ + nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); + if (nbi) { + if (nbi->expire > time.tv_sec) { + printf(" %-9.9s", + sec2str(nbi->expire - time.tv_sec)); + } else if (nbi->expire == 0) + printf(" %-9.9s", "permanent"); + else + printf(" %-9.9s", "expired"); + + switch(nbi->state) { + case ND6_LLINFO_NOSTATE: + printf(" N"); + break; +#ifdef ND6_LLINFO_WAITDELETE + case ND6_LLINFO_WAITDELETE: + printf(" W"); + break; +#endif + case ND6_LLINFO_INCOMPLETE: + printf(" I"); + break; + case ND6_LLINFO_REACHABLE: + printf(" R"); + break; + case ND6_LLINFO_STALE: + printf(" S"); + break; + case ND6_LLINFO_DELAY: + printf(" D"); + break; + case ND6_LLINFO_PROBE: + printf(" P"); + break; + default: + printf(" ?"); + break; + } + + isrouter = nbi->isrouter; + prbs = nbi->asked; + } else { + warnx("failed to get neighbor information"); + printf(" "); + } + putchar(' '); + + /* + * other flags. R: router, P: proxy, W: ?? + */ + if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { + snprintf(flgbuf, sizeof(flgbuf), "%s%s", + isrouter ? "R" : "", + (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); + } else { + sin = (struct sockaddr_in6 *) + (sdl->sdl_len + (char *)sdl); + snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", + isrouter ? "R" : "", + !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) + ? "P" : "", + (sin->sin6_len != sizeof(struct sockaddr_in6)) + ? "W" : "", + (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); + } + printf(" %-4.4s", flgbuf); + + if (prbs) + printf(" %4d", prbs); + + printf("\n"); + } + if (buf != NULL) + free(buf); + + if (repeat) { + printf("\n"); + sleep(repeat); + goto again; + } +} + +static struct in6_nbrinfo * +getnbrinfo(addr, ifindex, warning) + struct in6_addr *addr; + int ifindex; + int warning; +{ + static struct in6_nbrinfo nbi; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + bzero(&nbi, sizeof(nbi)); + if_indextoname(ifindex, nbi.ifname); + nbi.addr = *addr; + if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { + if (warning) + warn("ioctl(SIOCGNBRINFO_IN6)"); + close(s); + return(NULL); + } + + close(s); + return(&nbi); +} + +static char * +ether_str(sdl) + struct sockaddr_dl *sdl; +{ + static char ebuf[32]; + u_char *cp; + + if (sdl->sdl_alen) { + cp = (u_char *)LLADDR(sdl); + sprintf(ebuf, "%x:%x:%x:%x:%x:%x", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); + } else { + sprintf(ebuf, "(incomplete)"); + } + + return(ebuf); +} + +int +ndp_ether_aton(a, n) + char *a; + u_char *n; +{ + int i, o[6]; + + i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], + &o[3], &o[4], &o[5]); + if (i != 6) { + fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); + return (1); + } + for (i=0; i<6; i++) + n[i] = o[i]; + return (0); +} + +void +usage() +{ + printf("usage: ndp hostname\n"); + printf(" ndp -a[nt]\n"); + printf(" ndp [-nt] -A wait\n"); + printf(" ndp -c[nt]\n"); + printf(" ndp -d[nt] hostname\n"); + printf(" ndp -f[nt] filename\n"); + printf(" ndp -i interface [flags...]\n"); +#ifdef SIOCSDEFIFACE_IN6 + printf(" ndp -I [interface|delete]\n"); +#endif + printf(" ndp -p\n"); + printf(" ndp -r\n"); + printf(" ndp -s hostname ether_addr [temp] [proxy]\n"); + printf(" ndp -H\n"); + printf(" ndp -P\n"); + printf(" ndp -R\n"); + exit(1); +} + +int +rtmsg(cmd) + int cmd; +{ + static int seq; + int rlen; + register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; + register char *cp = m_rtmsg.m_space; + register int l; + + errno = 0; + if (cmd == RTM_DELETE) + goto doit; + bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); + rtm->rtm_flags = flags; + rtm->rtm_version = RTM_VERSION; + + switch (cmd) { + default: + fprintf(stderr, "ndp: internal wrong cmd\n"); + exit(1); + case RTM_ADD: + rtm->rtm_addrs |= RTA_GATEWAY; + rtm->rtm_rmx.rmx_expire = expire_time; + rtm->rtm_inits = RTV_EXPIRE; + rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); + if (rtm->rtm_flags & RTF_ANNOUNCE) { + rtm->rtm_flags &= ~RTF_HOST; + rtm->rtm_flags |= RTA_NETMASK; + } + /* FALLTHROUGH */ + case RTM_GET: + rtm->rtm_addrs |= RTA_DST; + } +#define NEXTADDR(w, s) \ + if (rtm->rtm_addrs & (w)) { \ + bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} + + NEXTADDR(RTA_DST, sin_m); + NEXTADDR(RTA_GATEWAY, sdl_m); + memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); + NEXTADDR(RTA_NETMASK, so_mask); + + rtm->rtm_msglen = cp - (char *)&m_rtmsg; +doit: + l = rtm->rtm_msglen; + rtm->rtm_seq = ++seq; + rtm->rtm_type = cmd; + if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { + if (errno != ESRCH || cmd != RTM_DELETE) { + perror("writing to routing socket"); + return (-1); + } + } + do { + l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); + if (l < 0) + (void) fprintf(stderr, "ndp: read from routing socket: %s\n", + strerror(errno)); + return (0); +} + +void +ifinfo(argc, argv) + int argc; + char **argv; +{ + struct in6_ndireq nd; + int i, s; + char *ifname = argv[0]; + u_int32_t newflags; +#ifdef IPV6CTL_USETEMPADDR + u_int8_t nullbuf[8]; +#endif + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ndp: socket"); + exit(1); + } + bzero(&nd, sizeof(nd)); + strcpy(nd.ifname, ifname); + if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { + perror("ioctl (SIOCGIFINFO_IN6)"); + exit(1); + } +#define ND nd.ndi + newflags = ND.flags; + for (i = 1; i < argc; i++) { + int clear = 0; + char *cp = argv[i]; + + if (*cp == '-') { + clear = 1; + cp++; + } + +#define SETFLAG(s, f) \ + do {\ + if (strcmp(cp, (s)) == 0) {\ + if (clear)\ + newflags &= ~(f);\ + else\ + newflags |= (f);\ + }\ + } while (0) + SETFLAG("nud", ND6_IFF_PERFORMNUD); + + ND.flags = newflags; + if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { + perror("ioctl(SIOCSIFINFO_FLAGS)"); + exit(1); + } +#undef SETFLAG + } + + printf("linkmtu=%d", ND.linkmtu); + printf(", curhlim=%d", ND.chlim); + printf(", basereachable=%ds%dms", + ND.basereachable / 1000, ND.basereachable % 1000); + printf(", reachable=%ds", ND.reachable); + printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); +#ifdef IPV6CTL_USETEMPADDR + memset(nullbuf, 0, sizeof(nullbuf)); + if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { + int j; + u_int8_t *rbuf; + + for (i = 0; i < 3; i++) { + switch(i) { + case 0: + printf("\nRandom seed(0): "); + rbuf = ND.randomseed0; + break; + case 1: + printf("\nRandom seed(1): "); + rbuf = ND.randomseed1; + break; + case 2: + printf("\nRandom ID: "); + rbuf = ND.randomid; + break; + } + for (j = 0; j < 8; j++) + printf("%02x", rbuf[j]); + } + } +#endif + if (ND.flags) { + printf("\nFlags: "); + if ((ND.flags & ND6_IFF_PERFORMNUD) != 0) + printf("PERFORMNUD "); + } + putc('\n', stdout); +#undef ND + + close(s); +} + +#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ +#endif + +void +rtrlist() +{ +#ifdef ICMPV6CTL_ND6_DRLIST + int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; + char *buf; + struct in6_defrouter *p, *ep; + size_t l; + struct timeval time; + + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); + /*NOTREACHED*/ + } + buf = malloc(l); + if (!buf) { + errx(1, "not enough core"); + /*NOTREACHED*/ + } + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); + /*NOTREACHED*/ + } + + ep = (struct in6_defrouter *)(buf + l); + for (p = (struct in6_defrouter *)buf; p < ep; p++) { + int rtpref; + + if (getnameinfo((struct sockaddr *)&p->rtaddr, + p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0) + strlcpy(host_buf, "?", sizeof(host_buf)); + + printf("%s if=%s", host_buf, + if_indextoname(p->if_index, ifix_buf)); + printf(", flags=%s%s", + p->flags & ND_RA_FLAG_MANAGED ? "M" : "", + p->flags & ND_RA_FLAG_OTHER ? "O" : ""); + rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; + printf(", pref=%s", rtpref_str[rtpref]); + + gettimeofday(&time, 0); + if (p->expire == 0) + printf(", expire=Never\n"); + else + printf(", expire=%s\n", + sec2str(p->expire - time.tv_sec)); + } + free(buf); +#else + struct in6_drlist dr; + int s, i; + struct timeval time; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ndp: socket"); + exit(1); + } + bzero(&dr, sizeof(dr)); + strcpy(dr.ifname, "lo0"); /* dummy */ + if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { + perror("ioctl (SIOCGDRLST_IN6)"); + exit(1); + } +#define DR dr.defrouter[i] + for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { + struct sockaddr_in6 sin6; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + sin6.sin6_addr = DR.rtaddr; + getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + + printf("%s if=%s", host_buf, + if_indextoname(DR.if_index, ifix_buf)); + printf(", flags=%s%s", + DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", + DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); + gettimeofday(&time, 0); + if (DR.expire == 0) + printf(", expire=Never\n"); + else + printf(", expire=%s\n", + sec2str(DR.expire - time.tv_sec)); + } +#undef DR + close(s); +#endif +} + +void +plist() +{ +#ifdef ICMPV6CTL_ND6_PRLIST + int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; + char *buf; + struct in6_prefix *p, *ep, *n; + struct sockaddr_in6 *advrtr; + size_t l; + struct timeval time; +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; + int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; + int ninflags = nflag ? NI_NUMERICHOST : 0; +#endif + char namebuf[NI_MAXHOST]; + + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); + /*NOTREACHED*/ + } + buf = malloc(l); + if (!buf) { + errx(1, "not enough core"); + /*NOTREACHED*/ + } + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { + err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); + /*NOTREACHED*/ + } + + ep = (struct in6_prefix *)(buf + l); + for (p = (struct in6_prefix *)buf; p < ep; p = n) { + advrtr = (struct sockaddr_in6 *)(p + 1); + n = (struct in6_prefix *)&advrtr[p->advrtrs]; + + if (getnameinfo((struct sockaddr *)&p->prefix, + p->prefix.sin6_len, namebuf, sizeof(namebuf), + NULL, 0, niflags) != 0) + strlcpy(namebuf, "?", sizeof(namebuf)); + printf("%s/%d if=%s\n", namebuf, p->prefixlen, + if_indextoname(p->if_index, ifix_buf)); + + gettimeofday(&time, 0); + /* + * meaning of fields, especially flags, is very different + * by origin. notify the difference to the users. + */ + printf("flags=%s%s%s%s%s", + p->raflags.onlink ? "L" : "", + p->raflags.autonomous ? "A" : "", + (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", + (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", +#ifdef NDPRF_HOME + (p->flags & NDPRF_HOME) != 0 ? "H" : "" +#else + "" +#endif + ); + if (p->vltime == ND6_INFINITE_LIFETIME) + printf(" vltime=infinity"); + else + printf(" vltime=%ld", (long)p->vltime); + if (p->pltime == ND6_INFINITE_LIFETIME) + printf(", pltime=infinity"); + else + printf(", pltime=%ld", (long)p->pltime); + if (p->expire == 0) + printf(", expire=Never"); + else if (p->expire >= time.tv_sec) + printf(", expire=%s", + sec2str(p->expire - time.tv_sec)); + else + printf(", expired"); + printf(", ref=%d", p->refcnt); + printf("\n"); + /* + * "advertising router" list is meaningful only if the prefix + * information is from RA. + */ + if (p->advrtrs) { + int j; + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)(p + 1); + printf(" advertised by\n"); + for (j = 0; j < p->advrtrs; j++) { + struct in6_nbrinfo *nbi; + + if (getnameinfo((struct sockaddr *)sin6, + sin6->sin6_len, namebuf, sizeof(namebuf), + NULL, 0, ninflags) != 0) + strlcpy(namebuf, "?", sizeof(namebuf)); + printf(" %s", namebuf); + + nbi = getnbrinfo(&sin6->sin6_addr, p->if_index, + 0); + if (nbi) { + switch(nbi->state) { + case ND6_LLINFO_REACHABLE: + case ND6_LLINFO_STALE: + case ND6_LLINFO_DELAY: + case ND6_LLINFO_PROBE: + printf(" (reachable)\n"); + break; + default: + printf(" (unreachable)\n"); + } + } else + printf(" (no neighbor state)\n"); + sin6++; + } + } else + printf(" No advertising router\n"); + } + free(buf); +#else + struct in6_prlist pr; + int s, i; + struct timeval time; + + gettimeofday(&time, 0); + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("ndp: socket"); + exit(1); + } + bzero(&pr, sizeof(pr)); + strcpy(pr.ifname, "lo0"); /* dummy */ + if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { + perror("ioctl (SIOCGPRLST_IN6)"); + exit(1); + } +#define PR pr.prefix[i] + for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { + struct sockaddr_in6 p6; + char namebuf[NI_MAXHOST]; + int niflags; + +#ifdef NDPRF_ONLINK + p6 = PR.prefix; +#else + memset(&p6, 0, sizeof(p6)); + p6.sin6_family = AF_INET6; + p6.sin6_len = sizeof(p6); + p6.sin6_addr = PR.prefix; +#endif + + /* + * copy link index to sin6_scope_id field. + * XXX: KAME specific. + */ + if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) { + u_int16_t linkid; + + memcpy(&linkid, &p6.sin6_addr.s6_addr[2], + sizeof(linkid)); + linkid = ntohs(linkid); + p6.sin6_scope_id = linkid; + p6.sin6_addr.s6_addr[2] = 0; + p6.sin6_addr.s6_addr[3] = 0; + } + + niflags = NI_NUMERICHOST; +#ifdef __KAME__ + niflags |= NI_WITHSCOPEID; +#endif + if (getnameinfo((struct sockaddr *)&p6, + sizeof(p6), namebuf, sizeof(namebuf), + NULL, 0, niflags)) { + warnx("getnameinfo failed"); + continue; + } + printf("%s/%d if=%s\n", namebuf, PR.prefixlen, + if_indextoname(PR.if_index, ifix_buf)); + + gettimeofday(&time, 0); + /* + * meaning of fields, especially flags, is very different + * by origin. notify the difference to the users. + */ +#if 0 + printf(" %s", + PR.origin == PR_ORIG_RA ? "" : "advertise: "); +#endif +#ifdef NDPRF_ONLINK + printf("flags=%s%s%s%s%s", + PR.raflags.onlink ? "L" : "", + PR.raflags.autonomous ? "A" : "", + (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", + (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", +#ifdef NDPRF_HOME + (PR.flags & NDPRF_HOME) != 0 ? "H" : "" +#else + "" +#endif + ); +#else + printf("flags=%s%s", + PR.raflags.onlink ? "L" : "", + PR.raflags.autonomous ? "A" : ""); +#endif + if (PR.vltime == ND6_INFINITE_LIFETIME) + printf(" vltime=infinity"); + else + printf(" vltime=%ld", (long)PR.vltime); + if (PR.pltime == ND6_INFINITE_LIFETIME) + printf(", pltime=infinity"); + else + printf(", pltime=%ld", (long)PR.pltime); + if (PR.expire == 0) + printf(", expire=Never"); + else if (PR.expire >= time.tv_sec) + printf(", expire=%s", + sec2str(PR.expire - time.tv_sec)); + else + printf(", expired"); +#ifdef NDPRF_ONLINK + printf(", ref=%d", PR.refcnt); +#endif +#if 0 + switch (PR.origin) { + case PR_ORIG_RA: + printf(", origin=RA"); + break; + case PR_ORIG_RR: + printf(", origin=RR"); + break; + case PR_ORIG_STATIC: + printf(", origin=static"); + break; + case PR_ORIG_KERNEL: + printf(", origin=kernel"); + break; + default: + printf(", origin=?"); + break; + } +#endif + printf("\n"); + /* + * "advertising router" list is meaningful only if the prefix + * information is from RA. + */ + if (0 && /* prefix origin is almost obsolted */ + PR.origin != PR_ORIG_RA) + ; + else if (PR.advrtrs) { + int j; + printf(" advertised by\n"); + for (j = 0; j < PR.advrtrs; j++) { + struct sockaddr_in6 sin6; + struct in6_nbrinfo *nbi; + + bzero(&sin6, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(sin6); + sin6.sin6_addr = PR.advrtr[j]; + sin6.sin6_scope_id = PR.if_index; /* XXX */ + getnameinfo((struct sockaddr *)&sin6, + sin6.sin6_len, host_buf, + sizeof(host_buf), NULL, 0, + NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); + printf(" %s", host_buf); + + nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index, + 0); + if (nbi) { + switch(nbi->state) { + case ND6_LLINFO_REACHABLE: + case ND6_LLINFO_STALE: + case ND6_LLINFO_DELAY: + case ND6_LLINFO_PROBE: + printf(" (reachable)\n"); + break; + default: + printf(" (unreachable)\n"); + } + } else + printf(" (no neighbor state)\n"); + } + if (PR.advrtrs > DRLSTSIZ) + printf(" and %d routers\n", + PR.advrtrs - DRLSTSIZ); + } else + printf(" No advertising router\n"); + } +#undef PR + close(s); +#endif +} + +void +pfx_flush() +{ + char dummyif[IFNAMSIZ+8]; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + strcpy(dummyif, "lo0"); /* dummy */ + if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) + err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); +} + +void +rtr_flush() +{ + char dummyif[IFNAMSIZ+8]; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + strcpy(dummyif, "lo0"); /* dummy */ + if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) + err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); + + close(s); +} + +void +harmonize_rtr() +{ + char dummyif[IFNAMSIZ+8]; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + strcpy(dummyif, "lo0"); /* dummy */ + if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) + err(1, "ioctl (SIOCSNDFLUSH_IN6)"); + + close(s); +} + +#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ +static void +setdefif(ifname) + char *ifname; +{ + struct in6_ndifreq ndifreq; + unsigned int ifindex; + + if (strcasecmp(ifname, "delete") == 0) + ifindex = 0; + else { + if ((ifindex = if_nametoindex(ifname)) == 0) + err(1, "failed to resolve i/f index for %s", ifname); + } + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + strcpy(ndifreq.ifname, "lo0"); /* dummy */ + ndifreq.ifindex = ifindex; + + if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) + err(1, "ioctl (SIOCSDEFIFACE_IN6)"); + + close(s); +} + +static void +getdefif() +{ + struct in6_ndifreq ndifreq; + char ifname[IFNAMSIZ+8]; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + memset(&ndifreq, 0, sizeof(ndifreq)); + strcpy(ndifreq.ifname, "lo0"); /* dummy */ + + if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) + err(1, "ioctl (SIOCGDEFIFACE_IN6)"); + + if (ndifreq.ifindex == 0) + printf("No default interface.\n"); + else { + if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) + err(1, "failed to resolve ifname for index %lu", + ndifreq.ifindex); + printf("ND default interface = %s\n", ifname); + } + + close(s); +} +#endif + +static char * +sec2str(total) + time_t total; +{ + static char result[256]; + int days, hours, mins, secs; + int first = 1; + char *p = result; + + days = total / 3600 / 24; + hours = (total / 3600) % 24; + mins = (total / 60) % 60; + secs = total % 60; + + if (days) { + first = 0; + p += sprintf(p, "%dd", days); + } + if (!first || hours) { + first = 0; + p += sprintf(p, "%dh", hours); + } + if (!first || mins) { + first = 0; + p += sprintf(p, "%dm", mins); + } + sprintf(p, "%ds", secs); + + return(result); +} + +/* + * Print the timestamp + * from tcpdump/util.c + */ +static void +ts_print(tvp) + const struct timeval *tvp; +{ + int s; + + /* Default */ + s = (tvp->tv_sec + thiszone) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); +} diff --git a/netstat.tproj/Makefile b/netstat.tproj/Makefile index a009e36..dfb70de 100644 --- a/netstat.tproj/Makefile +++ b/netstat.tproj/Makefile @@ -1,5 +1,5 @@ # -# Generated by the NeXT Project Builder. +# Generated by the Apple Project Builder. # # NOTE: Do NOT change this file -- Project Builder maintains it. # @@ -14,7 +14,7 @@ PROJECT_TYPE = Tool HFILES = netstat.h -CFILES = data.c if.c inet.c iso.c main.c mbuf.c mroute.c route.c\ +CFILES = data.c if.c inet.c inet6.c ipsec.c main.c mbuf.c mroute.c mroute6.c route.c\ tp_astring.c unix.c OTHERSRCS = Makefile.preamble Makefile Makefile.postamble netstat.1\ diff --git a/netstat.tproj/Makefile.postamble b/netstat.tproj/Makefile.postamble index 34d448d..25094f8 100644 --- a/netstat.tproj/Makefile.postamble +++ b/netstat.tproj/Makefile.postamble @@ -1,2 +1,6 @@ INSTALL_AS_USER = root -INSTALL_PERMISSIONS =4555 +INSTALL_PERMISSIONS = 4555 + +install-man-page: + install -d $(DSTROOT)/usr/share/man/man1 + install -c -m 444 netstat.1 $(DSTROOT)/usr/share/man/man1/netstat.1 diff --git a/netstat.tproj/Makefile.preamble b/netstat.tproj/Makefile.preamble index cc0d3d0..28e0879 100644 --- a/netstat.tproj/Makefile.preamble +++ b/netstat.tproj/Makefile.preamble @@ -1,4 +1,6 @@ CLEAN_ALL_SUBPROJECTS = YES OTHER_GENERATED_OFILES = $(VERS_OFILE) +OTHER_CFLAGS += -DINET6 -DIPSEC +AFTER_INSTALL += install-man-page -include ../Makefile.include vpath %.c `pwd` diff --git a/netstat.tproj/PB.project b/netstat.tproj/PB.project index 91d9ed6..420a54f 100644 --- a/netstat.tproj/PB.project +++ b/netstat.tproj/PB.project @@ -8,18 +8,7 @@ H_FILES = (netstat.h); LIBRARYSEARCH = (); OTHER_LIBS = (); - OTHER_LINKED = ( - data.c, - if.c, - inet.c, - iso.c, - main.c, - mbuf.c, - mroute.c, - route.c, - tp_astring.c, - unix.c - ); + OTHER_LINKED = (data.c, if.c, inet.c, main.c, mbuf.c, mroute.c, route.c, tp_astring.c, unix.c); OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, netstat.1, DERIVED_FILES); SUBPROJECTS = (); }; diff --git a/netstat.tproj/if.c b/netstat.tproj/if.c index 43be850..0be2dc8 100644 --- a/netstat.tproj/if.c +++ b/netstat.tproj/if.c @@ -36,12 +36,13 @@ static char sccsid[] = "@(#)if.c 8.3 (Berkeley) 4/28/95"; */ static const char rcsid[] = - "$Id: if.c,v 1.1.1.2 2000/01/11 01:48:51 wsanchez Exp $"; + "$Id: if.c,v 1.2 2002/03/05 20:35:13 lindak Exp $"; #endif /* not lint */ #include #include #include +#include #include #include @@ -61,10 +62,6 @@ static const char rcsid[] = #include #include #endif -#ifdef ISO -#include -#include -#endif #include #include @@ -77,23 +74,94 @@ static const char rcsid[] = #define YES 1 #define NO 0 -static void sidewaysintpr __P((u_int, u_long)); -static void catchalarm __P((int)); +static void sidewaysintpr (u_int, u_long); +static void catchalarm (int); + +#ifdef INET6 +char *netname6 (struct sockaddr_in6 *, struct in6_addr *); +static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */ +static int bdg_done; +#endif + +#if 0 +/* print bridge statistics */ +void +bdg_stats(u_long dummy , char *name, int af ) +{ + int i; + size_t slen ; + struct bdg_stats s ; + int mib[4] ; + + slen = sizeof(s); + + mib[0] = CTL_NET ; + mib[1] = PF_LINK ; + mib[2] = IFT_ETHER ; + if (sysctl(mib,4, &s,&slen,NULL,0)==-1) + return ; /* no bridging */ +#ifdef INET6 + if (bdg_done != 0) + return; + else + bdg_done = 1; +#endif + printf("-- Bridging statistics (%s) --\n", name) ; + printf( +"Name In Out Forward Drop Bcast Mcast Local Unknown\n"); + for (i = 0 ; i < 16 ; i++) { + if (s.s[i].name[0]) + printf("%-6s %9ld%9ld%9ld%9ld%9ld%9ld%9ld%9ld\n", + s.s[i].name, + s.s[i].p_in[(int)BDG_IN], + s.s[i].p_in[(int)BDG_OUT], + s.s[i].p_in[(int)BDG_FORWARD], + s.s[i].p_in[(int)BDG_DROP], + s.s[i].p_in[(int)BDG_BCAST], + s.s[i].p_in[(int)BDG_MCAST], + s.s[i].p_in[(int)BDG_LOCAL], + s.s[i].p_in[(int)BDG_UNKNOWN] ); + } +} + +#endif + + +/* + * Display a formatted value, or a '-' in the same space. + */ +static void +show_stat(const char *fmt, int width, u_long value, short showvalue) +{ + char newfmt[32]; + + /* Construct the format string */ + if (showvalue) { + sprintf(newfmt, "%%%d%s", width, fmt); + printf(newfmt, value); + } else { + sprintf(newfmt, "%%%ds", width); + printf(newfmt, "-"); + } +} + + /* * Print a description of the network interfaces. */ void -intpr(interval, ifnetaddr) - int interval; - u_long ifnetaddr; +intpr(int interval, u_long ifnetaddr, void (*pfunc)(char *)) { struct ifnet ifnet; struct ifnethead ifnethead; union { struct ifaddr ifa; struct in_ifaddr in; -#ifdef IPX +#ifdef INET6 + struct in6_ifaddr in6; +#endif +#if 0 struct ipx_ifaddr ipx; #endif #ifdef NS @@ -106,8 +174,19 @@ intpr(interval, ifnetaddr) u_long ifaddraddr; u_long ifaddrfound; u_long ifnetfound; - struct sockaddr *sa; + u_long opackets; + u_long ipackets; + u_long obytes; + u_long ibytes; + u_long oerrors; + u_long ierrors; + u_long collisions; + short timer; + int drops; + struct sockaddr *sa = NULL; char name[32], tname[16]; + short network_layer; + short link_layer; if (ifnetaddr == 0) { printf("ifnet: symbol not defined\n"); @@ -119,47 +198,76 @@ intpr(interval, ifnetaddr) } if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead)) return; - ifnetaddr = (u_long)ifnethead.tqh_first; + ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead); if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) return; - printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s", - "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); - if (bflag) - printf(" %10.10s","Ibytes"); - printf(" %8.8s %5.5s", "Opkts", "Oerrs"); - if (bflag) - printf(" %10.10s","Obytes"); - printf(" %5s", "Coll"); - if (tflag) - printf(" %s", "Time"); - if (dflag) - printf(" %s", "Drop"); - putchar('\n'); + if (!pfunc) { + printf("%-5.5s %-5.5s %-13.13s %-15.15s %8.8s %5.5s", + "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); + if (bflag) + printf(" %10.10s","Ibytes"); + printf(" %8.8s %5.5s", "Opkts", "Oerrs"); + if (bflag) + printf(" %10.10s","Obytes"); + printf(" %5s", "Coll"); + if (tflag) + printf(" %s", "Time"); + if (dflag) + printf(" %s", "Drop"); + putchar('\n'); + } ifaddraddr = 0; while (ifnetaddr || ifaddraddr) { struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif register char *cp; int n, m; + network_layer = 0; + link_layer = 0; + if (ifaddraddr == 0) { ifnetfound = ifnetaddr; if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet) || kread((u_long)ifnet.if_name, tname, 16)) return; tname[15] = '\0'; - ifnetaddr = (u_long)ifnet.if_link.tqe_next; + ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link); snprintf(name, 32, "%s%d", tname, ifnet.if_unit); if (interface != 0 && (strcmp(name, interface) != 0)) continue; cp = index(name, '\0'); + + if (pfunc) { + (*pfunc)(name); + continue; + } + if ((ifnet.if_flags&IFF_UP) == 0) *cp++ = '*'; *cp = '\0'; - ifaddraddr = (u_long)ifnet.if_addrhead.tqh_first; + ifaddraddr = (u_long)TAILQ_FIRST(&ifnet.if_addrhead); } printf("%-5.5s %-5lu ", name, ifnet.if_mtu); ifaddrfound = ifaddraddr; + + /* + * Get the interface stats. These may get + * overriden below on a per-interface basis. + */ + opackets = ifnet.if_opackets; + ipackets = ifnet.if_ipackets; + obytes = ifnet.if_obytes; + ibytes = ifnet.if_ibytes; + oerrors = ifnet.if_oerrors; + ierrors = ifnet.if_ierrors; + collisions = ifnet.if_collisions; + timer = ifnet.if_timer; + drops = ifnet.if_snd.ifq_drops; + if (ifaddraddr == 0) { printf("%-13.13s ", "none"); printf("%-15.15s ", "none"); @@ -170,7 +278,8 @@ intpr(interval, ifnetaddr) } #define CP(x) ((char *)(x)) cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + - CP(&ifaddr); sa = (struct sockaddr *)cp; + CP(&ifaddr); + sa = (struct sockaddr *)cp; switch (sa->sa_family) { case AF_UNSPEC: printf("%-13.13s ", "none"); @@ -193,9 +302,24 @@ intpr(interval, ifnetaddr) #endif printf("%-15.15s ", routename(sin->sin_addr.s_addr)); + + network_layer = 1; break; -#ifdef IPX +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)sa; + printf("%-11.11s ", + netname6(&ifaddr.in6.ia_addr, + &ifaddr.in6.ia_prefixmask.sin6_addr)); + printf("%-17.17s ", + (char *)inet_ntop(AF_INET6, + &sin6->sin6_addr, + ntop_buf, sizeof(ntop_buf))); + network_layer = 1; + break; +#endif /*INET6*/ +#if 0 case AF_IPX: { struct sockaddr_ipx *sipx = @@ -205,14 +329,13 @@ intpr(interval, ifnetaddr) *(union ipx_net *) &net = sipx->sipx_addr.x_net; sprintf(netnum, "%lx", (u_long)ntohl(net)); - printf("ipx:%-8s ", netnum); + printf("ipx:%-8s ", netnum); /* printf("ipx:%-8s ", netname(net, 0L)); */ printf("%-15s ", ipx_phost((struct sockaddr *)sipx)); } break; -#endif -#if 0 + case AF_APPLETALK: printf("atalk:%-12.12s ",atalk_print(sa,0x10) ); printf("%-9.9s ",atalk_print(sa,0x0b) ); @@ -239,10 +362,12 @@ intpr(interval, ifnetaddr) { struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; - cp = (char *)LLADDR(sdl); - n = sdl->sdl_alen; + char linknum[10]; + cp = (char *)LLADDR(sdl); + n = sdl->sdl_alen; + sprintf(linknum, "", sdl->sdl_index); + m = printf("%-11.11s ", linknum); } - m = printf("%-11.11s ", ""); goto hexprint; default: m = printf("(%d)", sa->sa_family); @@ -253,27 +378,54 @@ intpr(interval, ifnetaddr) hexprint: while (--n >= 0) m += printf("%02x%c", *cp++ & 0xff, - n > 0 ? '.' : ' '); + n > 0 ? ':' : ' '); m = 30 - m; while (m-- > 0) putchar(' '); + + link_layer = 1; break; } - ifaddraddr = (u_long)ifaddr.ifa.ifa_link.tqe_next; +#ifndef __APPLE__ + /* + * Fixup the statistics for interfaces that + * update stats for their network addresses + */ + if (network_layer) { + opackets = ifaddr.in.ia_ifa.if_opackets; + ipackets = ifaddr.in.ia_ifa.if_ipackets; + obytes = ifaddr.in.ia_ifa.if_obytes; + ibytes = ifaddr.in.ia_ifa.if_ibytes; + } +#endif + ifaddraddr = (u_long)TAILQ_NEXT(&ifaddr.ifa, ifa_link); + } + + show_stat("lu", 8, ipackets, link_layer|network_layer); + printf(" "); + show_stat("lu", 5, ierrors, link_layer); + printf(" "); + if (bflag) { + show_stat("lu", 10, ibytes, link_layer|network_layer); + printf(" "); + } + show_stat("lu", 8, opackets, link_layer|network_layer); + printf(" "); + show_stat("lu", 5, oerrors, link_layer); + printf(" "); + if (bflag) { + show_stat("lu", 10, obytes, link_layer|network_layer); + printf(" "); + } + show_stat("lu", 5, collisions, link_layer); + if (tflag) { + printf(" "); + show_stat("d", 3, timer, link_layer); + } + if (dflag) { + printf(" "); + show_stat("d", 3, drops, link_layer); } - printf("%8lu %5lu ", - ifnet.if_ipackets, ifnet.if_ierrors); - if (bflag) - printf("%10lu ", ifnet.if_ibytes); - printf("%8lu %5lu ", - ifnet.if_opackets, ifnet.if_oerrors); - if (bflag) - printf("%10lu ", ifnet.if_obytes); - printf("%5lu", ifnet.if_collisions); - if (tflag) - printf(" %3d", ifnet.if_timer); - if (dflag) - printf(" %3d", ifnet.if_snd.ifq_drops); putchar('\n'); if (aflag && ifaddrfound) { /* @@ -284,6 +436,9 @@ intpr(interval, ifnetaddr) union { struct sockaddr sa; struct sockaddr_in in; +#ifdef INET6 + struct sockaddr_in6 in6; +#endif /* INET6 */ struct sockaddr_dl dl; } msa; const char *fmt; @@ -305,9 +460,18 @@ intpr(interval, ifnetaddr) case AF_INET: fmt = routename(msa.in.sin_addr.s_addr); break; - +#ifdef INET6 + case AF_INET6: + printf("%23s %-19.19s(refs: %d)\n", "", + inet_ntop(AF_INET6, + &msa.in6.sin6_addr, + ntop_buf, + sizeof(ntop_buf)), + ifma.ifma_refcount); + break; +#endif /* INET6 */ case AF_LINK: - switch (ifnet.if_type) { + switch (msa.dl.sdl_type) { case IFT_ETHER: case IFT_FDDI: fmt = ether_ntoa( @@ -324,18 +488,18 @@ intpr(interval, ifnetaddr) } } -#define MAXIF 10 struct iftot { + SLIST_ENTRY(iftot) chain; char ift_name[16]; /* interface name */ - u_int ift_ip; /* input packets */ - u_int ift_ie; /* input errors */ - u_int ift_op; /* output packets */ - u_int ift_oe; /* output errors */ - u_int ift_co; /* collisions */ + u_long ift_ip; /* input packets */ + u_long ift_ie; /* input errors */ + u_long ift_op; /* output packets */ + u_long ift_oe; /* output errors */ + u_long ift_co; /* collisions */ u_int ift_dr; /* drops */ - u_int ift_ib; /* input bytes */ - u_int ift_ob; /* output bytes */ -} iftot[MAXIF]; + u_long ift_ib; /* input bytes */ + u_long ift_ob; /* output bytes */ +}; u_char signalled; /* set if alarm goes off "early" */ @@ -347,26 +511,26 @@ u_char signalled; /* set if alarm goes off "early" */ * XXX - should be rewritten to use ifmib(4). */ static void -sidewaysintpr(interval, off) - unsigned interval; - u_long off; +sidewaysintpr(unsigned interval, u_long off) { struct ifnet ifnet; u_long firstifnet; struct ifnethead ifnethead; - register struct iftot *ip, *total; + struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting; register int line; - struct iftot *lastif, *sum, *interesting; int oldmask, first; u_long interesting_off; if (kread(off, (char *)&ifnethead, sizeof ifnethead)) return; - firstifnet = (u_long)ifnethead.tqh_first; + firstifnet = (u_long)TAILQ_FIRST(&ifnethead); + + if ((iftot = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); + } + memset(iftot, 0, sizeof(struct iftot)); - lastif = iftot; - sum = iftot + MAXIF - 1; - total = sum - 1; interesting = NULL; interesting_off = 0; for (off = firstifnet, ip = iftot; off;) { @@ -383,26 +547,30 @@ sidewaysintpr(interval, off) interesting_off = off; } snprintf(ip->ift_name, 16, "(%s)", name);; - ip++; - if (ip >= iftot + MAXIF - 2) - break; - off = (u_long) ifnet.if_link.tqe_next; + if ((ipn = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); + } + memset(ipn, 0, sizeof(struct iftot)); + SLIST_NEXT(ip, chain) = ipn; + ip = ipn; + off = (u_long)TAILQ_NEXT(&ifnet, if_link); + } + if ((total = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); } - lastif = ip; + memset(total, 0, sizeof(struct iftot)); + if ((sum = malloc(sizeof(struct iftot))) == NULL) { + printf("malloc failed\n"); + exit(1); + } + memset(sum, 0, sizeof(struct iftot)); + (void)signal(SIGALRM, catchalarm); signalled = NO; (void)alarm(interval); - for (ip = iftot; ip < iftot + MAXIF; ip++) { - ip->ift_ip = 0; - ip->ift_ie = 0; - ip->ift_ib = 0; - ip->ift_op = 0; - ip->ift_oe = 0; - ip->ift_ob = 0; - ip->ift_co = 0; - ip->ift_dr = 0; - } first = 1; banner: printf("%17s %14s %16s", "input", @@ -451,7 +619,9 @@ loop: sum->ift_ob = 0; sum->ift_co = 0; sum->ift_dr = 0; - for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { + for (off = firstifnet, ip = iftot; + off && SLIST_NEXT(ip, chain) != NULL; + ip = SLIST_NEXT(ip, chain)) { if (kread(off, (char *)&ifnet, sizeof ifnet)) { off = 0; continue; @@ -464,10 +634,10 @@ loop: sum->ift_ob += ifnet.if_obytes; sum->ift_co += ifnet.if_collisions; sum->ift_dr += ifnet.if_snd.ifq_drops; - off = (u_long) ifnet.if_link.tqe_next; + off = (u_long)TAILQ_NEXT(&ifnet, if_link); } if (!first) { - printf("%10u %5u %10u %10u %5u %10u %5u", + printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu", sum->ift_ip - total->ift_ip, sum->ift_ie - total->ift_ie, sum->ift_ib - total->ift_ib, @@ -504,8 +674,7 @@ loop: * Sets a flag to not wait for the alarm. */ static void -catchalarm(signo) - int signo; +catchalarm(int signo ) { signalled = YES; } diff --git a/netstat.tproj/inet.c b/netstat.tproj/inet.c index 37d869f..7200bad 100644 --- a/netstat.tproj/inet.c +++ b/netstat.tproj/inet.c @@ -36,7 +36,7 @@ static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; */ static const char rcsid[] = - "$Id: inet.c,v 1.2 2001/07/31 05:54:11 wsanchez Exp $"; + "$Id: inet.c,v 1.4 2002/06/06 00:18:13 laurent Exp $"; #endif /* not lint */ #include @@ -50,6 +50,9 @@ static const char rcsid[] = #include #include #include +#ifdef INET6 +#include +#endif /* INET6 */ #include #include #include @@ -76,8 +79,12 @@ static const char rcsid[] = #include #include "netstat.h" -char *inetname __P((struct in_addr *)); -void inetprint __P((struct in_addr *, int, char *, int)); +char *inetname (struct in_addr *); +void inetprint (struct in_addr *, int, char *, int); +#ifdef INET6 +extern void inet6print (struct in6_addr *, int, char *, int); +static int udp_done, tcp_done; +#endif /* INET6 */ /* * Print a summary of connections related to an Internet @@ -86,15 +93,14 @@ void inetprint __P((struct in_addr *, int, char *, int)); * -a (all) flag is specified. */ void -protopr(proto, name) - u_long proto; /* for sysctl version we pass proto # */ - char *name; +protopr(u_long proto, /* for sysctl version we pass proto # */ + char *name, int af) { int istcp; static int first = 1; char *buf; const char *mibvar; - struct tcpcb *tp; + struct tcpcb *tp = NULL; struct inpcb *inp; struct xinpgen *xig, *oxig; struct xsocket *so; @@ -103,10 +109,22 @@ protopr(proto, name) istcp = 0; switch (proto) { case IPPROTO_TCP: +#ifdef INET6 + if (tcp_done != 0) + return; + else + tcp_done = 1; +#endif istcp = 1; mibvar = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: +#ifdef INET6 + if (udp_done != 0) + return; + else + udp_done = 1; +#endif mibvar = "net.inet.udp.pcblist"; break; case IPPROTO_DIVERT: @@ -121,7 +139,7 @@ protopr(proto, name) if (errno != ENOENT) warn("sysctl: %s", mibvar); return; - } + } if ((buf = malloc(len)) == 0) { warn("malloc %lu bytes", (u_long)len); return; @@ -131,7 +149,16 @@ protopr(proto, name) free(buf); return; } - + + /* + * Bail-out to avoid logic error in the loop below when + * there is in fact no more control block to process + */ + if (len <= sizeof(struct xinpgen)) { + free(buf); + return; + } + oxig = xig = (struct xinpgen *)buf; for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); xig->xig_len > sizeof(struct xinpgen); @@ -146,28 +173,65 @@ protopr(proto, name) } /* Ignore sockets for protocols other than the desired one. */ - if (so->xso_protocol != proto) + if (so->xso_protocol != (int)proto) continue; /* Ignore PCBs which were freed during copyout. */ if (inp->inp_gencnt > oxig->xig_gen) continue; - if (!aflag && inet_lnaof(inp->inp_laddr) == INADDR_ANY) + if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0) +#ifdef INET6 + || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0) +#endif /* INET6 */ + || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0 +#ifdef INET6 + && (inp->inp_vflag & + INP_IPV6) == 0 +#endif /* INET6 */ + )) + ) + continue; + if (!aflag && + ( + (af == AF_INET && + inet_lnaof(inp->inp_laddr) == INADDR_ANY) +#ifdef INET6 + || (af == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) +#endif /* INET6 */ + || (af == AF_UNSPEC && + (((inp->inp_vflag & INP_IPV4) != 0 && + inet_lnaof(inp->inp_laddr) == INADDR_ANY) +#ifdef INET6 + || ((inp->inp_vflag & INP_IPV6) != 0 && + IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) +#endif + )) + )) continue; if (first) { - printf("Active Internet connections"); - if (aflag) - printf(" (including servers)"); + if (!Lflag) { + printf("Active Internet connections"); + if (aflag) + printf(" (including servers)"); + } else + printf( + "Current listen queue sizes (qlen/incqlen/maxqlen)"); putchar('\n'); if (Aflag) printf("%-8.8s ", "Socket"); - printf(Aflag ? - "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : - "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", - "Proto", "Recv-Q", "Send-Q", - "Local Address", "Foreign Address", "(state)"); + if (Lflag) + printf("%-14.14s %-22.22s\n", + "Listen", "Local Address"); + else + printf((Aflag && !Wflag) ? + "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : + "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", + "Proto", "Recv-Q", "Send-Q", + "Local Address", "Foreign Address", + "(state)"); first = 0; } if (Aflag) { @@ -176,29 +240,92 @@ protopr(proto, name) else printf("%8lx ", (u_long)so->so_pcb); } - printf("%-5.5s %6ld %6ld ", name, so->so_rcv.sb_cc, - so->so_snd.sb_cc); + if (Lflag) + if (so->so_qlimit) { + char buf[15]; + + snprintf(buf, 15, "%d/%d/%d", so->so_qlen, + so->so_incqlen, so->so_qlimit); + printf("%-14.14s ", buf); + } else + continue; + else { + const char *vchar; + +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV6) != 0) + vchar = ((inp->inp_vflag & INP_IPV4) != 0) + ? "46" : "6 "; + else +#endif + vchar = ((inp->inp_vflag & INP_IPV4) != 0) + ? "4 " : " "; + + printf("%-3.3s%-2.2s %6ld %6ld ", name, vchar, + so->so_rcv.sb_cc, + so->so_snd.sb_cc); + } if (nflag) { - inetprint(&inp->inp_laddr, (int)inp->inp_lport, - name, 1); - inetprint(&inp->inp_faddr, (int)inp->inp_fport, - name, 1); + if (inp->inp_vflag & INP_IPV4) { + inetprint(&inp->inp_laddr, (int)inp->inp_lport, + name, 1); + if (!Lflag) + inetprint(&inp->inp_faddr, + (int)inp->inp_fport, name, 1); + } +#ifdef INET6 + else if (inp->inp_vflag & INP_IPV6) { + inet6print(&inp->in6p_laddr, + (int)inp->inp_lport, name, 1); + if (!Lflag) + inet6print(&inp->in6p_faddr, + (int)inp->inp_fport, name, 1); + } /* else nothing printed now */ +#endif /* INET6 */ } else if (inp->inp_flags & INP_ANONPORT) { - inetprint(&inp->inp_laddr, (int)inp->inp_lport, - name, 1); - inetprint(&inp->inp_faddr, (int)inp->inp_fport, - name, 0); + if (inp->inp_vflag & INP_IPV4) { + inetprint(&inp->inp_laddr, (int)inp->inp_lport, + name, 1); + if (!Lflag) + inetprint(&inp->inp_faddr, + (int)inp->inp_fport, name, 0); + } +#ifdef INET6 + else if (inp->inp_vflag & INP_IPV6) { + inet6print(&inp->in6p_laddr, + (int)inp->inp_lport, name, 1); + if (!Lflag) + inet6print(&inp->in6p_faddr, + (int)inp->inp_fport, name, 0); + } /* else nothing printed now */ +#endif /* INET6 */ } else { - inetprint(&inp->inp_laddr, (int)inp->inp_lport, - name, 0); - inetprint(&inp->inp_faddr, (int)inp->inp_fport, - name, inp->inp_lport != inp->inp_fport); + if (inp->inp_vflag & INP_IPV4) { + inetprint(&inp->inp_laddr, (int)inp->inp_lport, + name, 0); + if (!Lflag) + inetprint(&inp->inp_faddr, + (int)inp->inp_fport, name, + inp->inp_lport != + inp->inp_fport); + } +#ifdef INET6 + else if (inp->inp_vflag & INP_IPV6) { + inet6print(&inp->in6p_laddr, + (int)inp->inp_lport, name, 0); + if (!Lflag) + inet6print(&inp->in6p_faddr, + (int)inp->inp_fport, name, + inp->inp_lport != + inp->inp_fport); + } /* else nothing printed now */ +#endif /* INET6 */ } - if (istcp) { + if (istcp && !Lflag) { if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES) - printf(" %d", tp->t_state); + printf("%d", tp->t_state); else { - printf(" %s", tcpstates[tp->t_state]); + printf("%s", tcpstates[tp->t_state]); #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN) /* Show T/TCP `hidden state' */ if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN)) @@ -216,7 +343,7 @@ protopr(proto, name) printf("Some %s sockets may have been created.\n", name); } else { - printf("Some %s sockets may have been created or deleted\n", + printf("Some %s sockets may have been created or deleted", name); } } @@ -227,9 +354,7 @@ protopr(proto, name) * Dump TCP statistics structure. */ void -tcp_stats(off, name) - u_long off; - char *name; +tcp_stats(u_long off , char *name, int af ) { struct tcpstat tcpstat; size_t len = sizeof tcpstat; @@ -239,6 +364,13 @@ tcp_stats(off, name) return; } +#ifdef INET6 + if (tcp_done != 0) + return; + else + tcp_done = 1; +#endif + printf ("%s:\n", name); #define p(f, m) if (tcpstat.f || sflag <= 1) \ @@ -320,9 +452,7 @@ tcp_stats(off, name) * Dump UDP statistics structure. */ void -udp_stats(off, name) - u_long off; - char *name; +udp_stats(u_long off , char *name, int af ) { struct udpstat udpstat; size_t len = sizeof udpstat; @@ -333,6 +463,13 @@ udp_stats(off, name) return; } +#ifdef INET6 + if (udp_done != 0) + return; + else + udp_done = 1; +#endif + printf("%s:\n", name); #define p(f, m) if (udpstat.f || sflag <= 1) \ printf(m, udpstat.f, plural(udpstat.f)) @@ -342,6 +479,9 @@ udp_stats(off, name) p1a(udps_hdrops, "\t%lu with incomplete header\n"); p1a(udps_badlen, "\t%lu with bad data length field\n"); p1a(udps_badsum, "\t%lu with bad checksum\n"); +#ifndef __APPLE__ + p1a(udps_nosum, "\t%lu with no checksum\n"); +#endif p1a(udps_noport, "\t%lu dropped due to no socket\n"); p(udps_noportbcast, "\t%lu broadcast/multicast datagram%s dropped due to no socket\n"); @@ -365,9 +505,7 @@ udp_stats(off, name) * Dump IP statistics structure. */ void -ip_stats(off, name) - u_long off; - char *name; +ip_stats(u_long off , char *name, int af ) { struct ipstat ipstat; size_t len = sizeof ipstat; @@ -388,6 +526,7 @@ ip_stats(off, name) p(ips_badsum, "\t%lu bad header checksum%s\n"); p1a(ips_toosmall, "\t%lu with size smaller than minimum\n"); p1a(ips_tooshort, "\t%lu with data size < data length\n"); + p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n"); p1a(ips_badhlen, "\t%lu with header length < data size\n"); p1a(ips_badlen, "\t%lu with data length < header length\n"); p1a(ips_badoptions, "\t%lu with bad options\n"); @@ -414,6 +553,8 @@ ip_stats(off, name) p(ips_fragmented, "\t%lu output datagram%s fragmented\n"); p(ips_ofragments, "\t%lu fragment%s created\n"); p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n"); + p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n"); + p(ips_badaddr, "\t%lu datagram%s with bad address in header\n"); #undef p #undef p1a } @@ -444,9 +585,7 @@ static char *icmpnames[] = { * Dump ICMP statistics. */ void -icmp_stats(off, name) - u_long off; - char *name; +icmp_stats(u_long off , char *name, int af ) { struct icmpstat icmpstat; int i, first; @@ -512,9 +651,7 @@ icmp_stats(off, name) * Dump IGMP statistics structure. */ void -igmp_stats(off, name) - u_long off; - char *name; +igmp_stats(u_long off , char *name, int af ) { struct igmpstat igmpstat; size_t len = sizeof igmpstat; @@ -547,26 +684,28 @@ igmp_stats(off, name) * Pretty print an Internet address (net address + port). */ void -inetprint(in, port, proto,numeric) - register struct in_addr *in; - int port; - char *proto; - int numeric; +inetprint(struct in_addr *in, int port, char *proto, int numeric_port) { struct servent *sp = 0; char line[80], *cp; int width; - sprintf(line, "%.*s.", (Aflag && !numeric) ? 12 : 16, inetname(in)); + if (Wflag) + sprintf(line, "%s.", inetname(in)); + else + sprintf(line, "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in)); cp = index(line, '\0'); - if (!numeric && port) + if (!numeric_port && port) sp = getservbyport((int)port, proto); if (sp || port == 0) - sprintf(cp, "%.15s", sp ? sp->s_name : "*"); + sprintf(cp, "%.15s ", sp ? sp->s_name : "*"); + else + sprintf(cp, "%d ", ntohs((u_short)port)); + width = (Aflag && !Wflag) ? 18 : 22; + if (Wflag) + printf("%-*s ", width, line); else - sprintf(cp, "%d", ntohs((u_short)port)); - width = Aflag ? 18 : 22; - printf(" %-*.*s", width, width, line); + printf("%-*.*s ", width, width, line); } /* @@ -575,11 +714,10 @@ inetprint(in, port, proto,numeric) * numeric value, otherwise try for symbolic name. */ char * -inetname(inp) - struct in_addr *inp; +inetname(struct in_addr *inp) { register char *cp; - static char line[MAXHOSTNAMELEN + 1]; + static char line[MAXHOSTNAMELEN]; struct hostent *hp; struct netent *np; @@ -597,7 +735,7 @@ inetname(inp) hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET); if (hp) { cp = hp->h_name; - trimdomain(cp); + //### trimdomain(cp, strlen(cp)); } } } diff --git a/netstat.tproj/inet6.c b/netstat.tproj/inet6.c new file mode 100644 index 0000000..8fefbeb --- /dev/null +++ b/netstat.tproj/inet6.c @@ -0,0 +1,1111 @@ +/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */ +/* + * Copyright (c) 1983, 1988, 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. + * + * $FreeBSD: src/usr.bin/netstat/inet6.c,v 1.3.2.9 2001/08/10 09:07:09 ru Exp $ + */ + +#ifndef lint +/* +static char sccsid[] = "@(#)inet6.c 8.4 (Berkeley) 4/20/94"; +*/ +#endif /* not lint */ + +#ifdef INET6 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include "netstat.h" + +#ifdef __APPLE__ +#define __unused +#endif +struct socket sockb; + +char *inet6name (struct in6_addr *); +void inet6print (struct in6_addr *, int, char *, int); + +static char ntop_buf[INET6_ADDRSTRLEN]; + +static char *ip6nh[] = { + "hop by hop", + "ICMP", + "IGMP", + "#3", + "IP", + "#5", + "TCP", + "#7", + "#8", + "#9", + "#10", + "#11", + "#12", + "#13", + "#14", + "#15", + "#16", + "UDP", + "#18", + "#19", + "#20", + "#21", + "IDP", + "#23", + "#24", + "#25", + "#26", + "#27", + "#28", + "TP", + "#30", + "#31", + "#32", + "#33", + "#34", + "#35", + "#36", + "#37", + "#38", + "#39", + "#40", + "IP6", + "#42", + "routing", + "fragment", + "#45", + "#46", + "#47", + "#48", + "#49", + "ESP", + "AH", + "#52", + "#53", + "#54", + "#55", + "#56", + "#57", + "ICMP6", + "no next header", + "destination option", + "#61", + "#62", + "#63", + "#64", + "#65", + "#66", + "#67", + "#68", + "#69", + "#70", + "#71", + "#72", + "#73", + "#74", + "#75", + "#76", + "#77", + "#78", + "#79", + "ISOIP", + "#81", + "#82", + "#83", + "#84", + "#85", + "#86", + "#87", + "#88", + "OSPF", + "#80", + "#91", + "#92", + "#93", + "#94", + "#95", + "#96", + "Ethernet", + "#98", + "#99", + "#100", + "#101", + "#102", + "PIM", + "#104", + "#105", + "#106", + "#107", + "#108", + "#109", + "#110", + "#111", + "#112", + "#113", + "#114", + "#115", + "#116", + "#117", + "#118", + "#119", + "#120", + "#121", + "#122", + "#123", + "#124", + "#125", + "#126", + "#127", + "#128", + "#129", + "#130", + "#131", + "#132", + "#133", + "#134", + "#135", + "#136", + "#137", + "#138", + "#139", + "#140", + "#141", + "#142", + "#143", + "#144", + "#145", + "#146", + "#147", + "#148", + "#149", + "#150", + "#151", + "#152", + "#153", + "#154", + "#155", + "#156", + "#157", + "#158", + "#159", + "#160", + "#161", + "#162", + "#163", + "#164", + "#165", + "#166", + "#167", + "#168", + "#169", + "#170", + "#171", + "#172", + "#173", + "#174", + "#175", + "#176", + "#177", + "#178", + "#179", + "#180", + "#181", + "#182", + "#183", + "#184", + "#185", + "#186", + "#187", + "#188", + "#189", + "#180", + "#191", + "#192", + "#193", + "#194", + "#195", + "#196", + "#197", + "#198", + "#199", + "#200", + "#201", + "#202", + "#203", + "#204", + "#205", + "#206", + "#207", + "#208", + "#209", + "#210", + "#211", + "#212", + "#213", + "#214", + "#215", + "#216", + "#217", + "#218", + "#219", + "#220", + "#221", + "#222", + "#223", + "#224", + "#225", + "#226", + "#227", + "#228", + "#229", + "#230", + "#231", + "#232", + "#233", + "#234", + "#235", + "#236", + "#237", + "#238", + "#239", + "#240", + "#241", + "#242", + "#243", + "#244", + "#245", + "#246", + "#247", + "#248", + "#249", + "#250", + "#251", + "#252", + "#253", + "#254", + "#255", +}; + +/* + * Dump IP6 statistics structure. + */ +void +ip6_stats(u_long off __unused, char *name, int af __unused) +{ + struct ip6stat ip6stat; + int first, i; + int mib[4]; + size_t len; + + mib[0] = CTL_NET; + mib[1] = PF_INET6; + mib[2] = IPPROTO_IPV6; + mib[3] = IPV6CTL_STATS; + + len = sizeof ip6stat; + memset(&ip6stat, 0, len); + if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0) + return; + printf("%s:\n", name); + +#define p(f, m) if (ip6stat.f || sflag <= 1) \ + printf(m, (unsigned long long)ip6stat.f, plural(ip6stat.f)) +#define p1a(f, m) if (ip6stat.f || sflag <= 1) \ + printf(m, (unsigned long long)ip6stat.f) + + p(ip6s_total, "\t%llu total packet%s received\n"); + p1a(ip6s_toosmall, "\t%llu with size smaller than minimum\n"); + p1a(ip6s_tooshort, "\t%llu with data size < data length\n"); + p1a(ip6s_badoptions, "\t%llu with bad options\n"); + p1a(ip6s_badvers, "\t%llu with incorrect version number\n"); + p(ip6s_fragments, "\t%llu fragment%s received\n"); + p(ip6s_fragdropped, "\t%llu fragment%s dropped (dup or out of space)\n"); + p(ip6s_fragtimeout, "\t%llu fragment%s dropped after timeout\n"); + p(ip6s_fragoverflow, "\t%llu fragment%s that exceeded limit\n"); + p(ip6s_reassembled, "\t%llu packet%s reassembled ok\n"); + p(ip6s_delivered, "\t%llu packet%s for this host\n"); + p(ip6s_forward, "\t%llu packet%s forwarded\n"); + p(ip6s_cantforward, "\t%llu packet%s not forwardable\n"); + p(ip6s_redirectsent, "\t%llu redirect%s sent\n"); + p(ip6s_localout, "\t%llu packet%s sent from this host\n"); + p(ip6s_rawout, "\t%llu packet%s sent with fabricated ip header\n"); + p(ip6s_odropped, "\t%llu output packet%s dropped due to no bufs, etc.\n"); + p(ip6s_noroute, "\t%llu output packet%s discarded due to no route\n"); + p(ip6s_fragmented, "\t%llu output datagram%s fragmented\n"); + p(ip6s_ofragments, "\t%llu fragment%s created\n"); + p(ip6s_cantfrag, "\t%llu datagram%s that can't be fragmented\n"); + p(ip6s_badscope, "\t%llu packet%s that violated scope rules\n"); + p(ip6s_notmember, "\t%llu multicast packet%s which we don't join\n"); + for (first = 1, i = 0; i < 256; i++) + if (ip6stat.ip6s_nxthist[i] != 0) { + if (first) { + printf("\tInput histogram:\n"); + first = 0; + } + printf("\t\t%s: %llu\n", ip6nh[i], + (unsigned long long)ip6stat.ip6s_nxthist[i]); + } + printf("\tMbuf statistics:\n"); + printf("\t\t%llu one mbuf\n", (unsigned long long)ip6stat.ip6s_m1); + for (first = 1, i = 0; i < 32; i++) { + char ifbuf[IFNAMSIZ]; + if (ip6stat.ip6s_m2m[i] != 0) { + if (first) { + printf("\t\ttwo or more mbuf:\n"); + first = 0; + } + printf("\t\t\t%s= %llu\n", + if_indextoname(i, ifbuf), + (unsigned long long)ip6stat.ip6s_m2m[i]); + } + } + printf("\t\t%llu one ext mbuf\n", + (unsigned long long)ip6stat.ip6s_mext1); + printf("\t\t%llu two or more ext mbuf\n", + (unsigned long long)ip6stat.ip6s_mext2m); + p(ip6s_exthdrtoolong, + "\t%llu packet%s whose headers are not continuous\n"); + p(ip6s_nogif, "\t%llu tunneling packet%s that can't find gif\n"); + p(ip6s_toomanyhdr, + "\t%llu packet%s discarded due to too may headers\n"); + + /* for debugging source address selection */ +#define PRINT_SCOPESTAT(s,i) do {\ + switch(i) { /* XXX hardcoding in each case */\ + case 1:\ + p(s, "\t\t%llu node-local%s\n");\ + break;\ + case 2:\ + p(s,"\t\t%llu link-local%s\n");\ + break;\ + case 5:\ + p(s,"\t\t%llu site-local%s\n");\ + break;\ + case 14:\ + p(s,"\t\t%llu global%s\n");\ + break;\ + default:\ + printf("\t\t%llu addresses scope=%x\n",\ + (unsigned long long)ip6stat.s, i);\ + }\ + } while (0); + + p(ip6s_sources_none, + "\t%llu failure%s of source address selection\n"); + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_sameif[i]) { + if (first) { + printf("\tsource addresses on an outgoing I/F\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_sameif[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_otherif[i]) { + if (first) { + printf("\tsource addresses on a non-outgoing I/F\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_otherif[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_samescope[i]) { + if (first) { + printf("\tsource addresses of same scope\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_samescope[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_otherscope[i]) { + if (first) { + printf("\tsource addresses of a different scope\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i); + } + } + for (first = 1, i = 0; i < 16; i++) { + if (ip6stat.ip6s_sources_deprecated[i]) { + if (first) { + printf("\tdeprecated source addresses\n"); + first = 0; + } + PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i); + } + } + + p1a(ip6s_forward_cachehit, "\t%llu forward cache hit\n"); + p1a(ip6s_forward_cachemiss, "\t%llu forward cache miss\n"); +#undef p +#undef p1a +} + +/* + * Dump IPv6 per-interface statistics based on RFC 2465. + */ +void +ip6_ifstats(char *ifname) +{ + struct in6_ifreq ifr; + int s; +#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ + printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f)) +#define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \ + printf(m, (unsigned long long)ip6stat.f) + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("Warning: socket(AF_INET6)"); + return; + } + + strcpy(ifr.ifr_name, ifname); + printf("ip6 on %s:\n", ifr.ifr_name); + + if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) { + perror("Warning: ioctl(SIOCGIFSTAT_IN6)"); + goto end; + } + + p(ifs6_in_receive, "\t%llu total input datagram%s\n"); + p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n"); + p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n"); + p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n"); + p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n"); + p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n"); + p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n"); + p(ifs6_in_discard, "\t%llu input datagram%s discarded\n"); + p(ifs6_in_deliver, + "\t%llu datagram%s delivered to an upper layer protocol\n"); + p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n"); + p(ifs6_out_request, + "\t%llu datagram%s sent from an upper layer protocol\n"); + p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n"); + p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n"); + p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n"); + p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n"); + p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n"); + p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n"); + p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n"); + p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n"); + p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n"); + + end: + close(s); + +#undef p +#undef p_5 +} + +static char *icmp6names[] = { + "#0", + "unreach", + "packet too big", + "time exceed", + "parameter problem", + "#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", + "#30", + "#31", + "#32", + "#33", + "#34", + "#35", + "#36", + "#37", + "#38", + "#39", + "#40", + "#41", + "#42", + "#43", + "#44", + "#45", + "#46", + "#47", + "#48", + "#49", + "#50", + "#51", + "#52", + "#53", + "#54", + "#55", + "#56", + "#57", + "#58", + "#59", + "#60", + "#61", + "#62", + "#63", + "#64", + "#65", + "#66", + "#67", + "#68", + "#69", + "#70", + "#71", + "#72", + "#73", + "#74", + "#75", + "#76", + "#77", + "#78", + "#79", + "#80", + "#81", + "#82", + "#83", + "#84", + "#85", + "#86", + "#87", + "#88", + "#89", + "#80", + "#91", + "#92", + "#93", + "#94", + "#95", + "#96", + "#97", + "#98", + "#99", + "#100", + "#101", + "#102", + "#103", + "#104", + "#105", + "#106", + "#107", + "#108", + "#109", + "#110", + "#111", + "#112", + "#113", + "#114", + "#115", + "#116", + "#117", + "#118", + "#119", + "#120", + "#121", + "#122", + "#123", + "#124", + "#125", + "#126", + "#127", + "echo", + "echo reply", + "multicast listener query", + "multicast listener report", + "multicast listener done", + "router solicitation", + "router advertisement", + "neighbor solicitation", + "neighbor advertisement", + "redirect", + "router renumbering", + "node information request", + "node information reply", + "inverse neighbor solicitation", + "inverse neighbor advertisement", + "#143", + "#144", + "#145", + "#146", + "#147", + "#148", + "#149", + "#150", + "#151", + "#152", + "#153", + "#154", + "#155", + "#156", + "#157", + "#158", + "#159", + "#160", + "#161", + "#162", + "#163", + "#164", + "#165", + "#166", + "#167", + "#168", + "#169", + "#170", + "#171", + "#172", + "#173", + "#174", + "#175", + "#176", + "#177", + "#178", + "#179", + "#180", + "#181", + "#182", + "#183", + "#184", + "#185", + "#186", + "#187", + "#188", + "#189", + "#180", + "#191", + "#192", + "#193", + "#194", + "#195", + "#196", + "#197", + "#198", + "#199", + "#200", + "#201", + "#202", + "#203", + "#204", + "#205", + "#206", + "#207", + "#208", + "#209", + "#210", + "#211", + "#212", + "#213", + "#214", + "#215", + "#216", + "#217", + "#218", + "#219", + "#220", + "#221", + "#222", + "#223", + "#224", + "#225", + "#226", + "#227", + "#228", + "#229", + "#230", + "#231", + "#232", + "#233", + "#234", + "#235", + "#236", + "#237", + "#238", + "#239", + "#240", + "#241", + "#242", + "#243", + "#244", + "#245", + "#246", + "#247", + "#248", + "#249", + "#250", + "#251", + "#252", + "#253", + "#254", + "#255", +}; + +/* + * Dump ICMP6 statistics. + */ +void +icmp6_stats(u_long off __unused, char *name, int af __unused) +{ + struct icmp6stat icmp6stat; + register int i, first; + int mib[4]; + size_t len; + + mib[0] = CTL_NET; + mib[1] = PF_INET6; + mib[2] = IPPROTO_ICMPV6; + mib[3] = ICMPV6CTL_STATS; + + len = sizeof icmp6stat; + memset(&icmp6stat, 0, len); + if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0) + return; + printf("%s:\n", name); + +#define p(f, m) if (icmp6stat.f || sflag <= 1) \ + printf(m, (unsigned long long)icmp6stat.f, plural(icmp6stat.f)) +#define p_5(f, m) printf(m, (unsigned long long)icmp6stat.f) + + p(icp6s_error, "\t%llu call%s to icmp_error\n"); + p(icp6s_canterror, + "\t%llu error%s not generated because old message was icmp error or so\n"); + p(icp6s_toofreq, + "\t%llu error%s not generated because rate limitation\n"); +#define NELEM (sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0])) + for (first = 1, i = 0; i < NELEM; i++) + if (icmp6stat.icp6s_outhist[i] != 0) { + if (first) { + printf("\tOutput histogram:\n"); + first = 0; + } + printf("\t\t%s: %llu\n", icmp6names[i], + (unsigned long long)icmp6stat.icp6s_outhist[i]); + } +#undef NELEM + p(icp6s_badcode, "\t%llu message%s with bad code fields\n"); + p(icp6s_tooshort, "\t%llu message%s < minimum length\n"); + p(icp6s_checksum, "\t%llu bad checksum%s\n"); + p(icp6s_badlen, "\t%llu message%s with bad length\n"); +#define NELEM (sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0])) + for (first = 1, i = 0; i < NELEM; i++) + if (icmp6stat.icp6s_inhist[i] != 0) { + if (first) { + printf("\tInput histogram:\n"); + first = 0; + } + printf("\t\t%s: %llu\n", icmp6names[i], + (unsigned long long)icmp6stat.icp6s_inhist[i]); + } +#undef NELEM + printf("\tHistogram of error messages to be generated:\n"); + p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n"); + p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n"); + p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n"); + p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n"); + p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n"); + p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n"); + p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n"); + p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n"); + p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n"); + p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n"); + p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n"); + p_5(icp6s_oredirect, "\t\t%llu redirect\n"); + p_5(icp6s_ounknown, "\t\t%llu unknown\n"); + + p(icp6s_reflect, "\t%llu message response%s generated\n"); + p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n"); + p(icp6s_nd_badopt, "\t%qu message%s with bad ND options\n"); + p(icp6s_badns, "\t%qu bad neighbor solicitation message%s\n"); + p(icp6s_badna, "\t%qu bad neighbor advertisement message%s\n"); + p(icp6s_badrs, "\t%qu bad router solicitation message%s\n"); + p(icp6s_badra, "\t%qu bad router advertisement message%s\n"); + p(icp6s_badredirect, "\t%qu bad redirect message%s\n"); + p(icp6s_pmtuchg, "\t%llu path MTU change%s\n"); +#undef p +#undef p_5 +} + +/* + * Dump ICMPv6 per-interface statistics based on RFC 2466. + */ +void +icmp6_ifstats(char *ifname) +{ + struct in6_ifreq ifr; + int s; +#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \ + printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f)) + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("Warning: socket(AF_INET6)"); + return; + } + + strcpy(ifr.ifr_name, ifname); + printf("icmp6 on %s:\n", ifr.ifr_name); + + if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) { + perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)"); + goto end; + } + + p(ifs6_in_msg, "\t%llu total input message%s\n"); + p(ifs6_in_error, "\t%llu total input error message%s\n"); + p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n"); + p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n"); + p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n"); + p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n"); + p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n"); + p(ifs6_in_echo, "\t%llu input echo request%s\n"); + p(ifs6_in_echoreply, "\t%llu input echo reply%s\n"); + p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n"); + p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n"); + p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n"); + p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n"); + p(ifs6_in_redirect, "\t%llu input redirect%s\n"); + p(ifs6_in_mldquery, "\t%llu input MLD query%s\n"); + p(ifs6_in_mldreport, "\t%llu input MLD report%s\n"); + p(ifs6_in_mlddone, "\t%llu input MLD done%s\n"); + + p(ifs6_out_msg, "\t%llu total output message%s\n"); + p(ifs6_out_error, "\t%llu total output error message%s\n"); + p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n"); + p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n"); + p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n"); + p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n"); + p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n"); + p(ifs6_out_echo, "\t%llu output echo request%s\n"); + p(ifs6_out_echoreply, "\t%llu output echo reply%s\n"); + p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n"); + p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n"); + p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n"); + p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n"); + p(ifs6_out_redirect, "\t%llu output redirect%s\n"); + p(ifs6_out_mldquery, "\t%llu output MLD query%s\n"); + p(ifs6_out_mldreport, "\t%llu output MLD report%s\n"); + p(ifs6_out_mlddone, "\t%llu output MLD done%s\n"); + + end: + close(s); +#undef p +} + +/* + * Dump PIM statistics structure. + */ +void +pim6_stats(u_long off __unused, char *name, int af __unused) +{ + struct pim6stat pim6stat; + + if (off == 0) + return; + kread(off, (char *)&pim6stat, sizeof(pim6stat)); + printf("%s:\n", name); + +#define p(f, m) if (pim6stat.f || sflag <= 1) \ + printf(m, (unsigned long long)pim6stat.f, plural(pim6stat.f)) + p(pim6s_rcv_total, "\t%llu message%s received\n"); + p(pim6s_rcv_tooshort, "\t%llu message%s received with too few bytes\n"); + p(pim6s_rcv_badsum, "\t%llu message%s received with bad checksum\n"); + p(pim6s_rcv_badversion, "\t%llu message%s received with bad version\n"); + p(pim6s_rcv_registers, "\t%llu register%s received\n"); + p(pim6s_rcv_badregisters, "\t%llu bad register%s received\n"); + p(pim6s_snd_registers, "\t%llu register%s sent\n"); +#undef p +} + +/* + * Dump raw ip6 statistics structure. + */ +void +rip6_stats(u_long off __unused, char *name, int af __unused) +{ + struct rip6stat rip6stat; + u_quad_t delivered; + int mib[4]; + size_t l; + + mib[0] = CTL_NET; + mib[1] = PF_INET6; + mib[2] = IPPROTO_IPV6; + mib[3] = IPV6CTL_RIP6STATS; + l = sizeof(rip6stat); + if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) { + perror("Warning: sysctl(net.inet6.ip6.rip6stats)"); + return; + } + + printf("%s:\n", name); + +#define p(f, m) if (rip6stat.f || sflag <= 1) \ + printf(m, (unsigned long long)rip6stat.f, plural(rip6stat.f)) + p(rip6s_ipackets, "\t%llu message%s received\n"); + p(rip6s_isum, "\t%llu checksum calcuration%s on inbound\n"); + p(rip6s_badsum, "\t%llu message%s with bad checksum\n"); + p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n"); + p(rip6s_nosockmcast, + "\t%llu multicast message%s dropped due to no socket\n"); + p(rip6s_fullsock, + "\t%llu message%s dropped due to full socket buffers\n"); + delivered = rip6stat.rip6s_ipackets - + rip6stat.rip6s_badsum - + rip6stat.rip6s_nosock - + rip6stat.rip6s_nosockmcast - + rip6stat.rip6s_fullsock; + if (delivered || sflag <= 1) + printf("\t%llu delivered\n", (unsigned long long)delivered); + p(rip6s_opackets, "\t%llu datagram%s output\n"); +#undef p +} + +/* + * Pretty print an Internet address (net address + port). + * If the nflag was specified, use numbers instead of names. + */ +#define GETSERVBYPORT6(port, proto, ret)\ +{\ + if (strcmp((proto), "tcp6") == 0)\ + (ret) = getservbyport((int)(port), "tcp");\ + else if (strcmp((proto), "udp6") == 0)\ + (ret) = getservbyport((int)(port), "udp");\ + else\ + (ret) = getservbyport((int)(port), (proto));\ +}; + +void +inet6print(struct in6_addr *in6, int port, char *proto, int numeric) +{ + struct servent *sp = 0; + char line[80], *cp; + int width; + + sprintf(line, "%.*s.", lflag ? 39 : + (Aflag && !numeric) ? 12 : 16, inet6name(in6)); + cp = index(line, '\0'); + if (!numeric && port) + GETSERVBYPORT6(port, proto, sp); + if (sp || port == 0) + sprintf(cp, "%.8s", sp ? sp->s_name : "*"); + else + sprintf(cp, "%d", ntohs((u_short)port)); + width = lflag ? 45 : Aflag ? 18 : 22; + printf("%-*.*s ", width, width, line); +} + +/* + * Construct an Internet address representation. + * If the nflag has been supplied, give + * numeric value, otherwise try for symbolic name. + */ + +char * +inet6name(struct in6_addr *in6p) +{ + register char *cp; + static char line[50]; + struct hostent *hp; + static char domain[MAXHOSTNAMELEN]; + static int first = 1; + + if (first && !nflag) { + first = 0; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = index(domain, '.'))) + (void) strcpy(domain, cp + 1); + else + domain[0] = 0; + } + cp = 0; + if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) { + hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6); + if (hp) { + if ((cp = index(hp->h_name, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = hp->h_name; + } + } + if (IN6_IS_ADDR_UNSPECIFIED(in6p)) + strcpy(line, "*"); + else if (cp) + strcpy(line, cp); + else + sprintf(line, "%s", + inet_ntop(AF_INET6, (void *)in6p, ntop_buf, + sizeof(ntop_buf))); + return (line); +} +#endif /*INET6*/ diff --git a/netstat.tproj/ipsec.c b/netstat.tproj/ipsec.c new file mode 100644 index 0000000..b686f97 --- /dev/null +++ b/netstat.tproj/ipsec.c @@ -0,0 +1,328 @@ +/* $FreeBSD: src/usr.bin/netstat/ipsec.c,v 1.1.2.3 2001/08/10 09:07:09 ru Exp $ */ +/* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */ +/* $KAME: ipsec.c,v 1.25 2001/03/12 09:04:39 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +/* + * Copyright (c) 1983, 1988, 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. + */ + +#include +#ifndef lint +/* +static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95"; +*/ +static const char rcsid[] = + "$FreeBSD: src/usr.bin/netstat/ipsec.c,v 1.1.2.3 2001/08/10 09:07:09 ru Exp $"; +#endif /* not lint */ + +#include +#include +#include + +#include + +#ifdef IPSEC +#include +#include +#endif + +#include +#include +#include +#include "netstat.h" + +#ifdef __APPLE__ +#define __unused +#endif +/* + * portability issues: + * - bsdi[34] uses PLURAL(), not plural(). + * - freebsd2 can't print "unsigned long long" properly. + */ +/* + * XXX see PORTABILITY for the twist + */ +#define LLU "%llu" +#define CAST unsigned long long + +#ifdef IPSEC +struct val2str { + int val; + const char *str; +}; + +static struct val2str ipsec_ahnames[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, +#endif + { -1, NULL }, +}; + +static struct val2str ipsec_espnames[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, +#ifdef SADB_X_EALG_RC5CBC + { SADB_X_EALG_RC5CBC, "rc5-cbc", }, +#endif + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_RIJNDAELCBC + { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, +#endif + { -1, NULL }, +}; + +static struct val2str ipsec_compnames[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL }, +}; + +static const char *pfkey_msgtypenames[] = { + "reserved", "getspi", "update", "add", "delete", + "get", "acquire", "register", "expire", "flush", + "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd", + "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush", + "x_spdsetidx", "x_spdexpire", "x_spddelete2" +}; + +static struct ipsecstat ipsecstat; + +static void print_ipsecstats (void); +static const char *pfkey_msgtype_names (int); +static void ipsec_hist (const u_quad_t *, size_t, const struct val2str *, + const char *); + +/* + * Dump IPSEC statistics structure. + */ +static void +ipsec_hist(const u_quad_t *hist, + size_t histmax, + const struct val2str *name, + const char *title) +{ + int first; + size_t proto; + const struct val2str *p; + + first = 1; + for (proto = 0; proto < histmax; proto++) { + if (hist[proto] <= 0) + continue; + if (first) { + printf("\t%s histogram:\n", title); + first = 0; + } + for (p = name; p && p->str; p++) { + if (p->val == (int)proto) + break; + } + if (p && p->str) { + printf("\t\t%s: " LLU "\n", p->str, (CAST)hist[proto]); + } else { + printf("\t\t#%ld: " LLU "\n", (long)proto, + (CAST)hist[proto]); + } + } +} + +static void +print_ipsecstats(void) +{ +#define p(f, m) if (ipsecstat.f || sflag <= 1) \ + printf(m, (CAST)ipsecstat.f, plural(ipsecstat.f)) +#define hist(f, n, t) \ + ipsec_hist((f), sizeof(f)/sizeof(f[0]), (n), (t)); + + p(in_success, "\t" LLU " inbound packet%s processed successfully\n"); + p(in_polvio, "\t" LLU " inbound packet%s violated process security " + "policy\n"); + p(in_nosa, "\t" LLU " inbound packet%s with no SA available\n"); + p(in_inval, "\t" LLU " invalid inbound packet%s\n"); + p(in_nomem, "\t" LLU " inbound packet%s failed due to insufficient memory\n"); + p(in_badspi, "\t" LLU " inbound packet%s failed getting SPI\n"); + p(in_ahreplay, "\t" LLU " inbound packet%s failed on AH replay check\n"); + p(in_espreplay, "\t" LLU " inbound packet%s failed on ESP replay check\n"); + p(in_ahauthsucc, "\t" LLU " inbound packet%s considered authentic\n"); + p(in_ahauthfail, "\t" LLU " inbound packet%s failed on authentication\n"); + hist(ipsecstat.in_ahhist, ipsec_ahnames, "AH input"); + hist(ipsecstat.in_esphist, ipsec_espnames, "ESP input"); + hist(ipsecstat.in_comphist, ipsec_compnames, "IPComp input"); + + p(out_success, "\t" LLU " outbound packet%s processed successfully\n"); + p(out_polvio, "\t" LLU " outbound packet%s violated process security " + "policy\n"); + p(out_nosa, "\t" LLU " outbound packet%s with no SA available\n"); + p(out_inval, "\t" LLU " invalid outbound packet%s\n"); + p(out_nomem, "\t" LLU " outbound packet%s failed due to insufficient memory\n"); + p(out_noroute, "\t" LLU " outbound packet%s with no route\n"); + hist(ipsecstat.out_ahhist, ipsec_ahnames, "AH output"); + hist(ipsecstat.out_esphist, ipsec_espnames, "ESP output"); + hist(ipsecstat.out_comphist, ipsec_compnames, "IPComp output"); +#undef p +#undef hist +} + +void +ipsec_stats(u_long off __unused, char *name, int af __unused) +{ + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&ipsecstat, sizeof (ipsecstat)); + + print_ipsecstats(); +} + +static const char * +pfkey_msgtype_names(int x) +{ + const int max = + sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]); + static char buf[10]; + + if (x < max && pfkey_msgtypenames[x]) + return pfkey_msgtypenames[x]; + snprintf(buf, sizeof(buf), "#%d", x); + return buf; +} + +void +pfkey_stats(u_long off __unused, char *name, int af __unused) +{ + struct pfkeystat pfkeystat; + unsigned first, type; + + if (off == 0) + return; + printf ("%s:\n", name); + kread(off, (char *)&pfkeystat, sizeof(pfkeystat)); + +#define p(f, m) if (pfkeystat.f || sflag <= 1) \ + printf(m, (CAST)pfkeystat.f, plural(pfkeystat.f)) + + /* kernel -> userland */ + p(out_total, "\t" LLU " request%s sent to userland\n"); + p(out_bytes, "\t" LLU " byte%s sent to userland\n"); + for (first = 1, type = 0; + type < sizeof(pfkeystat.out_msgtype)/sizeof(pfkeystat.out_msgtype[0]); + type++) { + if (pfkeystat.out_msgtype[type] <= 0) + continue; + if (first) { + printf("\thistogram by message type:\n"); + first = 0; + } + printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type), + (CAST)pfkeystat.out_msgtype[type]); + } + p(out_invlen, "\t" LLU " message%s with invalid length field\n"); + p(out_invver, "\t" LLU " message%s with invalid version field\n"); + p(out_invmsgtype, "\t" LLU " message%s with invalid message type field\n"); + p(out_tooshort, "\t" LLU " message%s too short\n"); + p(out_nomem, "\t" LLU " message%s with memory allocation failure\n"); + p(out_dupext, "\t" LLU " message%s with duplicate extension\n"); + p(out_invexttype, "\t" LLU " message%s with invalid extension type\n"); + p(out_invsatype, "\t" LLU " message%s with invalid sa type\n"); + p(out_invaddr, "\t" LLU " message%s with invalid address extension\n"); + + /* userland -> kernel */ + p(in_total, "\t" LLU " request%s sent from userland\n"); + p(in_bytes, "\t" LLU " byte%s sent from userland\n"); + for (first = 1, type = 0; + type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]); + type++) { + if (pfkeystat.in_msgtype[type] <= 0) + continue; + if (first) { + printf("\thistogram by message type:\n"); + first = 0; + } + printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type), + (CAST)pfkeystat.in_msgtype[type]); + } + p(in_msgtarget[KEY_SENDUP_ONE], + "\t" LLU " message%s toward single socket\n"); + p(in_msgtarget[KEY_SENDUP_ALL], + "\t" LLU " message%s toward all sockets\n"); + p(in_msgtarget[KEY_SENDUP_REGISTERED], + "\t" LLU " message%s toward registered sockets\n"); + p(in_nomem, "\t" LLU " message%s with memory allocation failure\n"); +#undef p +} +#endif /*IPSEC*/ diff --git a/netstat.tproj/iso.c b/netstat.tproj/iso.c deleted file mode 100644 index 526e790..0000000 --- a/netstat.tproj/iso.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1983, 1988, 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. - */ - -#ifndef lint -static char sccsid[] = "@(#)iso.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -/* - * $Header: /cvs/Darwin/Commands/NeXT/network_cmds/netstat.tproj/iso.c,v 1.1.1.2 2000/01/11 01:48:52 wsanchez Exp $ - * $Source: /cvs/Darwin/Commands/NeXT/network_cmds/netstat.tproj/iso.c,v $ - */ -/******************************************************************************* - Copyright IBM Corporation 1987 - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of IBM not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL -IBM BE LIABLE FOR ANY SPECIAL, 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. - -*******************************************************************************/ - -/* - * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#undef satosiso -#include -#include -#include -#include -#include -#include -#include -#ifdef IncStat -#undef IncStat -#endif -#include -#include -#include -#include -#include -#include -#include "netstat.h" - -static void tprintstat __P((struct tp_stat *, int)); -static void isonetprint __P((struct sockaddr_iso *, int)); -static void hexprint __P((int, char *, char *)); -extern void inetprint __P((struct in_addr *, int, char *)); - -/* - * Dump esis stats - */ -void -esis_stats(off, name) - u_long off; - char *name; -{ - struct esis_stat esis_stat; - - if (off == 0 || - kread(off, (char *)&esis_stat, sizeof (struct esis_stat))) - return; - printf("%s:\n", name); - printf("\t%d esh sent, %d esh received\n", esis_stat.es_eshsent, - esis_stat.es_eshrcvd); - printf("\t%d ish sent, %d ish received\n", esis_stat.es_ishsent, - esis_stat.es_ishrcvd); - printf("\t%d rd sent, %d rd received\n", esis_stat.es_rdsent, - esis_stat.es_rdrcvd); - printf("\t%d pdus not sent due to insufficient memory\n", - esis_stat.es_nomem); - printf("\t%d pdus received with bad checksum\n", esis_stat.es_badcsum); - printf("\t%d pdus received with bad version number\n", - esis_stat.es_badvers); - printf("\t%d pdus received with bad type field\n", esis_stat.es_badtype); - printf("\t%d short pdus received\n", esis_stat.es_toosmall); -} - -/* - * Dump clnp statistics structure. - */ -void -clnp_stats(off, name) - u_long off; - char *name; -{ - struct clnp_stat clnp_stat; - - if (off == 0 || - kread(off, (char *)&clnp_stat, sizeof (clnp_stat))) - return; - - printf("%s:\n\t%d total packets sent\n", name, clnp_stat.cns_sent); - printf("\t%d total fragments sent\n", clnp_stat.cns_fragments); - printf("\t%d total packets received\n", clnp_stat.cns_total); - printf("\t%d with fixed part of header too small\n", - clnp_stat.cns_toosmall); - printf("\t%d with header length not reasonable\n", clnp_stat.cns_badhlen); - printf("\t%d incorrect checksum%s\n", - clnp_stat.cns_badcsum, plural(clnp_stat.cns_badcsum)); - printf("\t%d with unreasonable address lengths\n", clnp_stat.cns_badaddr); - printf("\t%d with forgotten segmentation information\n", - clnp_stat.cns_noseg); - printf("\t%d with an incorrect protocol identifier\n", clnp_stat.cns_noproto); - printf("\t%d with an incorrect version\n", clnp_stat.cns_badvers); - printf("\t%d dropped because the ttl has expired\n", - clnp_stat.cns_ttlexpired); - printf("\t%d clnp cache misses\n", clnp_stat.cns_cachemiss); - printf("\t%d clnp congestion experience bits set\n", - clnp_stat.cns_congest_set); - printf("\t%d clnp congestion experience bits received\n", - clnp_stat.cns_congest_rcvd); -} -/* - * Dump CLTP statistics structure. - */ -void -cltp_stats(off, name) - u_long off; - char *name; -{ - struct cltpstat cltpstat; - - if (off == 0 || - kread(off, (char *)&cltpstat, sizeof (cltpstat))) - return; - printf("%s:\n\t%u incomplete header%s\n", name, - cltpstat.cltps_hdrops, plural(cltpstat.cltps_hdrops)); - printf("\t%u bad data length field%s\n", - cltpstat.cltps_badlen, plural(cltpstat.cltps_badlen)); - printf("\t%u bad checksum%s\n", - cltpstat.cltps_badsum, plural(cltpstat.cltps_badsum)); -} - -struct tp_pcb tpcb; -struct isopcb isopcb; -static struct socket sockb; -union { - struct sockaddr_iso siso; - char data[128]; -} laddr, faddr; -#define kget(o, p) \ - (kread((u_long)(o), (char *)&p, sizeof (p))) - -static int first = 1; - -/* - * Print a summary of connections related to an Internet - * protocol. For TP, also give state of connection. - * Listening processes (aflag) are suppressed unless the - * -a (all) flag is specified. - */ -void -iso_protopr(off, name) - u_long off; - char *name; -{ - struct isopcb cb; - register struct isopcb *prev, *next; - - if (off == 0) { - printf("%s control block: symbol not in namelist\n", name); - return; - } - if (strcmp(name, "tp") == 0) { - tp_protopr(off, name); - return; - } - if (kread(off, (char *)&cb, sizeof(cb))) - return; - isopcb = cb; - prev = (struct isopcb *)off; - if (isopcb.isop_next == (struct isopcb *)off) - return; - while (isopcb.isop_next != (struct isopcb *)off) { - next = isopcb.isop_next; - kget(next, isopcb); - if (isopcb.isop_prev != prev) { - printf("prev 0x%x next 0x%x isop_prev 0x%x isop_next 0x%x???\n", - prev, next, isopcb.isop_prev, isopcb.isop_next); - break; - } - kget(isopcb.isop_socket, sockb); - iso_protopr1((u_long)next, 0); - putchar('\n'); - prev = next; - } -} - -void -iso_protopr1(kern_addr, istp) - u_long kern_addr; - int istp; -{ - if (first) { - printf("Active ISO net connections"); - if (aflag) - printf(" (including servers)"); - putchar('\n'); - if (Aflag) - printf("%-8.8s ", "PCB"); - printf(Aflag ? - "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : - "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", - "Proto", "Recv-Q", "Send-Q", - "Local Address", "Foreign Address", "(state)"); - first = 0; - } - if (Aflag) - printf("%8x ", - (sockb.so_pcb ? (void *)sockb.so_pcb : (void *)kern_addr)); - printf("%-5.5s %6d %6d ", "tp", sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); - if (istp && tpcb.tp_lsuffixlen) { - hexprint(tpcb.tp_lsuffixlen, tpcb.tp_lsuffix, "()"); - printf("\t"); - } else if (isopcb.isop_laddr == 0) - printf("*.*\t"); - else { - if ((char *)isopcb.isop_laddr == ((char *)kern_addr) + - _offsetof(struct isopcb, isop_sladdr)) - laddr.siso = isopcb.isop_sladdr; - else - kget(isopcb.isop_laddr, laddr); - isonetprint((struct sockaddr_iso *)&laddr, 1); - } - if (istp && tpcb.tp_fsuffixlen) { - hexprint(tpcb.tp_fsuffixlen, tpcb.tp_fsuffix, "()"); - printf("\t"); - } else if (isopcb.isop_faddr == 0) - printf("*.*\t"); - else { - if ((char *)isopcb.isop_faddr == ((char *)kern_addr) + - _offsetof(struct isopcb, isop_sfaddr)) - faddr.siso = isopcb.isop_sfaddr; - else - kget(isopcb.isop_faddr, faddr); - isonetprint((struct sockaddr_iso *)&faddr, 0); - } -} - -void -tp_protopr(off, name) - u_long off; - char *name; -{ - extern char *tp_sstring[]; - struct tp_ref *tpr, *tpr_base; - struct tp_refinfo tpkerninfo; - int size; - - kget(off, tpkerninfo); - size = tpkerninfo.tpr_size * sizeof (*tpr); - tpr_base = (struct tp_ref *)malloc(size); - if (tpr_base == 0) - return; - kread((u_long)(tpkerninfo.tpr_base), (char *)tpr_base, size); - for (tpr = tpr_base; tpr < tpr_base + tpkerninfo.tpr_size; tpr++) { - if (tpr->tpr_pcb == 0) - continue; - kget(tpr->tpr_pcb, tpcb); - if (tpcb.tp_state == ST_ERROR) - printf("undefined tpcb state: 0x%x\n", tpr->tpr_pcb); - if (!aflag && - (tpcb.tp_state == TP_LISTENING || - tpcb.tp_state == TP_CLOSED || - tpcb.tp_state == TP_REFWAIT)) { - continue; - } - kget(tpcb.tp_sock, sockb); - if (tpcb.tp_npcb) switch(tpcb.tp_netservice) { - case IN_CLNS: - tp_inproto((u_long)tpkerninfo.tpr_base); - break; - default: - kget(tpcb.tp_npcb, isopcb); - iso_protopr1((u_long)tpcb.tp_npcb, 1); - break; - } - if (tpcb.tp_state >= tp_NSTATES) - printf(" %d", tpcb.tp_state); - else - printf(" %-12.12s", tp_sstring[tpcb.tp_state]); - putchar('\n'); - } -} - -void -tp_inproto(pcb) - u_long pcb; -{ - struct inpcb inpcb; - kget(tpcb.tp_npcb, inpcb); - if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY) - return; - if (Aflag) - printf("%8x ", pcb); - printf("%-5.5s %6d %6d ", "tpip", - sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc); - inetprint(&inpcb.inp_laddr, inpcb.inp_lport, "tp"); - inetprint(&inpcb.inp_faddr, inpcb.inp_fport, "tp"); -} - -/* - * Pretty print an iso address (net address + port). - * If the nflag was specified, use numbers instead of names. - */ - -#ifdef notdef -char * -isonetname(iso) - register struct iso_addr *iso; -{ - struct sockaddr_iso sa; - struct iso_hostent *ihe = 0; - struct iso_hostent *iso_gethostentrybyaddr(); - struct iso_hostent *iso_getserventrybytsel(); - struct iso_hostent Ihe; - static char line[80]; - - bzero(line, sizeof(line)); - if( iso->isoa_afi ) { - sa.siso_family = AF_ISO; - sa.siso_addr = *iso; - sa.siso_tsuffix = 0; - - if (!nflag ) - ihe = iso_gethostentrybyaddr( &sa, 0, 0 ); - if( ihe ) { - Ihe = *ihe; - ihe = &Ihe; - sprintf(line, "%s", ihe->isoh_hname); - } else { - sprintf(line, "%s", iso_ntoa(iso)); - } - } else { - sprintf(line, "*"); - } - return line; -} - -static void -isonetprint(iso, sufx, sufxlen, islocal) - register struct iso_addr *iso; - char *sufx; - u_short sufxlen; - int islocal; -{ - struct iso_hostent *iso_getserventrybytsel(), *ihe; - struct iso_hostent Ihe; - char *line, *cp; - int Alen = Aflag?18:22; - - line = isonetname(iso); - cp = index(line, '\0'); - ihe = (struct iso_hostent *)0; - - if( islocal ) - islocal = 20; - else - islocal = 22 + Alen; - - if(Aflag) - islocal += 10 ; - - if(!nflag) { - if( (cp -line)>10 ) { - cp = line+10; - bzero(cp, sizeof(line)-10); - } - } - - *cp++ = '.'; - if(sufxlen) { - if( !Aflag && !nflag && (ihe=iso_getserventrybytsel(sufx, sufxlen))) { - Ihe = *ihe; - ihe = &Ihe; - } - if( ihe && (strlen(ihe->isoh_aname)>0) ) { - sprintf(cp, "%s", ihe->isoh_aname); - } else { - iso_sprinttsel(cp, sufx, sufxlen); - } - } else - sprintf(cp, "*"); - /* - fprintf(stdout, Aflag?" %-18.18s":" %-22.22s", line); - */ - - if( strlen(line) > Alen ) { - fprintf(stdout, " %s", line); - fprintf(stdout, "\n %*.s", islocal+Alen," "); - } else { - fprintf(stdout, " %-*.*s", Alen, Alen,line); - } -} -#endif - -#ifdef notdef -static void -x25_protopr(off, name) - u_long off; - char *name; -{ - static char *xpcb_states[] = { - "CLOSED", - "LISTENING", - "CLOSING", - "CONNECTING", - "ACKWAIT", - "OPEN", - }; - register struct isopcb *prev, *next; - struct x25_pcb xpcb; - - if (off == 0) { - printf("%s control block: symbol not in namelist\n", name); - return; - } - kread(off, &xpcb, sizeof (struct x25_pcb)); - prev = (struct isopcb *)off; - if (xpcb.x_next == (struct isopcb *)off) - return; - while (xpcb.x_next != (struct isopcb *)off) { - next = isopcb.isop_next; - kread((u_long)next, &xpcb, sizeof (struct x25_pcb)); - if (xpcb.x_prev != prev) { - printf("???\n"); - break; - } - kread((u_long)xpcb.x_socket, &sockb, sizeof (sockb)); - - if (!aflag && - xpcb.x_state == LISTENING || - xpcb.x_state == TP_CLOSED ) { - prev = next; - continue; - } - if (first) { - printf("Active X25 net connections"); - if (aflag) - printf(" (including servers)"); - putchar('\n'); - if (Aflag) - printf("%-8.8s ", "PCB"); - printf(Aflag ? - "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %s\n" : - "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %s\n", - "Proto", "Recv-Q", "Send-Q", - "Local Address", "Foreign Address", "(state)"); - first = 0; - } - printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc, - sockb.so_snd.sb_cc); - isonetprint(&xpcb.x_laddr.siso_addr, &xpcb.x_lport, - sizeof(xpcb.x_lport), 1); - isonetprint(&xpcb.x_faddr.siso_addr, &xpcb.x_fport, - sizeof(xpcb.x_lport), 0); - if (xpcb.x_state < 0 || xpcb.x_state >= x25_NSTATES) - printf(" 0x0x0x0x0x0x0x0x0x%x", xpcb.x_state); - else - printf(" %-12.12s", xpcb_states[xpcb.x_state]); - putchar('\n'); - prev = next; - } -} -#endif - -struct tp_stat tp_stat; - -void -tp_stats(off, name) - caddr_t off, name; -{ - if (off == 0) { - printf("TP not configured\n\n"); - return; - } - printf("%s:\n", name); - kget(off, tp_stat); - tprintstat(&tp_stat, 8); -} - -#define OUT stdout - -static void -tprintstat(s, indent) - register struct tp_stat *s; - int indent; -{ - fprintf(OUT, - "%*sReceiving:\n",indent," "); - fprintf(OUT, - "\t%*s%d variable parameter%s ignored\n", indent," ", - s->ts_param_ignored ,plural(s->ts_param_ignored)); - fprintf(OUT, - "\t%*s%d invalid parameter code%s\n", indent, " ", - s->ts_inv_pcode ,plural(s->ts_inv_pcode)); - fprintf(OUT, - "\t%*s%d invalid parameter value%s\n", indent, " ", - s->ts_inv_pval ,plural(s->ts_inv_pval)); - fprintf(OUT, - "\t%*s%d invalid dutype%s\n", indent, " ", - s->ts_inv_dutype ,plural(s->ts_inv_dutype)); - fprintf(OUT, - "\t%*s%d negotiation failure%s\n", indent, " ", - s->ts_negotfailed ,plural(s->ts_negotfailed)); - fprintf(OUT, - "\t%*s%d invalid destination reference%s\n", indent, " ", - s->ts_inv_dref ,plural(s->ts_inv_dref)); - fprintf(OUT, - "\t%*s%d invalid suffix parameter%s\n", indent, " ", - s->ts_inv_sufx ,plural(s->ts_inv_sufx)); - fprintf(OUT, - "\t%*s%d invalid length\n",indent, " ", s->ts_inv_length); - fprintf(OUT, - "\t%*s%d invalid checksum%s\n", indent, " ", - s->ts_bad_csum ,plural(s->ts_bad_csum)); - fprintf(OUT, - "\t%*s%d DT%s out of order\n", indent, " ", - s->ts_dt_ooo ,plural(s->ts_dt_ooo)); - fprintf(OUT, - "\t%*s%d DT%s not in window\n", indent, " ", - s->ts_dt_niw ,plural(s->ts_dt_niw)); - fprintf(OUT, - "\t%*s%d duplicate DT%s\n", indent, " ", - s->ts_dt_dup ,plural(s->ts_dt_dup)); - fprintf(OUT, - "\t%*s%d XPD%s not in window\n", indent, " ", - s->ts_xpd_niw ,plural(s->ts_xpd_niw)); - fprintf(OUT, - "\t%*s%d XPD%s w/o credit to stash\n", indent, " ", - s->ts_xpd_dup ,plural(s->ts_xpd_dup)); - fprintf(OUT, - "\t%*s%d time%s local credit reneged\n", indent, " ", - s->ts_lcdt_reduced ,plural(s->ts_lcdt_reduced)); - fprintf(OUT, - "\t%*s%d concatenated TPDU%s\n", indent, " ", - s->ts_concat_rcvd ,plural(s->ts_concat_rcvd)); - fprintf(OUT, - "%*sSending:\n", indent, " "); - fprintf(OUT, - "\t%*s%d XPD mark%s discarded\n", indent, " ", - s->ts_xpdmark_del ,plural(s->ts_xpdmark_del)); - fprintf(OUT, - "\t%*sXPD stopped data flow %d time%s\n", indent, " ", - s->ts_xpd_intheway ,plural(s->ts_xpd_intheway)); - fprintf(OUT, - "\t%*s%d time%s foreign window closed\n", indent, " ", - s->ts_zfcdt ,plural(s->ts_zfcdt)); - fprintf(OUT, - "%*sMiscellaneous:\n", indent, " "); - fprintf(OUT, - "\t%*s%d small mbuf%s\n", indent, " ", - s->ts_mb_small ,plural(s->ts_mb_small)); - fprintf(OUT, - "\t%*s%d cluster%s\n", indent, " ", - s->ts_mb_cluster, plural(s->ts_mb_cluster)); - fprintf(OUT, - "\t%*s%d source quench \n",indent, " ", - s->ts_quench); - fprintf(OUT, - "\t%*s%d dec bit%s\n", indent, " ", - s->ts_rcvdecbit, plural(s->ts_rcvdecbit)); - fprintf(OUT, - "\t%*sM:L ( M mbuf chains of length L)\n", indent, " "); - { - register int j; - - fprintf(OUT, "\t%*s%d: over 16\n", indent, " ", - s->ts_mb_len_distr[0]); - for( j=1; j<=8; j++) { - fprintf(OUT, - "\t%*s%d: %d\t\t%d: %d\n", indent, " ", - s->ts_mb_len_distr[j],j, - s->ts_mb_len_distr[j<<1],j<<1 - ); - } - } - fprintf(OUT, - "\t%*s%d EOT rcvd\n", indent, " ", s->ts_eot_input); - fprintf(OUT, - "\t%*s%d EOT sent\n", indent, " ", s->ts_EOT_sent); - fprintf(OUT, - "\t%*s%d EOT indication%s\n", indent, " ", - s->ts_eot_user ,plural(s->ts_eot_user)); - - fprintf(OUT, - "%*sConnections:\n", indent, " "); - fprintf(OUT, - "\t%*s%d connection%s used extended format\n", indent, " ", - s->ts_xtd_fmt ,plural(s->ts_xtd_fmt)); - fprintf(OUT, - "\t%*s%d connection%s allowed transport expedited data\n", indent, " ", - s->ts_use_txpd ,plural(s->ts_use_txpd)); - fprintf(OUT, - "\t%*s%d connection%s turned off checksumming\n", indent, " ", - s->ts_csum_off ,plural(s->ts_csum_off)); - fprintf(OUT, - "\t%*s%d connection%s dropped due to retrans limit\n", indent, " ", - s->ts_conn_gaveup ,plural(s->ts_conn_gaveup)); - fprintf(OUT, - "\t%*s%d tp 4 connection%s\n", indent, " ", - s->ts_tp4_conn ,plural(s->ts_tp4_conn)); - fprintf(OUT, - "\t%*s%d tp 0 connection%s\n", indent, " ", - s->ts_tp0_conn ,plural(s->ts_tp0_conn)); - { - register int j; - static char *name[]= { - "~LOCAL, PDN", - "~LOCAL,~PDN", - " LOCAL,~PDN", - " LOCAL, PDN" - }; - - fprintf(OUT, - "\n%*sRound trip times, listed in ticks:\n", indent, " "); - fprintf(OUT, - "\t%*s%11.11s %12.12s | %12.12s | %s\n", indent, " ", - "Category", - "Smoothed avg", "Deviation", "Deviation/Avg"); - for (j = 0; j <= 3; j++) { - fprintf(OUT, - "\t%*s%11.11s: %-11d | %-11d | %-11d | %-11d\n", indent, " ", - name[j], - s->ts_rtt[j], - s->ts_rtt[j], - s->ts_rtv[j], - s->ts_rtv[j]); - } - } - fprintf(OUT, -"\n%*sTpdus RECVD [%d valid, %3.6f %% of total (%d); %d dropped]\n",indent," ", - s->ts_tpdu_rcvd , - ((s->ts_pkt_rcvd > 0) ? - ((100 * (float)s->ts_tpdu_rcvd)/(float)s->ts_pkt_rcvd) - : 0), - s->ts_pkt_rcvd, - s->ts_recv_drop ); - - fprintf(OUT, - "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ", - s->ts_DT_rcvd, s->ts_AK_rcvd, s->ts_DR_rcvd, s->ts_CR_rcvd); - fprintf(OUT, - "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ", - s->ts_XPD_rcvd, s->ts_XAK_rcvd, s->ts_DC_rcvd, s->ts_CC_rcvd, - s->ts_ER_rcvd); - fprintf(OUT, - "\n%*sTpdus SENT [%d total, %d dropped]\n", indent, " ", - s->ts_tpdu_sent, s->ts_send_drop); - - fprintf(OUT, - "\t%*sDT %6d AK %6d DR %4d CR %4d \n", indent, " ", - s->ts_DT_sent, s->ts_AK_sent, s->ts_DR_sent, s->ts_CR_sent); - fprintf(OUT, - "\t%*sXPD %6d XAK %6d DC %4d CC %4d ER %4d\n", indent, " ", - s->ts_XPD_sent, s->ts_XAK_sent, s->ts_DC_sent, s->ts_CC_sent, - s->ts_ER_sent); - - fprintf(OUT, - "\n%*sRetransmissions:\n", indent, " "); -#define PERCENT(X,Y) (((Y)>0)?((100 *(float)(X)) / (float) (Y)):0) - - fprintf(OUT, - "\t%*sCR %6d CC %6d DR %6d \n", indent, " ", - s->ts_retrans_cr, s->ts_retrans_cc, s->ts_retrans_dr); - fprintf(OUT, - "\t%*sDT %6d (%5.2f%%)\n", indent, " ", - s->ts_retrans_dt, - PERCENT(s->ts_retrans_dt, s->ts_DT_sent)); - fprintf(OUT, - "\t%*sXPD %6d (%5.2f%%)\n", indent, " ", - s->ts_retrans_xpd, - PERCENT(s->ts_retrans_xpd, s->ts_XPD_sent)); - - - fprintf(OUT, - "\n%*sE Timers: [%6d ticks]\n", indent, " ", s->ts_Eticks); - fprintf(OUT, - "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n",indent, " ", - s->ts_Eset ,plural(s->ts_Eset), - s->ts_Eexpired ,plural(s->ts_Eexpired), - s->ts_Ecan_act ,plural(s->ts_Ecan_act)); - - fprintf(OUT, - "\n%*sC Timers: [%6d ticks]\n", indent, " ",s->ts_Cticks); - fprintf(OUT, - "%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n", - indent, " ", - s->ts_Cset ,plural(s->ts_Cset), - s->ts_Cexpired ,plural(s->ts_Cexpired), - s->ts_Ccan_act ,plural(s->ts_Ccan_act)); - fprintf(OUT, - "%*s%6d inactive timer%s cancelled\n", indent, " ", - s->ts_Ccan_inact ,plural(s->ts_Ccan_inact)); - - fprintf(OUT, - "\n%*sPathological debugging activity:\n", indent, " "); - fprintf(OUT, - "\t%*s%6d CC%s sent to zero dref\n", indent, " ", - s->ts_zdebug ,plural(s->ts_zdebug)); - /* SAME LINE AS ABOVE */ - fprintf(OUT, - "\t%*s%6d random DT%s dropped\n", indent, " ", - s->ts_ydebug ,plural(s->ts_ydebug)); - fprintf(OUT, - "\t%*s%6d illegally large XPD TPDU%s\n", indent, " ", - s->ts_vdebug ,plural(s->ts_vdebug)); - fprintf(OUT, - "\t%*s%6d faked reneging of cdt\n", indent, " ", - s->ts_ldebug ); - - fprintf(OUT, - "\n%*sACK reasons:\n", indent, " "); - fprintf(OUT, "\t%*s%6d not acked immediately\n", indent, " ", - s->ts_ackreason[_ACK_DONT_] ); - fprintf(OUT, "\t%*s%6d strategy==each\n", indent, " ", - s->ts_ackreason[_ACK_STRAT_EACH_] ); - fprintf(OUT, "\t%*s%6d strategy==fullwindow\n", indent, " ", - s->ts_ackreason[_ACK_STRAT_FULLWIN_] ); - fprintf(OUT, "\t%*s%6d duplicate DT\n", indent, " ", - s->ts_ackreason[_ACK_DUP_] ); - fprintf(OUT, "\t%*s%6d EOTSDU\n", indent, " ", - s->ts_ackreason[_ACK_EOT_] ); - fprintf(OUT, "\t%*s%6d reordered DT\n", indent, " ", - s->ts_ackreason[_ACK_REORDER_] ); - fprintf(OUT, "\t%*s%6d user rcvd\n", indent, " ", - s->ts_ackreason[_ACK_USRRCV_] ); - fprintf(OUT, "\t%*s%6d fcc reqd\n", indent, " ", - s->ts_ackreason[_ACK_FCC_] ); -} -#ifndef SSEL -#define SSEL(s) ((s)->siso_tlen + TSEL(s)) -#define PSEL(s) ((s)->siso_slen + SSEL(s)) -#endif - -static void -isonetprint(siso, islocal) - register struct sockaddr_iso *siso; - int islocal; -{ - hexprint(siso->siso_nlen, siso->siso_addr.isoa_genaddr, "{}"); - if (siso->siso_tlen || siso->siso_slen || siso->siso_plen) - hexprint(siso->siso_tlen, TSEL(siso), "()"); - if (siso->siso_slen || siso->siso_plen) - hexprint(siso->siso_slen, SSEL(siso), "[]"); - if (siso->siso_plen) - hexprint(siso->siso_plen, PSEL(siso), "<>"); - putchar(' '); -} - -static char hexlist[] = "0123456789abcdef", obuf[128]; - -static void -hexprint(n, buf, delim) - int n; - char *buf, *delim; -{ - register u_char *in = (u_char *)buf, *top = in + n; - register char *out = obuf; - register int i; - - if (n == 0) - return; - while (in < top) { - i = *in++; - *out++ = '.'; - if (i > 0xf) { - out[1] = hexlist[i & 0xf]; - i >>= 4; - out[0] = hexlist[i]; - out += 2; - } else - *out++ = hexlist[i]; - } - *obuf = *delim; *out++ = delim[1]; *out = 0; - printf("%s", obuf); -} diff --git a/netstat.tproj/main.c b/netstat.tproj/main.c index 8ca3a72..b6144de 100644 --- a/netstat.tproj/main.c +++ b/netstat.tproj/main.c @@ -65,7 +65,7 @@ char const copyright[] = static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94"; #endif static const char rcsid[] = - "$Id: main.c,v 1.2 2000/06/16 03:37:29 lindak Exp $"; + "$Id: main.c,v 1.4 2002/03/05 20:35:14 lindak Exp $"; #endif /* not lint */ #include @@ -100,7 +100,7 @@ static const char rcsid[] = * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * - * $Id: main.c,v 1.2 2000/06/16 03:37:29 lindak Exp $ + * $Id: main.c,v 1.4 2002/03/05 20:35:14 lindak Exp $ * */ @@ -160,8 +160,38 @@ static struct nlist nl[] = { { "_ddpstat"}, #define N_DDPCB 26 { "_ddpcb"}, -#define N_MBSTAT 27 - {"_mbstat"}, +#define N_NGSOCKS 27 + { "_ngsocklist"}, +#define N_IP6STAT 28 + { "_ip6stat" }, +#define N_ICMP6STAT 29 + { "_icmp6stat" }, +#define N_IPSECSTAT 30 + { "_ipsecstat" }, +#define N_IPSEC6STAT 31 + { "_ipsec6stat" }, +#define N_PIM6STAT 32 + { "_pim6stat" }, +#define N_MRT6PROTO 33 + { "_ip6_mrtproto" }, +#define N_MRT6STAT 34 + { "_mrt6stat" }, +#define N_MF6CTABLE 35 + { "_mf6ctable" }, +#define N_MIF6TABLE 36 + { "_mif6table" }, +#define N_PFKEYSTAT 37 + { "_pfkeystat" }, +#define N_MBSTAT 38 + { "_mbstat" }, +#define N_MBTYPES 39 + { "_mbtypes" }, +#define N_NMBCLUSTERS 40 + { "_nmbclusters" }, +#define N_NMBUFS 41 + { "_nmbufs" }, +#define N_RTTRASH 42 + { "_rttrash" }, { "" }, }; @@ -171,85 +201,140 @@ struct protox { u_char pr_index; /* index into nlist of cb head */ u_char pr_sindex; /* index into nlist of stat block */ u_char pr_wanted; /* 1 if wanted, 0 otherwise */ - void (*pr_cblocks)(); /* control blocks printing routine */ - void (*pr_stats)(); /* statistics printing routine */ + void (*pr_cblocks)(u_long, char *, int); + /* control blocks printing routine */ + void (*pr_stats)(u_long, char *, int); + /* statistics printing routine */ + void (*pr_istats)(char *); /* per/if statistics printing routine */ char *pr_name; /* well-known name */ int pr_usesysctl; /* true if we use sysctl, not kvm */ } protox[] = { { -1, -1, 1, protopr, - tcp_stats, "tcp", IPPROTO_TCP }, + tcp_stats, NULL, "tcp", IPPROTO_TCP }, { -1, -1, 1, protopr, - udp_stats, "udp", IPPROTO_UDP }, + udp_stats, NULL, "udp", IPPROTO_UDP }, { -1, -1, 1, protopr, - NULL, "divert", IPPROTO_DIVERT }, + NULL, NULL, "divert",IPPROTO_DIVERT }, { -1, -1, 1, protopr, - ip_stats, "ip", IPPROTO_RAW }, + ip_stats, NULL, "ip", IPPROTO_RAW }, { -1, -1, 1, protopr, - icmp_stats, "icmp", IPPROTO_ICMP }, + icmp_stats, NULL, "icmp", IPPROTO_ICMP }, { -1, -1, 1, protopr, - igmp_stats, "igmp", IPPROTO_IGMP }, + igmp_stats, NULL, "igmp", IPPROTO_IGMP }, +#ifdef IPSEC + { -1, N_IPSECSTAT, 1, 0, + ipsec_stats, NULL, "ipsec", 0}, +#endif +#if 0 + { -1, -1, 1, 0, + bdg_stats, NULL, "bdg", 1 /* bridging... */ }, +#endif + { -1, -1, 0, 0, + 0, NULL, 0 } +}; + +#ifdef INET6 +struct protox ip6protox[] = { + { -1, -1, 1, protopr, + tcp_stats, NULL, "tcp", IPPROTO_TCP }, + { -1, -1, 1, protopr, + udp_stats, NULL, "udp", IPPROTO_UDP }, + { -1, N_IP6STAT, 1, protopr, + ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW }, + { -1, N_ICMP6STAT, 1, protopr, + icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 }, +#ifdef IPSEC + { -1, N_IPSEC6STAT, 1, 0, + ipsec_stats, NULL, "ipsec6",0 }, +#endif +#ifdef notyet + { -1, N_PIM6STAT, 1, 0, + pim6_stats, NULL, "pim6", 0 }, +#endif + { -1, -1, 1, 0, + rip6_stats, NULL, "rip6", 0 }, +#if 0 + { -1, -1, 1, 0, + bdg_stats, NULL, "bdg", 1 /* bridging... */ }, +#endif { -1, -1, 0, 0, - 0, 0 } + 0, NULL, 0, 0 } }; +#endif /*INET6*/ -#ifdef UNIX_ATALK +#ifdef IPSEC +struct protox pfkeyprotox[] = { + { -1, N_PFKEYSTAT, 1, 0, + pfkey_stats, NULL, "pfkey", 0 }, + { -1, -1, 0, 0, + 0, NULL, 0, 0 } +}; +#endif +#ifndef __APPLE__ struct protox atalkprotox[] = { { N_DDPCB, N_DDPSTAT, 1, atalkprotopr, - ddp_stats, "ddp" }, + ddp_stats, NULL, "ddp" }, { -1, -1, 0, 0, - 0, 0 } + 0, NULL, 0 } +}; + +struct protox netgraphprotox[] = { + { N_NGSOCKS, -1, 1, netgraphprotopr, + NULL, NULL, "ctrl" }, + { N_NGSOCKS, -1, 1, netgraphprotopr, + NULL, NULL, "data" }, + { -1, NULL, 0, 0, + 0, NULL, 0 } }; -#endif -#ifdef IPX struct protox ipxprotox[] = { { N_IPX, N_IPXSTAT, 1, ipxprotopr, - ipx_stats, "ipx", 0 }, + ipx_stats, NULL, "ipx", 0 }, { N_IPX, N_SPXSTAT, 1, ipxprotopr, - spx_stats, "spx", 0 }, + spx_stats, NULL, "spx", 0 }, { -1, -1, 0, 0, - 0, 0, 0 } + 0, NULL, 0, 0 } }; #endif - #ifdef NS struct protox nsprotox[] = { { N_IDP, N_IDPSTAT, 1, nsprotopr, - idp_stats, "idp" }, + idp_stats, NULL, "idp" }, { N_IDP, N_SPPSTAT, 1, nsprotopr, - spp_stats, "spp" }, + spp_stats, NULL, "spp" }, { -1, N_NSERR, 1, 0, - nserr_stats, "ns_err" }, + nserr_stats, NULL, "ns_err" }, { -1, -1, 0, 0, - 0, 0 } + 0, NULL, 0 } }; #endif #ifdef ISO struct protox isoprotox[] = { { ISO_TP, N_TPSTAT, 1, iso_protopr, - tp_stats, "tp" }, + tp_stats, NULL, "tp" }, { N_CLTP, N_CLTPSTAT, 1, iso_protopr, - cltp_stats, "cltp" }, + cltp_stats, NULL, "cltp" }, { -1, N_CLNPSTAT, 1, 0, - clnp_stats, "clnp"}, + clnp_stats, NULL, "clnp"}, { -1, N_ESISSTAT, 1, 0, - esis_stats, "esis"}, + esis_stats, NULL, "esis"}, { -1, -1, 0, 0, - 0, 0 } + 0, NULL, 0 } }; #endif -struct protox *protoprotox[] = { protox, - -#ifdef IPX -ipxprotox, +struct protox *protoprotox[] = { + protox, +#ifdef INET6 + ip6protox, #endif - -#ifdef UNIX_ATALK -atalkprotox, +#ifdef IPSEC + pfkeyprotox, +#endif +#ifndef __APPLE__ + ipxprotox, atalkprotox, #endif - #ifdef NS nsprotox, #endif @@ -258,26 +343,48 @@ atalkprotox, #endif NULL }; -static void printproto __P((struct protox *, char *)); -static void usage __P((void)); -static struct protox *name2protox __P((char *)); -static struct protox *knownname __P((char *)); +static void printproto (struct protox *, char *); +static void usage (void); +static struct protox *name2protox (char *); +static struct protox *knownname (char *); static kvm_t *kvmd; -char *nlistf = NULL, *memf = NULL; +static char *nlistf = NULL, *memf = NULL; + +int Aflag; /* show addresses of protocol control block */ +int aflag; /* show all sockets (including servers) */ +int bflag; /* show i/f total bytes in/out */ +int dflag; /* show i/f dropped packets */ +int gflag; /* show group (multicast) routing or stats */ +int iflag; /* show interfaces */ +int lflag; /* show routing table with use and ref */ +int Lflag; /* show size of listen queues */ +int mflag; /* show memory stats */ +int nflag; /* show addresses numerically */ +static int pflag; /* show given protocol */ +int rflag; /* show routing tables (or routing stats) */ +int sflag; /* show protocol statistics */ +int tflag; /* show i/f watchdog timers */ +int Wflag; /* wide display */ + +int interval; /* repeat interval for i/f stats */ + +char *interface; /* desired i/f for stats, or NULL for all i/fs */ +int unit; /* unit number for above */ + +int af; /* address family */ int main(argc, argv) int argc; char *argv[]; { - register struct protoent *p; - register struct protox *tp; /* for printing cblocks & stats */ + register struct protox *tp = NULL; /* for printing cblocks & stats */ int ch; af = AF_UNSPEC; - while ((ch = getopt(argc, argv, "Aabdf:ghI:iM:mN:np:rstuw:")) != -1) + while ((ch = getopt(argc, argv, "Aabdf:gI:iLlM:mN:np:rstuWw:")) != -1) switch(ch) { case 'A': Aflag = 1; @@ -301,12 +408,23 @@ main(argc, argv) af = AF_IPX; else if (strcmp(optarg, "inet") == 0) af = AF_INET; +#ifdef INET6 + else if (strcmp(optarg, "inet6") == 0) + af = AF_INET6; +#endif /*INET6*/ +#ifdef INET6 + else if (strcmp(optarg, "pfkey") == 0) + af = PF_KEY; +#endif /*INET6*/ else if (strcmp(optarg, "unix") == 0) af = AF_UNIX; - else if (strcmp(optarg, "local") == 0) - af = AF_LOCAL; +#ifndef __APPLE__ else if (strcmp(optarg, "atalk") == 0) af = AF_APPLETALK; + else if (strcmp(optarg, "ng") == 0 + || strcmp(optarg, "netgraph") == 0) + af = AF_NETGRAPH; +#endif #ifdef ISO else if (strcmp(optarg, "iso") == 0) af = AF_ISO; @@ -330,6 +448,12 @@ main(argc, argv) case 'i': iflag = 1; break; + case 'l': + lflag = 1; + break; + case 'L': + Lflag = 1; + break; case 'M': memf = optarg; break; @@ -362,6 +486,9 @@ main(argc, argv) case 'u': af = AF_UNIX; break; + case 'W': + Wflag = 1; + break; case 'w': interval = atoi(optarg); iflag = 1; @@ -399,22 +526,16 @@ main(argc, argv) setgid(getgid()); if (mflag) { - kread(0,0,0); - mbpr(nl[N_MBSTAT].n_value); - exit(0); - } - if (pflag) { - if (!tp->pr_stats) { - printf("%s: no stats routine\n", tp->pr_name); - exit(0); - } - if (tp->pr_usesysctl) { - (*tp->pr_stats)(tp->pr_usesysctl, tp->pr_name); - } else { - kread(0, 0, 0); - (*tp->pr_stats)(nl[tp->pr_sindex].n_value, - tp->pr_name); - } + //if (memf != NULL) { + if (kread(0, 0, 0) == 0) + mbpr(nl[N_MBSTAT].n_value); + //mbpr(nl[N_MBSTAT].n_value, + // nl[N_MBTYPES].n_value, + // nl[N_NMBCLUSTERS].n_value, + // nl[N_NMBUFS].n_value); + //} else + // mbpr(0, 0, 0, 0); + //mbpr(0) ; exit(0); } #if 0 @@ -431,54 +552,71 @@ main(argc, argv) * used for the queries, which is slower. */ #endif - if (iflag) { + if (iflag && !sflag) { kread(0, 0, 0); - intpr(interval, nl[N_IFNET].n_value); + intpr(interval, nl[N_IFNET].n_value, NULL); exit(0); } if (rflag) { kread(0, 0, 0); if (sflag) - rt_stats(nl[N_RTSTAT].n_value); + rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value); else routepr(nl[N_RTREE].n_value); exit(0); } if (gflag) { kread(0, 0, 0); - if (sflag) - mrt_stats(nl[N_MRTSTAT].n_value); - else - mroutepr(nl[N_MFCTABLE].n_value, - nl[N_VIFTABLE].n_value); - exit(0); - } - if (af == AF_INET || af == AF_UNSPEC) { - setprotoent(1); - setservent(1); - /* ugh, this is O(MN) ... why do we do this? */ - while ((p = getprotoent())) { - for (tp = protox; tp->pr_name; tp++) - if (strcmp(tp->pr_name, p->p_name) == 0) - break; - if (tp->pr_name == 0 || tp->pr_wanted == 0) - continue; - printproto(tp, p->p_name); + if (sflag) { + if (af == AF_INET || af == AF_UNSPEC) + mrt_stats(nl[N_MRTSTAT].n_value); +#ifdef INET6 + if (af == AF_INET6 || af == AF_UNSPEC) + mrt6_stats(nl[N_MRT6STAT].n_value); +#endif + } else { + if (af == AF_INET || af == AF_UNSPEC) + mroutepr(nl[N_MFCTABLE].n_value, + nl[N_VIFTABLE].n_value); +#ifdef INET6 + if (af == AF_INET6 || af == AF_UNSPEC) + mroute6pr(nl[N_MF6CTABLE].n_value, + nl[N_MIF6TABLE].n_value); +#endif } - endprotoent(); + exit(0); } -#ifdef IPX + kread(0, 0, 0); + if (tp) { + printproto(tp, tp->pr_name); + exit(0); + } + if (af == AF_INET || af == AF_UNSPEC) + for (tp = protox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#ifdef INET6 + if (af == AF_INET6 || af == AF_UNSPEC) + for (tp = ip6protox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#endif /*INET6*/ +#ifdef IPSEC + if (af == PF_KEY || af == AF_UNSPEC) + for (tp = pfkeyprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); +#endif /*IPSEC*/ +#ifndef __APPLE__ if (af == AF_IPX || af == AF_UNSPEC) { kread(0, 0, 0); for (tp = ipxprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); } -#endif -#ifdef UNIX_ATALK if (af == AF_APPLETALK || af == AF_UNSPEC) for (tp = atalkprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); + if (af == AF_NETGRAPH || af == AF_UNSPEC) + for (tp = netgraphprotox; tp->pr_name; tp++) + printproto(tp, tp->pr_name); #endif #ifdef NS if (af == AF_NS || af == AF_UNSPEC) @@ -490,7 +628,7 @@ main(argc, argv) for (tp = isoprotox; tp->pr_name; tp++) printproto(tp, tp->pr_name); #endif - if ((af == AF_UNIX || af == AF_LOCAL || af == AF_UNSPEC) && !sflag) + if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag) unixpr(); exit(0); } @@ -505,30 +643,49 @@ printproto(tp, name) register struct protox *tp; char *name; { - void (*pr)(); + void (*pr)(u_long, char *, int); u_long off; if (sflag) { - pr = tp->pr_stats; - off = tp->pr_usesysctl ? tp->pr_usesysctl - : nl[tp->pr_sindex].n_value; + if (iflag) { + if (tp->pr_istats) + intpr(interval, nl[N_IFNET].n_value, + tp->pr_istats); + else if (pflag) + printf("%s: no per-interface stats routine\n", + tp->pr_name); + return; + } + else { + pr = tp->pr_stats; + if (!pr) { + if (pflag) + printf("%s: no stats routine\n", + tp->pr_name); + return; + } + off = tp->pr_usesysctl ? tp->pr_usesysctl + : nl[tp->pr_sindex].n_value; + } } else { pr = tp->pr_cblocks; + if (!pr) { + if (pflag) + printf("%s: no PCB routine\n", tp->pr_name); + return; + } off = tp->pr_usesysctl ? tp->pr_usesysctl : nl[tp->pr_index].n_value; } if (pr != NULL && (off || af != AF_UNSPEC)) - (*pr)(off, name); + (*pr)(off, name, af); } /* * Read kernel memory, return 0 on success. */ int -kread(addr, buf, size) - u_long addr; - char *buf; - int size; +kread(u_long addr, char *buf, int size) { if (kvmd == 0) { /* @@ -565,15 +722,13 @@ kread(addr, buf, size) } char * -plural(n) - int n; +plural(int n) { return (n != 1 ? "s" : ""); } char * -plurales(n) - int n; +plurales(int n) { return (n != 1 ? "es" : ""); } @@ -582,8 +737,7 @@ plurales(n) * Find the protox for the given "well-known" name. */ static struct protox * -knownname(name) - char *name; +knownname(char *name) { struct protox **tpp, *tp; @@ -598,8 +752,7 @@ knownname(name) * Find the protox corresponding to name. */ static struct protox * -name2protox(name) - char *name; +name2protox(char *name) { struct protox *tp; char **alias; /* alias from p->aliases */ @@ -609,11 +762,11 @@ name2protox(name) * Try to find the name in the list of "well-known" names. If that * fails, check if name is an alias for an Internet protocol. */ - if ((tp = knownname(name))) + if ((tp = knownname(name)) != NULL) return (tp); setprotoent(1); /* make protocol lookup cheaper */ - while ((p = getprotoent())) { + while ((p = getprotoent()) != NULL) { /* assert: name not same as p->name */ for (alias = p->p_aliases; *alias; alias++) if (strcmp(name, *alias) == 0) { @@ -626,42 +779,13 @@ name2protox(name) } static void -usage() +usage(void) { (void)fprintf(stderr, "%s\n%s\n%s\n%s\n", "usage: netstat [-Aan] [-f address_family] [-M core] [-N system]", " netstat [-bdghimnrs] [-f address_family] [-M core] [-N system]", " netstat [-bdn] [-I interface] [-M core] [-N system] [-w wait]", +" netstat -m [-M core] [-N system]", " netstat [-M core] [-N system] [-p protocol]"); exit(1); } - -void -trimdomain(cp) - char *cp; -{ - static char domain[MAXHOSTNAMELEN + 1]; - static int first = 1; - char *s; - - if (first) { - first = 0; - if (gethostname(domain, MAXHOSTNAMELEN) == 0 && - (s = strchr(domain, '.'))) - (void) strcpy(domain, s + 1); - else - domain[0] = 0; - } - - if (domain[0]) { - while ((cp = strchr(cp, '.'))) { - if (!strcasecmp(cp + 1, domain)) { - *cp = 0; /* hit it */ - break; - } else { - cp++; - } - } - } -} - diff --git a/netstat.tproj/mroute.c b/netstat.tproj/mroute.c index 03e47cc..a2d22f9 100644 --- a/netstat.tproj/mroute.c +++ b/netstat.tproj/mroute.c @@ -100,7 +100,7 @@ mroutepr(mfcaddr, vifaddr) vifi_t maxvif = 0; if (mfcaddr == 0 || vifaddr == 0) { - printf("No multicast routing compiled into this system.\n"); + printf("No IPv4 multicast routing compiled into this system.\n"); return; } @@ -141,7 +141,7 @@ mroutepr(mfcaddr, vifaddr) kread((u_long)m, (char *)&mfc, sizeof mfc); if (!banner_printed) { - printf("\nMulticast Forwarding Cache\n" + printf("\nIPv4 Multicast Forwarding Cache\n" " Origin Group " " Packets In-Vif Out-Vifs:Ttls\n"); banner_printed = 1; @@ -175,12 +175,12 @@ mrt_stats(mstaddr) struct mrtstat mrtstat; if (mstaddr == 0) { - printf("No multicast routing compiled into this system.\n"); + printf("No IPv4 multicast routing compiled into this system.\n"); return; } kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); - printf("multicast forwarding:\n"); + printf("IPv4 multicast forwarding:\n"); printf(" %10lu multicast forwarding cache lookup%s\n", mrtstat.mrts_mfc_lookups, plural(mrtstat.mrts_mfc_lookups)); printf(" %10lu multicast forwarding cache miss%s\n", diff --git a/netstat.tproj/mroute6.c b/netstat.tproj/mroute6.c new file mode 100644 index 0000000..64c92cb --- /dev/null +++ b/netstat.tproj/mroute6.c @@ -0,0 +1,248 @@ +/* + * Copyright (C) 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. 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. + */ + +/* + * Copyright (c) 1989 Stephen Deering + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Stephen Deering of Stanford University. + * + * 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. + * + * @(#)mroute.c 8.2 (Berkeley) 4/28/95 + * $FreeBSD: src/usr.bin/netstat/mroute6.c,v 1.1.2.5 2001/08/10 09:07:09 ru Exp $ + */ + +#ifdef INET6 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#define KERNEL 1 +#include +#undef KERNEL + +#include "netstat.h" + +#define WID_ORG (lflag ? 39 : (nflag ? 29 : 18)) /* width of origin column */ +#define WID_GRP (lflag ? 18 : (nflag ? 16 : 18)) /* width of group column */ + +void +mroute6pr(u_long mfcaddr, u_long mifaddr) +{ + struct mf6c *mf6ctable[MF6CTBLSIZ], *mfcp; + struct mif6 mif6table[MAXMIFS]; + struct mf6c mfc; + struct rtdetq rte, *rtep; + register struct mif6 *mifp; + register mifi_t mifi; + register int i; + register int banner_printed; + register int saved_nflag; + mifi_t maxmif = 0; + long int waitings; + + if (mfcaddr == 0 || mifaddr == 0) { + printf("No IPv6 multicast routing compiled into this" + " system.\n"); + return; + } + + saved_nflag = nflag; + nflag = 1; + + kread(mifaddr, (char *)&mif6table, sizeof(mif6table)); + banner_printed = 0; + for (mifi = 0, mifp = mif6table; mifi < MAXMIFS; ++mifi, ++mifp) { + struct ifnet ifnet; + char ifname[IFNAMSIZ]; + + if (mifp->m6_ifp == NULL) + continue; + + kread((u_long)mifp->m6_ifp, (char *)&ifnet, sizeof(ifnet)); + maxmif = mifi; + if (!banner_printed) { + printf("\nIPv6 Multicast Interface Table\n" + " Mif Rate PhyIF " + "Pkts-In Pkts-Out\n"); + banner_printed = 1; + } + + printf(" %2u %4d", + mifi, mifp->m6_rate_limit); + printf(" %5s", (mifp->m6_flags & MIFF_REGISTER) ? + "reg0" : if_indextoname(ifnet.if_index, ifname)); + + printf(" %9llu %9llu\n", (unsigned long long)mifp->m6_pkt_in, + (unsigned long long)mifp->m6_pkt_out); + } + if (!banner_printed) + printf("\nIPv6 Multicast Interface Table is empty\n"); + + kread(mfcaddr, (char *)&mf6ctable, sizeof(mf6ctable)); + banner_printed = 0; + for (i = 0; i < MF6CTBLSIZ; ++i) { + mfcp = mf6ctable[i]; + while(mfcp) { + kread((u_long)mfcp, (char *)&mfc, sizeof(mfc)); + if (!banner_printed) { + printf ("\nIPv6 Multicast Forwarding Cache\n"); + printf(" %-*.*s %-*.*s %s", + WID_ORG, WID_ORG, "Origin", + WID_GRP, WID_GRP, "Group", + " Packets Waits In-Mif Out-Mifs\n"); + banner_printed = 1; + } + + printf(" %-*.*s", WID_ORG, WID_ORG, + routename6(&mfc.mf6c_origin)); + printf(" %-*.*s", WID_GRP, WID_GRP, + routename6(&mfc.mf6c_mcastgrp)); + printf(" %9llu", (unsigned long long)mfc.mf6c_pkt_cnt); + + for (waitings = 0, rtep = mfc.mf6c_stall; rtep; ) { + waitings++; + kread((u_long)rtep, (char *)&rte, sizeof(rte)); + rtep = rte.next; + } + printf(" %3ld", waitings); + + if (mfc.mf6c_parent == MF6C_INCOMPLETE_PARENT) + printf(" --- "); + else + printf(" %3d ", mfc.mf6c_parent); + for (mifi = 0; mifi <= maxmif; mifi++) { + if (IF_ISSET(mifi, &mfc.mf6c_ifset)) + printf(" %u", mifi); + } + printf("\n"); + + mfcp = mfc.mf6c_next; + } + } + if (!banner_printed) + printf("\nIPv6 Multicast Routing Table is empty\n"); + + printf("\n"); + nflag = saved_nflag; +} + +void +mrt6_stats(u_long mstaddr) +{ + struct mrt6stat mrtstat; + + if (mstaddr == 0) { + printf("No IPv6 multicast routing compiled into this" + "system.\n"); + return; + } + + kread(mstaddr, (char *)&mrtstat, sizeof(mrtstat)); + printf("IPv6 multicast forwarding:\n"); + printf(" %10llu multicast forwarding cache lookup%s\n", + (unsigned long long)mrtstat.mrt6s_mfc_lookups, + plural(mrtstat.mrt6s_mfc_lookups)); + printf(" %10llu multicast forwarding cache miss%s\n", + (unsigned long long)mrtstat.mrt6s_mfc_misses, + plurales(mrtstat.mrt6s_mfc_misses)); + printf(" %10llu upcall%s to mrouted\n", + (unsigned long long)mrtstat.mrt6s_upcalls, + plural(mrtstat.mrt6s_upcalls)); + printf(" %10llu upcall llueue overflow%s\n", + (unsigned long long)mrtstat.mrt6s_upq_ovflw, + plural(mrtstat.mrt6s_upq_ovflw)); + printf(" %10llu upcall%s dropped due to full socket buffer\n", + (unsigned long long)mrtstat.mrt6s_upq_sockfull, + plural(mrtstat.mrt6s_upq_sockfull)); + printf(" %10llu cache cleanup%s\n", + (unsigned long long)mrtstat.mrt6s_cache_cleanups, + plural(mrtstat.mrt6s_cache_cleanups)); + printf(" %10llu datagram%s with no route for origin\n", + (unsigned long long)mrtstat.mrt6s_no_route, + plural(mrtstat.mrt6s_no_route)); + printf(" %10llu datagram%s arrived with bad tunneling\n", + (unsigned long long)mrtstat.mrt6s_bad_tunnel, + plural(mrtstat.mrt6s_bad_tunnel)); + printf(" %10llu datagram%s could not be tunneled\n", + (unsigned long long)mrtstat.mrt6s_cant_tunnel, + plural(mrtstat.mrt6s_cant_tunnel)); + printf(" %10llu datagram%s arrived on wrong interface\n", + (unsigned long long)mrtstat.mrt6s_wrong_if, + plural(mrtstat.mrt6s_wrong_if)); + printf(" %10llu datagram%s selectively dropped\n", + (unsigned long long)mrtstat.mrt6s_drop_sel, + plural(mrtstat.mrt6s_drop_sel)); + printf(" %10llu datagram%s dropped due to llueue overflow\n", + (unsigned long long)mrtstat.mrt6s_q_overflow, + plural(mrtstat.mrt6s_q_overflow)); + printf(" %10llu datagram%s dropped for being too large\n", + (unsigned long long)mrtstat.mrt6s_pkt2large, + plural(mrtstat.mrt6s_pkt2large)); +} +#endif /*INET6*/ diff --git a/netstat.tproj/netstat.1 b/netstat.tproj/netstat.1 index fc0d303..de44198 100644 --- a/netstat.tproj/netstat.1 +++ b/netstat.tproj/netstat.1 @@ -30,218 +30,313 @@ .\" SUCH DAMAGE. .\" .\" @(#)netstat.1 8.8 (Berkeley) 4/18/94 +.\" $FreeBSD: src/usr.bin/netstat/netstat.1,v 1.22.2.7 2001/08/10 09:07:09 ru Exp $ .\" -.Dd April 18, 1994 +.Dd June 15, 2001 .Dt NETSTAT 1 -.Os BSD 4.2 +.Os Darwin .Sh NAME .Nm netstat .Nd show network status .Sh SYNOPSIS -.Nm netstat -.Op Fl Aan -.Op Fl f Ar address_family +.Nm +.Op Fl AaLlnW +.Op Fl f Ar address_family | Fl p Ar protocol .Op Fl M Ar core .Op Fl N Ar system -.Nm netstat -.Op Fl dghimnrs +.Nm +.Op Fl gilns .Op Fl f Ar address_family .Op Fl M Ar core .Op Fl N Ar system -.Nm netstat -.Op Fl dn -.Op Fl I Ar interface +.Nm +.Fl i | I Ar interface +.Op Fl w Ar wait +.Op Fl abdgt .Op Fl M Ar core .Op Fl N Ar system -.Op Fl w Ar wait -.Nm netstat -.Op Fl p Ar protocol +.Nm +.Fl s Op Fl s +.Op Fl f Ar address_family | Fl p Ar protocol +.Op Fl M Ar core +.Op Fl N Ar system +.Nm +.Fl i | I Ar interface Fl s +.Op Fl f Ar address_family | Fl p Ar protocol +.Op Fl M Ar core +.Op Fl N Ar system +.Nm +.Fl m .Op Fl M Ar core .Op Fl N Ar system +.Nm +.Fl r +.Op Fl Aaln +.Op Fl f Ar address_family +.Op Fl M Ar core +.Op Fl N Ar system +.Nm +.Fl rs +.Op Fl s +.Op Fl M Ar core +.Op Fl N Ar system +.\"----------------------------------------------------------------------------------------- .Sh DESCRIPTION +.\"----------------------------------------------------------------------------------------- The -.Nm netstat -command symbolically displays the contents of various network-related -data structures. -There are a number of output formats, -depending on the options for the information presented. -The first form of the command displays a list of active sockets for -each protocol. -The second form presents the contents of one of the other network -data structures according to the option selected. -Using the third form, with a +.Nm +command symbolically displays the contents of various network-related data structures. +There are a number of output formats, depending on the options for the information presented. +The first form of the command displays a list of active sockets for each protocol. +The second form presents the contents of one of the other network data structures according +to the option selected. Using the third form, with a .Ar wait interval specified, -.Nm netstat -will continuously display the information regarding packet -traffic on the configured network interfaces. -The fourth form displays statistics about the named protocol. +.Nm +will continuously display the information regarding packet traffic on the configured network +interfaces. The fourth form displays statistics for the specified protocol or address family. +The fifth form displays per-interface statistics for the specified protocol or address family. +The sixth form displays +.Xr mbuf 9 +statistics. The seventh form displays routing table for the specified address family. The +eighth form displays routing statistics. .Pp The options have the following meaning: .Bl -tag -width flag .It Fl A -With the default display, -show the address of any protocol control blocks associated with sockets; used -for debugging. +With the default display, show the address of any protocol control blocks associated with +sockets; used for debugging. .It Fl a -With the default display, -show the state of all sockets; normally sockets used by -server processes are not shown. +With the default display, show the state of all sockets; normally sockets used by server +processes are not shown. With the routing table display (option +.Fl r , +as described below), show protocol-cloned routes (routes generated by a +.Dv RTF_PRCLONING +parent route); normally these routes are not shown. +.It Fl b +With the interface display (option +.Fl i , +as described below), show the number of bytes in and out. .It Fl d With either interface display (option .Fl i -or an interval, as described below), -show the number of dropped packets. -.It Fl f Ar address_family -Limit statistics or address control block reports to those -of the specified +or an interval, as described below), show the number of dropped packets. +.It Fl f Ar address_family +Limit statistics or address control block reports to those of the specified .Ar address family . -The following address families -are recognized: +The following address families are recognized: .Ar inet , for .Dv AF_INET , -.Ar ns , -for -.Dv AF_NS , -.Ar iso , +.Ar inet6 , for -.Dv AF_ISO , +.Dv AF_INET6 and .Ar unix , for .Dv AF_UNIX . .It Fl g -Show information related to multicast (group address) routing. -By default, show the IP Multicast virtual-interface and routing tables. -If the +Show information related to multicast (group address) routing. By default, show the +IP Multicast virtual-interface and routing tables. If the .Fl s option is also present, show multicast routing statistics. -.It Fl h -Show the state of the -.Tn IMP -host table (obsolete). -.It Fl I Ar interface -Show information about the specified interface; -used with a +.It Fl I Ar interface +Show information about the specified interface; used with a .Ar wait interval as described below. -.It Fl i -Show the state of interfaces which have been auto-configured -(interfaces statically configured into a system, but not -located at boot time are not shown). If the +.Fl s +option is present, show per-interface protocol statistics on the +.Ar interface +for the specified +.Ar address_family +or +.Ar protocol , +or for all protocol families. +.It Fl i +Show the state of interfaces which have been auto-configured (interfaces statically +configured into a system, but not located at boot time are not shown). If the .Fl a -options is also present, multicast addresses currently in use are shown -for each Ethernet interface and for each IP interface address. -Multicast addresses are shown on separate lines following the interface -address with which they are associated. +options is also present, multicast addresses currently in use are shown for each +Ethernet interface and for each IP interface address. Multicast addresses are shown +on separate lines following the interface address with which they are associated. +If the +.Fl s +option is present, show per-interface statistics on all interfaces for the specified +.Ar address_family +or +.Ar protocol , +or for all protocol families. +.It Fl L +Show the size of the various listen queues. The first count shows the number of +unaccepted connections. The second count shows the amount of unaccepted incomplete +connections. The third count is the maximum number of queued connections. +.It Fl l +Print full IPv6 address. .It Fl M -Extract values associated with the name list from the specified core -instead of the default +Extract values associated with the name list from the specified core instead of the +default .Pa /dev/kmem . .It Fl m -Show statistics recorded by the memory management routines -(the network manages a private pool of memory buffers). +Show statistics recorded by the memory management routines (the network manages a +private pool of memory buffers). .It Fl N Extract the name list from the specified system instead of the default -.Pa /vmunix . +.Pa /kernel . .It Fl n Show network addresses as numbers (normally -.Nm netstat -interprets addresses and attempts to display them -symbolically). -This option may be used with any of the display formats. -.It Fl p Ar protocol +.Nm +interprets addresses and attempts to display them symbolically). This option may be +used with any of the display formats. +.It Fl p Ar protocol Show statistics about -.Ar protocol , -which is either a well-known name for a protocol or an alias for it. Some -protocol names and aliases are listed in the file +.Ar protocol , +which is either a well-known name for a protocol or an alias for it. Some protocol +names and aliases are listed in the file .Pa /etc/protocols . -A null response typically means that there are no interesting numbers to -report. -The program will complain if +The special protocol name +.Dq bdg +is used to show bridging statistics. A null response typically means that there are +no interesting numbers to report. The program will complain if .Ar protocol is unknown or if there is no statistics routine for it. -.It Fl s -Show per-protocol statistics. -If this option is repeated, counters with a value of zero are suppressed. .It Fl r -Show the routing tables. -When +Show the routing tables. Use with +.Fl a +to show protocol-cloned routes. When .Fl s -is also present, show routing statistics instead. +is also present, show routing statistics instead. When +.Fl l +is also present, +.Nm +assumes more columns are there and the maximum transmission unit +.Pq Dq mtu +are also displayed. +.It Fl s +Show per-protocol statistics. If this option is repeated, counters with a value of +zero are suppressed. +.It Fl W +In certain displays, avoid truncating addresses even if this causes some fields to +overflow. .It Fl w Ar wait Show network interface statistics at intervals of .Ar wait seconds. .El .Pp -The default display, for active sockets, shows the local -and remote addresses, send and receive queue sizes (in bytes), protocol, -and the internal state of the protocol. -Address formats are of the form ``host.port'' or ``network.port'' +.\"------------------------------------------------------------------------------- +.Sh OUTPUT +.\"------------------------------------------------------------------------------- +The default display, for active sockets, shows the local and remote addresses, +send and receive queue sizes (in bytes), protocol, and the internal state of +the protocol. Address formats are of the form +.Dq host.port +or +.Dq network.port if a socket's address specifies a network but no specific host address. -When known the host and network addresses are displayed symbolically -according to the data bases +If known, the host and network addresses are displayed symbolically +according to the databases .Pa /etc/hosts and .Pa /etc/networks , -respectively. If a symbolic name for an address is unknown, or if -the +respectively. If a symbolic name for an address is unknown, or if the .Fl n -option is specified, the address is printed numerically, according -to the address family. -For more information regarding -the Internet ``dot format,'' +option is specified, the address is printed numerically, according to the +address family. For more information regarding the Internet +.Dq dot format , refer to .Xr inet 3 ) . Unspecified, -or ``wildcard'', addresses and ports appear as ``*''. +or +.Dq wildcard , +addresses and ports appear as +.Dq * . +.Pp +Internet domain socket states: +.Bl -column X LISTEN +CLOSED: The socket is not in use. +.Pp +LISTEN: The socket is listening for incoming connections. Unconnected +listening sockets like these are only displayed when using the -a option. +.Pp +SYN_SENT: The socket is actively trying to establish a connection to a +remote peer. .Pp -The interface display provides a table of cumulative -statistics regarding packets transferred, errors, and collisions. -The network addresses of the interface -and the maximum transmission unit (``mtu'') are also displayed. +SYN_RCVD: The socket has passively received a connection request from a +remote peer. .Pp -The routing table display indicates the available routes and -their status. Each route consists of a destination host or network -and a gateway to use in forwarding packets. The flags field shows -a collection of information about the route stored as -binary choices. The individual flags are discussed in more -detail in the +ESTABLISHED: The socket has an established connection between a local +application and a remote peer. +.Pp +CLOSE_WAIT: The socket connection has been closed by the remote peer, +and the system is waiting for the local application to close its half of +the connection. +.Pp +LAST_ACK: The socket connection has been closed by the remote peer, the +local application has closed its half of the connection, and the system +is waiting for the remote peer to acknowledge the close. +.Pp +FIN_WAIT_1: The socket connection has been closed by the local +application, the remote peer has not yet acknowledged the close, and the +system is waiting for it to close its half of the connection. +.Pp +FIN_WAIT_2: The socket connection has been closed by the local +application, the remote peer has acknowledged the close, and the system +is waiting for it to close its half of the connection. +.Pp +CLOSING: The socket connection has been closed by the local application +and the remote peer simultaneously, and the remote peer has not yet +acknowledged the close attempt of the local application. +.Pp +TIME_WAIT: The socket connection has been closed by the local +application, the remote peer has closed its half of the connection, and +the system is waiting to be sure that the remote peer received the last +acknowledgement. +.El +.Pp +The interface display provides a table of cumulative statistics regarding +packets transferred, errors, and collisions. The network addresses of the +interface and the maximum transmission unit +.Pq Dq mtu +are also displayed. +.Pp +The routing table display indicates the available routes and their status. +Each route consists of a destination host or network and a gateway to use +in forwarding packets. The flags field shows a collection of information +about the route stored as binary choices. The individual flags are discussed +in more detail in the .Xr route 8 and .Xr route 4 -manual pages. -The mapping between letters and flags is: +manual pages. The mapping between letters and flags is: .Bl -column XXXX RTF_BLACKHOLE -1 RTF_PROTO2 Protocol specific routing flag #1 -2 RTF_PROTO1 Protocol specific routing flag #2 -B RTF_BLACKHOLE Just discard pkts (during updates) -C RTF_CLONING Generate new routes on use -D RTF_DYNAMIC Created dynamically (by redirect) +1 RTF_PROTO1 Protocol specific routing flag #1 +2 RTF_PROTO2 Protocol specific routing flag #2 +3 RTF_PROTO3 Protocol specific routing flag #3 +B RTF_BLACKHOLE Just discard packets (during updates) +b RTF_BROADCAST The route represents a broadcast address +C RTF_CLONING Generate new routes on use +c RTF_PRCLONING Protocol-specified generate new routes on use +D RTF_DYNAMIC Created dynamically (by redirect) G RTF_GATEWAY Destination requires forwarding by intermediary -H RTF_HOST Host entry (net otherwise) -L RTF_LLINFO Valid protocol to link address translation. -M RTF_MODIFIED Modified dynamically (by redirect) -R RTF_REJECT Host or net unreachable -S RTF_STATIC Manually added -U RTF_UP Route usable +H RTF_HOST Host entry (net otherwise) +L RTF_LLINFO Valid protocol to link address translation +M RTF_MODIFIED Modified dynamically (by redirect) +R RTF_REJECT Host or net unreachable +S RTF_STATIC Manually added +U RTF_UP Route usable +W RTF_WASCLONED Route was generated as a result of cloning X RTF_XRESOLVE External daemon translates proto to link address .El .Pp -Direct routes are created for each -interface attached to the local host; -the gateway field for such entries shows the address of the outgoing interface. -The refcnt field gives the -current number of active uses of the route. Connection oriented -protocols normally hold on to a single route for the duration of -a connection while connectionless protocols obtain a route while sending -to the same destination. -The use field provides a count of the number of packets -sent using that route. The interface entry indicates the network -interface utilized for the route. +Direct routes are created for each interface attached to the local host; +the gateway field for such entries shows the address of the outgoing +interface. The refcnt field gives the current number of active uses of +the route. Connection oriented protocols normally hold on to a single +route for the duration of a connection while connectionless protocols +obtain a route while sending to the same destination. The use field +provides a count of the number of packets sent using that route. The +interface entry indicates the network interface utilized for the route. .Pp When .Nm netstat @@ -250,40 +345,39 @@ is invoked with the option and a .Ar wait interval argument, it displays a running count of statistics related to -network interfaces. -An obsolescent version of this option used a numeric parameter -with no option, and is currently supported for backward compatibility. -This display consists of a column for the primary interface (the first -interface found during autoconfiguration) and a column summarizing -information for all interfaces. -The primary interface may be replaced with another interface with the +network interfaces. An obsolete version of this option used a numeric +parameter with no option, and is currently supported for backward +compatibility. By default, this display summarizes information for all +interfaces. Information for a specific interface may be displayed with the .Fl I option. -The first line of each screen of information contains a summary since the -system was last rebooted. Subsequent lines of output show values -accumulated over the preceding interval. .Sh SEE ALSO -.Xr iostat 1 , +.Xr fstat 1 , .Xr nfsstat 1 , .Xr ps 1 , -.Xr vmstat 1 , +.Xr sockstat 1 , +.Xr inet 4 , +.Xr unix 4 , .Xr hosts 5 , .Xr networks 5 , .Xr protocols 5 , .Xr services 5 , +.Xr iostat 8 , .Xr trpt 8 , -.Xr trsp 8 +.Xr vmstat 8 .Sh HISTORY The .Nm netstat command appeared in .Bx 4.2 . -.\" .Sh FILES -.\" .Bl -tag -width /dev/kmem -compact -.\" .It Pa /vmunix -.\" default kernel namelist -.\" .It Pa /dev/kmem -.\" default memory file -.\" .El +.Pp +IPv6 support was added by WIDE/KAME project. +.Sh FILES +.Bl -tag -width /dev/kmem -compact +.It Pa /kernel +default kernel namelist +.It Pa /dev/kmem +default memory file +.El .Sh BUGS The notion of errors is ill-defined. diff --git a/netstat.tproj/netstat.h b/netstat.tproj/netstat.h index 8a70629..b64150a 100644 --- a/netstat.tproj/netstat.h +++ b/netstat.tproj/netstat.h @@ -59,91 +59,118 @@ #include #include -#ifndef EXTERN -#define EXTERN extern +extern int Aflag; /* show addresses of protocol control block */ +extern int aflag; /* show all sockets (including servers) */ +extern int bflag; /* show i/f total bytes in/out */ +extern int dflag; /* show i/f dropped packets */ +extern int gflag; /* show group (multicast) routing or stats */ +extern int iflag; /* show interfaces */ +extern int lflag; /* show routing table with use and ref */ +extern int Lflag; /* show size of listen queues */ +extern int mflag; /* show memory stats */ +extern int nflag; /* show addresses numerically */ +extern int rflag; /* show routing tables (or routing stats) */ +extern int sflag; /* show protocol statistics */ +extern int tflag; /* show i/f watchdog timers */ +extern int Wflag; /* wide display */ + +extern int interval; /* repeat interval for i/f stats */ + +extern char *interface; /* desired i/f for stats, or NULL for all i/fs */ +extern int unit; /* unit number for above */ + +extern int af; /* address family */ + +int kread (u_long addr, char *buf, int size); +char *plural (int); +char *plurales (int); + +void protopr (u_long, char *, int); +void tcp_stats (u_long, char *, int); +void udp_stats (u_long, char *, int); +void ip_stats (u_long, char *, int); +void icmp_stats (u_long, char *, int); +void igmp_stats (u_long, char *, int); +#ifdef IPSEC +void ipsec_stats (u_long, char *, int); #endif -EXTERN int Aflag; /* show addresses of protocol control block */ -EXTERN int aflag; /* show all sockets (including servers) */ -EXTERN int bflag; /* show i/f total bytes in/out */ -EXTERN int dflag; /* show i/f dropped packets */ -EXTERN int gflag; /* show group (multicast) routing or stats */ -EXTERN int iflag; /* show static interfaces */ -EXTERN int mflag; /* show memory stats */ -EXTERN int nflag; /* show addresses numerically */ -EXTERN int pflag; /* show given protocol */ -EXTERN int rflag; /* show routing tables (or routing stats) */ -EXTERN int sflag; /* show protocol statistics */ -EXTERN int tflag; /* show i/f watchdog timers */ - -EXTERN int interval; /* repeat interval for i/f stats */ - -EXTERN char *interface; /* desired i/f for stats, or NULL for all i/fs */ -EXTERN int unit; /* unit number for above */ - -EXTERN int af; /* address family */ - -int kread __P((u_long addr, char *buf, int size)); -char *plural __P((int)); -char *plurales __P((int)); -void trimdomain __P((char *)); - -void protopr __P((u_long, char *)); -void tcp_stats __P((u_long, char *)); -void udp_stats __P((u_long, char *)); -void ip_stats __P((u_long, char *)); -void icmp_stats __P((u_long, char *)); -void igmp_stats __P((u_long, char *)); -void protopr __P((u_long, char *)); - -void mbpr __P((u_long)); - -void hostpr __P((u_long, u_long)); -void impstats __P((u_long, u_long)); - -void intpr __P((int, u_long)); - -void pr_rthdr __P(()); -void pr_family __P((int)); -void rt_stats __P((u_long)); -char *ipx_pnet __P((struct sockaddr *)); -char *ipx_phost __P((struct sockaddr *)); -char *ns_phost __P((struct sockaddr *)); -void upHex __P((char *)); - -char *routename __P((u_long)); -char *netname __P((u_long, u_long)); -char *atalk_print __P((struct sockaddr *, int)); -char *atalk_print2 __P((struct sockaddr *, struct sockaddr *, int)); -char *ipx_print __P((struct sockaddr *)); -char *ns_print __P((struct sockaddr *)); -void routepr __P((u_long)); - -void ipxprotopr __P((u_long, char *)); -void spx_stats __P((u_long, char *)); -void ipx_stats __P((u_long, char *)); -void ipxerr_stats __P((u_long, char *)); - -void nsprotopr __P((u_long, char *)); -void spp_stats __P((u_long, char *)); -void idp_stats __P((u_long, char *)); -void nserr_stats __P((u_long, char *)); - -void atalkprotopr __P((u_long, char *)); -void ddp_stats __P((u_long, char *)); - -void intpr __P((int, u_long)); - -void unixpr __P((void)); - -void esis_stats __P((u_long, char *)); -void clnp_stats __P((u_long, char *)); -void cltp_stats __P((u_long, char *)); -void iso_protopr __P((u_long, char *)); -void iso_protopr1 __P((u_long, int)); -void tp_protopr __P((u_long, char *)); -void tp_inproto __P((u_long)); -void tp_stats __P((caddr_t, caddr_t)); - -void mroutepr __P((u_long, u_long)); -void mrt_stats __P((u_long)); + +#ifdef INET6 +void ip6_stats (u_long, char *, int); +void ip6_ifstats (char *); +void icmp6_stats (u_long, char *, int); +void icmp6_ifstats (char *); +void pim6_stats (u_long, char *, int); +void rip6_stats (u_long, char *, int); +void mroute6pr (u_long, u_long); +void mrt6_stats (u_long); + +struct sockaddr_in6; +struct in6_addr; +char *routename6 (struct sockaddr_in6 *); +char *netname6 (struct sockaddr_in6 *, struct in6_addr *); +#endif /*INET6*/ + +#ifdef IPSEC +void pfkey_stats (u_long, char *, int); +#endif + +void bdg_stats (u_long, char *, int); + +//void mbpr (u_long, u_long, u_long, u_long); +void mbpr (u_long); + +void hostpr (u_long, u_long); +void impstats (u_long, u_long); + +void intpr (int, u_long, void (*)(char *)); + +void pr_rthdr (int); +void pr_family (int); +void rt_stats (u_long, u_long); +char *ipx_pnet (struct sockaddr *); +char *ipx_phost (struct sockaddr *); +char *ns_phost (struct sockaddr *); +void upHex (char *); + +char *routename (u_long); +char *netname (u_long, u_long); +#if 0 +char *atalk_print (struct sockaddr *, int); +char *atalk_print2 (struct sockaddr *, struct sockaddr *, int); +char *ipx_print (struct sockaddr *); +char *ns_print (struct sockaddr *); +#endif +void routepr (u_long); + +#if 0 +void ipxprotopr (u_long, char *, int); +void spx_stats (u_long, char *, int); +void ipx_stats (u_long, char *, int); +void ipxerr_stats (u_long, char *, int); + +void nsprotopr (u_long, char *, int); +void spp_stats (u_long, char *, int); +void idp_stats (u_long, char *, int); +void nserr_stats (u_long, char *, int); + +void atalkprotopr (u_long, char *, int); +void ddp_stats (u_long, char *, int); + +void netgraphprotopr (u_long, char *, int); +#endif + +void unixpr (void); + +void esis_stats (u_long, char *, int); +void clnp_stats (u_long, char *, int); +void cltp_stats (u_long, char *, int); +void iso_protopr (u_long, char *, int); +void iso_protopr1 (u_long, int); +void tp_protopr (u_long, char *, int); +void tp_inproto (u_long); +void tp_stats (caddr_t, caddr_t); + +void mroutepr (u_long, u_long); +void mrt_stats (u_long); diff --git a/netstat.tproj/route.c b/netstat.tproj/route.c index 84b945a..5a3bfb1 100644 --- a/netstat.tproj/route.c +++ b/netstat.tproj/route.c @@ -59,7 +59,7 @@ static char sccsid[] = "From: @(#)route.c 8.6 (Berkeley) 4/28/95"; #endif static const char rcsid[] = - "$Id: route.c,v 1.1.1.2 2000/01/11 01:48:53 wsanchez Exp $"; + "$Id: route.c,v 1.3 2002/03/05 20:35:15 lindak Exp $"; #endif /* not lint */ #include @@ -74,10 +74,10 @@ static const char rcsid[] = #include #include - -#ifdef IPX +#ifndef __APPLE__ #include #include +#include #endif #ifdef NS @@ -86,6 +86,10 @@ static const char rcsid[] = #include +#include +#ifndef __APPLE__ +#include +#endif #include #include #include @@ -97,6 +101,12 @@ static const char rcsid[] = #define kget(p, d) (kread((u_long)(p), (char *)&(d), sizeof (d))) + +/* alignment constraint for routing socket */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) + /* * Definitions for showing gateway flags. */ @@ -156,8 +166,7 @@ static void domask __P((char *, u_long, u_long)); * Print routing tables. */ void -routepr(rtree) - u_long rtree; +routepr(u_long rtree) { struct radix_node_head *rnh, head; int i; @@ -185,7 +194,7 @@ routepr(rtree) } else if (af == AF_UNSPEC || af == i) { pr_family(i); do_rtent = 1; - pr_rthdr(); + pr_rthdr(i); p_tree(head.rnh_treetop); } } @@ -196,8 +205,7 @@ routepr(rtree) * Print address family header before a section of the routing table. */ void -pr_family(af) - int af; +pr_family(int af) { char *afname; @@ -205,18 +213,20 @@ pr_family(af) case AF_INET: afname = "Internet"; break; - -#ifdef IPX +#ifdef INET6 + case AF_INET6: + afname = "Internet6"; + break; +#endif /*INET6*/ case AF_IPX: afname = "IPX"; break; -#endif - #ifdef NS case AF_NS: afname = "XNS"; break; #endif +#ifndef __APPLE__ case AF_ISO: afname = "ISO"; break; @@ -226,6 +236,10 @@ pr_family(af) case AF_CCITT: afname = "X.25"; break; + case AF_NETGRAPH: + afname = "Netgraph"; + break; +#endif default: afname = NULL; break; @@ -237,26 +251,49 @@ pr_family(af) } /* column widths; each followed by one space */ -#define WID_DST 18 /* width of destination column */ -#define WID_GW 18 /* width of gateway column */ +#ifndef INET6 +#define WID_DST(af) 18 /* width of destination column */ +#define WID_GW(af) 18 /* width of gateway column */ +#define WID_IF(af) 6 /* width of netif column */ +#else +#define WID_DST(af) \ + ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 33: 18)) : 18) +#define WID_GW(af) \ + ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 29 : 18)) : 18) +#define WID_IF(af) ((af) == AF_INET6 ? 8 : 6) +#endif /*INET6*/ /* * Print header for routing table columns. */ void -pr_rthdr() +pr_rthdr(int af) { + if (Aflag) printf("%-8.8s ","Address"); - printf("%-*.*s %-*.*s %-6.6s %6.6s%8.8s %8.8s %6s\n", - WID_DST, WID_DST, "Destination", - WID_GW, WID_GW, "Gateway", - "Flags", "Refs", "Use", "Netif", "Expire"); + if (af == AF_INET || lflag) + if (lflag) + printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %6.6s %*.*s %6s\n", + WID_DST(af), WID_DST(af), "Destination", + WID_GW(af), WID_GW(af), "Gateway", + "Flags", "Refs", "Use", "Mtu", + WID_IF(af), WID_IF(af), "Netif", "Expire"); + else + printf("%-*.*s %-*.*s %-6.6s %6.6s %8.8s %*.*s %6s\n", + WID_DST(af), WID_DST(af), "Destination", + WID_GW(af), WID_GW(af), "Gateway", + "Flags", "Refs", "Use", + WID_IF(af), WID_IF(af), "Netif", "Expire"); + else + printf("%-*.*s %-*.*s %-6.6s %8.8s %6s\n", + WID_DST(af), WID_DST(af), "Destination", + WID_GW(af), WID_GW(af), "Gateway", + "Flags", "Netif", "Expire"); } static struct sockaddr * -kgetsa(dst) - register struct sockaddr *dst; +kgetsa(struct sockaddr *dst) { kget(dst, pt_u.u_sa); @@ -266,13 +303,12 @@ kgetsa(dst) } static void -p_tree(rn) - struct radix_node *rn; +p_tree(struct radix_node *rn) { again: kget(rn, rnode); - if (rnode.rn_b < 0) { + if (rnode.rn_bit < 0) { if (Aflag) printf("%-8.8lx ", (u_long)rn); if (rnode.rn_flags & RNF_ROOT) { @@ -296,8 +332,8 @@ again: printf("%-8.8lx ", (u_long)rn); p_rtnode(); } - rn = rnode.rn_r; - p_tree(rnode.rn_l); + rn = rnode.rn_right; + p_tree(rnode.rn_left); p_tree(rn); } } @@ -305,11 +341,11 @@ again: char nbuf[20]; static void -p_rtnode() +p_rtnode(void) { struct radix_mask *rm = rnode.rn_mklist; - if (rnode.rn_b < 0) { + if (rnode.rn_bit < 0) { if (rnode.rn_mask) { printf("\t mask "); p_sockaddr(kgetsa((struct sockaddr *)rnode.rn_mask), @@ -317,14 +353,14 @@ p_rtnode() } else if (rm == 0) return; } else { - sprintf(nbuf, "(%d)", rnode.rn_b); - printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_l, (u_long)rnode.rn_r); + sprintf(nbuf, "(%d)", rnode.rn_bit); + printf("%6.6s %8.8lx : %8.8lx", nbuf, (u_long)rnode.rn_left, (u_long)rnode.rn_right); } while (rm) { kget(rm, rmask); sprintf(nbuf, " %d refs, ", rmask.rm_refs); printf(" mk = %8.8lx {(%d),%s", - (u_long)rm, -1 - rmask.rm_b, rmask.rm_refs ? nbuf : " "); + (u_long)rm, -1 - rmask.rm_bit, rmask.rm_refs ? nbuf : " "); if (rmask.rm_flags & RNF_NORMAL) { struct radix_node rnode_aux; printf(" , "); @@ -342,7 +378,7 @@ p_rtnode() } static void -ntreestuff() +ntreestuff(void) { size_t needed; int mib[6]; @@ -373,8 +409,7 @@ ntreestuff() } static void -np_rtentry(rtm) - register struct rt_msghdr *rtm; +np_rtentry(struct rt_msghdr *rtm) { register struct sockaddr *sa = (struct sockaddr *)(rtm + 1); #ifdef notdef @@ -405,9 +440,7 @@ np_rtentry(rtm) p_sockaddr(sa, NULL, 0, 36); else { p_sockaddr(sa, NULL, rtm->rtm_flags, 16); - if (sa->sa_len == 0) - sa->sa_len = sizeof(long); - sa = (struct sockaddr *)(sa->sa_len + (char *)sa); + sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); p_sockaddr(sa, NULL, 0, 18); } p_flags(rtm->rtm_flags & interesting, "%-6.6s "); @@ -415,9 +448,7 @@ np_rtentry(rtm) } static void -p_sockaddr(sa, mask, flags, width) - struct sockaddr *sa, *mask; - int flags, width; +p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width) { char workbuf[128], *cplim; register char *cp = workbuf; @@ -427,8 +458,11 @@ p_sockaddr(sa, mask, flags, width) { register struct sockaddr_in *sin = (struct sockaddr_in *)sa; - if (sin->sin_addr.s_addr == INADDR_ANY) - cp = "default"; + if ((sin->sin_addr.s_addr == INADDR_ANY) && + mask && + ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) + ==0L) + cp = "default" ; else if (flags & RTF_HOST) cp = routename(sin->sin_addr.s_addr); else if (mask) @@ -439,7 +473,36 @@ p_sockaddr(sa, mask, flags, width) cp = netname(sin->sin_addr.s_addr, 0L); break; } -#ifdef IPX + +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; + struct in6_addr *in6 = &sa6->sin6_addr; + + /* + * XXX: This is a special workaround for KAME kernels. + * sin6_scope_id field of SA should be set in the future. + */ + if (IN6_IS_ADDR_LINKLOCAL(in6) || + IN6_IS_ADDR_MC_LINKLOCAL(in6)) { + /* XXX: override is ok? */ + sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]); + *(u_short *)&in6->s6_addr[2] = 0; + } + + if (flags & RTF_HOST) + cp = routename6(sa6); + else if (mask) + cp = netname6(sa6, + &((struct sockaddr_in6 *)mask)->sin6_addr); + else { + cp = netname6(sa6, NULL); + } + break; + } +#endif /*INET6*/ +#ifndef __APPLE__ case AF_IPX: { struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr; @@ -449,9 +512,6 @@ p_sockaddr(sa, mask, flags, width) cp = ipx_print(sa); break; } -#endif - -#if 0 case AF_APPLETALK: { if (!(flags & RTF_HOST) && mask) @@ -460,8 +520,12 @@ p_sockaddr(sa, mask, flags, width) cp = atalk_print(sa,11); break; } + case AF_NETGRAPH: + { + printf("%s", ((struct sockaddr_ng *)sa)->sg_data); + break; + } #endif - #ifdef NS case AF_NS: cp = ns_print(sa); @@ -526,9 +590,7 @@ p_sockaddr(sa, mask, flags, width) } static void -p_flags(f, format) - register int f; - char *format; +p_flags(int f, char *format) { char name[33], *flags; register struct bits *p = bits; @@ -541,10 +603,10 @@ p_flags(f, format) } static void -p_rtentry(rt) - register struct rtentry *rt; +p_rtentry(struct rtentry *rt) { static struct ifnet ifnet, *lastif; + struct rtentry parent; static char name[16]; static char prettyname[9]; struct sockaddr *sa; @@ -553,8 +615,11 @@ p_rtentry(rt) /* * Don't print protocol-cloned routes unless -a. */ - if (rt->rt_parent && !aflag) - return; + if (rt->rt_flags & RTF_WASCLONED && !aflag) { + kget(rt->rt_parent, parent); + if (parent.rt_flags & RTF_PRCLONING) + return; + } bzero(&addr, sizeof(addr)); if ((sa = kgetsa(rt_key(rt)))) @@ -562,40 +627,48 @@ p_rtentry(rt) bzero(&mask, sizeof(mask)); if (rt_mask(rt) && (sa = kgetsa(rt_mask(rt)))) bcopy(sa, &mask, sa->sa_len); - p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, WID_DST); - p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, WID_GW); + p_sockaddr(&addr.u_sa, &mask.u_sa, rt->rt_flags, + WID_DST(addr.u_sa.sa_family)); + p_sockaddr(kgetsa(rt->rt_gateway), NULL, RTF_HOST, + WID_GW(addr.u_sa.sa_family)); p_flags(rt->rt_flags, "%-6.6s "); - printf("%6d %8ld ", rt->rt_refcnt, rt->rt_use); + if (addr.u_sa.sa_family == AF_INET || lflag) { + printf("%6ld %8ld ", rt->rt_refcnt, rt->rt_use); + if (lflag) { + if (rt->rt_rmx.rmx_mtu != 0) + printf("%6lu ", rt->rt_rmx.rmx_mtu); + else + printf("%6s ", ""); + } + } if (rt->rt_ifp) { if (rt->rt_ifp != lastif) { kget(rt->rt_ifp, ifnet); kread((u_long)ifnet.if_name, name, 16); lastif = rt->rt_ifp; snprintf(prettyname, sizeof prettyname, - "%.6s%d", name, ifnet.if_unit); + "%s%d", name, ifnet.if_unit); } - printf("%8.8s", prettyname); + printf("%*.*s", WID_IF(addr.u_sa.sa_family), + WID_IF(addr.u_sa.sa_family), prettyname); if (rt->rt_rmx.rmx_expire) { time_t expire_time; if ((expire_time = rt->rt_rmx.rmx_expire - time((time_t *)0)) > 0) - printf(" %6d%s", (int)expire_time, - rt->rt_nodes[0].rn_dupedkey ? " =>" : ""); - } else if (rt->rt_nodes[0].rn_dupedkey) { - printf(" =>"); + printf(" %6d", (int)expire_time); } - + if (rt->rt_nodes[0].rn_dupedkey) + printf(" =>"); } putchar('\n'); } char * -routename(in) - u_long in; +routename(u_long in) { register char *cp; - static char line[MAXHOSTNAMELEN + 1]; + static char line[MAXHOSTNAMELEN]; struct hostent *hp; cp = 0; @@ -604,7 +677,7 @@ routename(in) AF_INET); if (hp) { cp = hp->h_name; - trimdomain(cp); + //### trimdomain(cp, strlen(cp)); } } if (cp) { @@ -620,8 +693,7 @@ routename(in) } static u_long -forgemask(a) - u_long a; +forgemask(u_long a) { u_long m; @@ -635,9 +707,7 @@ forgemask(a) } static void -domask(dst, addr, mask) - char *dst; - u_long addr, mask; +domask(char *dst, u_long addr, u_long mask) { register int b, i; @@ -669,74 +739,182 @@ domask(dst, addr, mask) * The address is assumed to be that of a net or subnet, not a host. */ char * -netname(in, mask) - u_long in, mask; +netname(u_long in, u_long mask) { char *cp = 0; - static char line[MAXHOSTNAMELEN + 1]; + static char line[MAXHOSTNAMELEN]; struct netent *np = 0; u_long net, omask, dmask; register u_long i; i = ntohl(in); + dmask = forgemask(i); omask = mask; if (!nflag && i) { - dmask = forgemask(i); net = i & dmask; if (!(np = getnetbyaddr(i, AF_INET)) && net != i) np = getnetbyaddr(net, AF_INET); if (np) { cp = np->n_name; - trimdomain(cp); + //### trimdomain(cp, strlen(cp)); } } if (cp) strncpy(line, cp, sizeof(line) - 1); - else if ((i & 0xffffff) == 0) - sprintf(line, "%lu", C(i >> 24)); - else if ((i & 0xffff) == 0) - sprintf(line, "%lu.%lu", C(i >> 24) , C(i >> 16)); - else if ((i & 0xff) == 0) - sprintf(line, "%lu.%lu.%lu", C(i >> 24), C(i >> 16), C(i >> 8)); - else - sprintf(line, "%lu.%lu.%lu.%lu", C(i >> 24), - C(i >> 16), C(i >> 8), C(i)); + else { + switch (dmask) { + case IN_CLASSA_NET: + if ((i & IN_CLASSA_HOST) == 0) { + sprintf(line, "%lu", C(i >> 24)); + break; + } + /* FALLTHROUGH */ + case IN_CLASSB_NET: + if ((i & IN_CLASSB_HOST) == 0) { + sprintf(line, "%lu.%lu", + C(i >> 24), C(i >> 16)); + break; + } + /* FALLTHROUGH */ + case IN_CLASSC_NET: + if ((i & IN_CLASSC_HOST) == 0) { + sprintf(line, "%lu.%lu.%lu", + C(i >> 24), C(i >> 16), C(i >> 8)); + break; + } + /* FALLTHROUGH */ + default: + sprintf(line, "%lu.%lu.%lu.%lu", + C(i >> 24), C(i >> 16), C(i >> 8), C(i)); + break; + } + } domask(line+strlen(line), i, omask); return (line); } +#ifdef INET6 +char * +netname6(struct sockaddr_in6 *sa6, struct in6_addr *mask) +{ + static char line[MAXHOSTNAMELEN]; + u_char *p = (u_char *)mask; + u_char *lim; + int masklen, illegal = 0, flag = NI_WITHSCOPEID; + + if (mask) { + for (masklen = 0, lim = p + 16; p < lim; p++) { + switch (*p) { + case 0xff: + masklen += 8; + break; + case 0xfe: + masklen += 7; + break; + case 0xfc: + masklen += 6; + break; + case 0xf8: + masklen += 5; + break; + case 0xf0: + masklen += 4; + break; + case 0xe0: + masklen += 3; + break; + case 0xc0: + masklen += 2; + break; + case 0x80: + masklen += 1; + break; + case 0x00: + break; + default: + illegal ++; + break; + } + } + if (illegal) + fprintf(stderr, "illegal prefixlen\n"); + } + else + masklen = 128; + + if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr)) + return("default"); + + if (nflag) + flag |= NI_NUMERICHOST; + getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line), + NULL, 0, flag); + + if (nflag) + sprintf(&line[strlen(line)], "/%d", masklen); + + return line; +} + +char * +routename6(struct sockaddr_in6 *sa6) +{ + static char line[MAXHOSTNAMELEN]; + int flag = NI_WITHSCOPEID; + /* use local variable for safety */ + struct sockaddr_in6 sa6_local = {AF_INET6, sizeof(sa6_local),}; + + sa6_local.sin6_addr = sa6->sin6_addr; + sa6_local.sin6_scope_id = sa6->sin6_scope_id; + + if (nflag) + flag |= NI_NUMERICHOST; + + getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len, + line, sizeof(line), NULL, 0, flag); + + return line; +} +#endif /*INET6*/ + /* * Print routing statistics */ void -rt_stats(off) - u_long off; +rt_stats(u_long rtsaddr, u_long rttaddr) { struct rtstat rtstat; + int rttrash; - if (off == 0) { + if (rtsaddr == 0) { printf("rtstat: symbol not in namelist\n"); return; } - kread(off, (char *)&rtstat, sizeof (rtstat)); + if (rttaddr == 0) { + printf("rttrash: symbol not in namelist\n"); + return; + } + kread(rtsaddr, (char *)&rtstat, sizeof (rtstat)); + kread(rttaddr, (char *)&rttrash, sizeof (rttrash)); printf("routing:\n"); - printf("\t%u bad routing redirect%s\n", - rtstat.rts_badredirect, plural(rtstat.rts_badredirect)); - printf("\t%u dynamically created route%s\n", - rtstat.rts_dynamic, plural(rtstat.rts_dynamic)); - printf("\t%u new gateway%s due to redirects\n", - rtstat.rts_newgateway, plural(rtstat.rts_newgateway)); - printf("\t%u destination%s found unreachable\n", - rtstat.rts_unreach, plural(rtstat.rts_unreach)); - printf("\t%u use%s of a wildcard route\n", - rtstat.rts_wildcard, plural(rtstat.rts_wildcard)); -} -#ifdef IPX +#define p(f, m) if (rtstat.f || sflag <= 1) \ + printf(m, rtstat.f, plural(rtstat.f)) + + p(rts_badredirect, "\t%u bad routing redirect%s\n"); + p(rts_dynamic, "\t%u dynamically created route%s\n"); + p(rts_newgateway, "\t%u new gateway%s due to redirects\n"); + p(rts_unreach, "\t%u destination%s found unreachable\n"); + p(rts_wildcard, "\t%u use%s of a wildcard route\n"); +#undef p + if (rttrash || sflag <= 1) + printf("\t%u route%s not in table but not freed\n", + rttrash, plural(rttrash)); +} +#ifndef __APPLE__ char * -ipx_print(sa) - register struct sockaddr *sa; +ipx_print(struct sockaddr *sa) { u_short port; struct servent *sp = 0; @@ -805,8 +983,7 @@ ipx_print(sa) } char * -ipx_phost(sa) - struct sockaddr *sa; +ipx_phost(struct sockaddr *sa) { register struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)sa; struct sockaddr_ipx work; @@ -825,14 +1002,12 @@ ipx_phost(sa) return(p); } #endif - #ifdef NS short ns_nullh[] = {0,0,0}; short ns_bh[] = {-1,-1,-1}; char * -ns_print(sa) - register struct sockaddr *sa; +ns_print(struct sockaddr *sa) { register struct sockaddr_ns *sns = (struct sockaddr_ns*)sa; struct ns_addr work; @@ -878,8 +1053,7 @@ ns_print(sa) } char * -ns_phost(sa) - struct sockaddr *sa; +ns_phost(struct sockaddr *sa) { register struct sockaddr_ns *sns = (struct sockaddr_ns *)sa; struct sockaddr_ns work; @@ -898,8 +1072,7 @@ ns_phost(sa) #endif void -upHex(p0) - char *p0; +upHex(char *p0) { register char *p = p0; diff --git a/newclient.tproj/Makefile b/newclient.tproj/Makefile deleted file mode 100644 index e822c95..0000000 --- a/newclient.tproj/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# Stubbed Legacy Makefile for the newclient script -# - -NAME = newclient - -OTHERSRCS = Makefile Makefile.preamble newclient.csh - -MAKEFILEDIR = $(MAKEFILEPATH)/project -MAKEFILE = common.make - -# INSTALL is already set to "install -S" -XINSTALL = install - -INSTALLDIR=/usr/sbin - --include Makefile.preamble - -include $(MAKEFILEDIR)/$(MAKEFILE) - --include Makefile.postamble - --include Makefile.dependencies - -all project $(NAME): - -install: - @dstdir=$(DSTROOT)`grep NEXTSTEP_INSTALLDIR PB.project | sed 's/.*= \(.*\);.*/\1/'`; \ - if [ ! -d $$dstdir ]; then \ - $(MKDIRS) $$dstdir; \ - fi; \ - $(RM) -f $$dstdir/$(NAME); \ - echo $(XINSTALL) -c -o $(INSTALL_AS_USER) -g $(INSTALL_AS_GROUP) \ - -m 555 newclient.csh $$dstdir/$(NAME); \ - $(XINSTALL) -c -o $(INSTALL_AS_USER) -g $(INSTALL_AS_GROUP) \ - -m 555 newclient.csh $$dstdir/$(NAME) diff --git a/newclient.tproj/Makefile.preamble b/newclient.tproj/Makefile.preamble deleted file mode 100644 index fe326e5..0000000 --- a/newclient.tproj/Makefile.preamble +++ /dev/null @@ -1 +0,0 @@ --include ../Makefile.include diff --git a/newclient.tproj/newclient.csh b/newclient.tproj/newclient.csh deleted file mode 100644 index af24796..0000000 --- a/newclient.tproj/newclient.csh +++ /dev/null @@ -1,233 +0,0 @@ -#! /bin/csh -f -## -# Copyright (c) 1999 Apple Computer, Inc. All rights reserved. -# -# @APPLE_LICENSE_HEADER_START@ -# -# "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights -# Reserved. This file contains Original Code and/or Modifications of -# Original Code as defined in and that are subject to the Apple Public -# Source License Version 1.0 (the 'License'). You may not use this file -# except in compliance with the License. Please obtain a copy of the -# License at http://www.apple.com/publicsource and read it before using -# this file. -# -# The Original Code and all software distributed under the License are -# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, -# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the -# License for the specific language governing rights and limitations -# under the License." -# -# @APPLE_LICENSE_HEADER_END@ -## -# -# newclient -# -# NetBoot client building script. -# -# Copyright (c) 1988, NeXT, Inc. -# -# Usage: -# "newclient -p DISKTYPE TEMPLATE DEST" Standalone Private -# "newclient [-s SERVER] CLIENT-1 ... CLIENT-n" Clients -# - -# -# Constants -# -set path=(/bin /usr/bin /usr/ucb /usr/etc /etc) -set TESTDIR -set CLIENTDIR=${TESTDIR}/clients -set template=${TESTDIR}/usr/template/client -set HOSTFILE=${TESTDIR}/etc/hosts -set BOOTPTAB=${TESTDIR}/etc/bootptab - -# We are the default server -set server=`hostname` - -# Are we root? -if ( `whoami` != root ) then - echo "You must be root to run $0" - exit(1) -endif - -# Preliminary argument checkout -if ( $#argv < 1 ) then - goto usage -endif - -# Switches must be at argv[1] -foreach arg ( $argv[2-] ) - if ( x$arg =~ x-* ) then - goto usage - endif -end - -# Parse the switches -if ( $argv[1] == -p || $argv[1] == -P ) then - if ( $#argv != 4 ) then - goto usage - endif - set PrivateMode - set disktype=$argv[2] - set template=$argv[3] - set dest=$argv[4] - if ( $argv[1] == -P ) then - set swapsize=1b - else - set swapsize=16m - endif - - # Check that the disk type is valid - if ( ! -e $template/etc/fstab.$disktype ) then - echo "Unknown disk type" $disktype - exit(1) - endif -else if ( $argv[1] == -s ) then - if ( $#argv < 3 ) then - goto usage - endif - set server=$argv[2] - shift - shift -else if ( $argv[1] =~ -* ) then - goto usage -endif - -# Make sure we have a template to work with -if ( ! -d $template ) then - echo "New client template $template does not exist" - exit(1) -endif - -# Process the private partition if that is the mode we are in. -if ( $?PrivateMode ) then - if ( -e $dest ) then - echo "$dest already exists" - exit(1) - endif - - # Create the destination directory - echo -n "Creating ${dest}..." - mkdir $dest - chmod 775 $dest - chown root.staff $dest - if ( $status != 0 ) then - echo "failed" - exit(1) - endif - echo "[OK]" - - # Copy the template into it - echo -n "Copying ${template} into ${dest}..." - (cd $template; tar cf - .)|(cd $dest; tar xpBf -) - echo "[OK]" - - # Make the device files - echo -n "Making devices in ${dest}/dev..." - (cd ${dest}/dev; /usr/etc/MAKEDEV NeXT) - echo "[OK]" - - # Customize the fstab file - echo -n "Installing fstab.$disktype as ${dest}/etc/fstab..." - cp -p $dest/etc/fstab.${disktype} $dest/etc/fstab - if ( $status != 0 ) then - echo "failed" - exit(1) - endif - echo "[OK]" - - # Touch the first 16 Meg of the swapfile - echo -n "Preallocating swapfile blocks..." - (cd ${dest}/vm; /bin/rm -f swapfile; /usr/etc/mkfile $swapsize swapfile) - echo "[OK]" - - exit(0) -endif - -# -# If we get here, then we are building a list of clients -# - -echo $argv[*] -foreach client ( $argv[*] ) - if ( $server == localhost ) then - echo "This machine can't be a server until it is given a hostname" - exit(1) - endif - set dest=$CLIENTDIR/$client - - if (! -f /private/tftpboot/mach) then - echo Installing /private/tftpboot/mach - cp -p /mach /private/tftpboot/mach - endif - if (! -f /private/tftpboot/boot) then - echo Installing /private/tftpboot/boot - cp -p /usr/standalone/boot /private/tftpboot/boot - endif - - # Check for already existing client directory - if ( -e $dest ) then - echo $dest already exists - continue - endif - - # Create the destination directory - echo -n "Creating $dest..." - mkdir -p -m $dest - chown root:staff $dest - if ( $status != 0 ) then - echo "failed" - exit(1) - endif - echo "[OK]" - - # Copy the template into it. - echo -n "Copying $template into ${dest}..." - (cd $template; tar cf - .)|(cd $dest; tar xpBf -) - echo "[OK]" - - # Make the device files - echo -n "Making devices in ${dest}/dev..." - (cd $dest/dev; /usr/etc/MAKEDEV NeXT) - echo "[OK]" - - # Customize the fstab file - echo -n "Installing fstab.client as ${dest}/etc/fstab..." - cp -p $dest/etc/fstab.client $dest/etc/fstab - sed -e "s/SERVER/$server/g" -e "s/CLIENT/$client/g" $dest/etc/fstab.client > $dest/etc/fstab - if ( $status != 0 ) then - echo $failed - exit(1) - endif - echo "[OK]" - - # Set up a symbolic link to the kernel - - if (-f ${dest}/tftpboot/mach) then - echo -n "Removing ${dest}/tftpboot/mach " - rm ${dest}/tftpboot/mach - echo "[OK]" - endif - - echo -n "Linking /tftpboot/mach to /sdmach " - ln -s /sdmach ${dest}/tftpboot/mach - echo "[OK]" - - # Touch the first 16 Meg of the swapfile - echo -n "Creating swapfile..." - (cd ${dest}/vm; /bin/rm -f swapfile; /usr/etc/mkfile 8k swapfile) - echo "[OK]" - -end - -exit(0) - -usage: - echo "Usage: $0 -p DISKTYPE TEMPLATE DEST" - echo " $0 [-s SERVER] CLIENT CLIENT ..." - exit(1) - - diff --git a/nfsstat.tproj/nfsstat.c b/nfsstat.tproj/nfsstat.c index 7bd1ce2..1f589c3 100644 --- a/nfsstat.tproj/nfsstat.c +++ b/nfsstat.tproj/nfsstat.c @@ -190,7 +190,6 @@ readstats(stp) int name[3]; size_t buflen = sizeof *stp; struct vfsconf vfc; - extern int getvfsbyname(char *, struct vfsconf *); if (getvfsbyname("nfs", &vfc) < 0) err(1, "getvfsbyname: NFS not compiled into kernel"); diff --git a/startslip.tproj/Makefile b/ping6.tproj/Makefile similarity index 82% rename from startslip.tproj/Makefile rename to ping6.tproj/Makefile index 968b995..0235287 100644 --- a/startslip.tproj/Makefile +++ b/ping6.tproj/Makefile @@ -7,14 +7,16 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = startslip +NAME = ping6 PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -CFILES = startslip.c +CFILES = ping6.c md5.c +HFILES = md5.h -OTHERSRCS = Makefile.preamble Makefile Makefile.dist startslip.1 +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble Makefile.dist\ + ping6.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles @@ -23,13 +25,15 @@ MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /sbin WINDOWS_INSTALLDIR = /sbin PDO_UNIX_INSTALLDIR = /sbin -LIBS = +LIBS = -lipsec DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) +NEXTSTEP_BUILD_OUTPUT_DIR = /$(USER)/BUILD + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc diff --git a/startslip.tproj/Makefile.dist b/ping6.tproj/Makefile.dist similarity index 54% rename from startslip.tproj/Makefile.dist rename to ping6.tproj/Makefile.dist index 14c72bc..7f3443c 100644 --- a/startslip.tproj/Makefile.dist +++ b/ping6.tproj/Makefile.dist @@ -1,6 +1,8 @@ # @(#)Makefile 8.1 (Berkeley) 6/5/93 -PROG= startslip -MAN8= startslip.0 +PROG= ping6 +MAN8= ping6.8 +BINOWN= root +BINMODE=4555 .include diff --git a/ping6.tproj/Makefile.postamble b/ping6.tproj/Makefile.postamble new file mode 100644 index 0000000..81495b9 --- /dev/null +++ b/ping6.tproj/Makefile.postamble @@ -0,0 +1,5 @@ +INSTALL_PERMISSIONS = 4555 # If set, 'install' chmod's executable to this +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 ping6.8 "$(DSTROOT)/usr/share/man/man8/ping6.8" + diff --git a/ping6.tproj/Makefile.preamble b/ping6.tproj/Makefile.preamble new file mode 100644 index 0000000..604fd2a --- /dev/null +++ b/ping6.tproj/Makefile.preamble @@ -0,0 +1,4 @@ +OTHER_GENERATED_OFILES = $(VERS_OFILE) +-include ../Makefile.include +LOCAL_CFLAGS= -DINET6 -DIPSEC_DEBUG -DKAME_SCOPEID +AFTER_INSTALL += install-man-page diff --git a/startslip.tproj/PB.project b/ping6.tproj/PB.project similarity index 64% rename from startslip.tproj/PB.project rename to ping6.tproj/PB.project index 1ba4a2b..96c419a 100644 --- a/startslip.tproj/PB.project +++ b/ping6.tproj/PB.project @@ -2,31 +2,30 @@ APPCLASS = NSApplication; FILESTABLE = { FRAMEWORKS = (); - H_FILES = (); + H_FILES = (md5.h); M_FILES = (); OTHER_LIBS = (); - OTHER_LINKED = (startslip.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.dist, startslip.1); - PRECOMPILED_HEADERS = (); - PROJECT_HEADERS = (); - PUBLIC_HEADERS = (); + OTHER_LINKED = (ping6.c, md5.c); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, Makefile.dist, ping.8); SUBPROJECTS = (); }; LANGUAGE = English; LOCALIZABLE_FILES = {}; + NEXTSTEP_BUILDDIR = "/$(USER)/BUILD"; + NEXTSTEP_BUILDTOOL = /bin/gnumake; NEXTSTEP_INSTALLDIR = /sbin; NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_MAINNIB = startslip; + NEXTSTEP_MAINNIB = ping6; NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; PDO_UNIX_INSTALLDIR = /sbin; PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_MAINNIB = startslip; + PDO_UNIX_MAINNIB = ping6; PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = startslip; + PROJECTNAME = ping6; PROJECTTYPE = Tool; PROJECTVERSION = 2.8; WINDOWS_INSTALLDIR = /sbin; WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_MAINNIB = startslip; + WINDOWS_MAINNIB = ping6; WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; } diff --git a/ping6.tproj/md5.c b/ping6.tproj/md5.c new file mode 100644 index 0000000..68a654b --- /dev/null +++ b/ping6.tproj/md5.c @@ -0,0 +1,308 @@ +/* $KAME: md5.c,v 1.3 2000/05/27 07:14:22 itojun 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. 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. + */ + +#include +#include +#include +#include +#include +#include "md5.h" + +#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s)))) + +#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))) + +#define ROUND1(a, b, c, d, k, s, i) { \ + (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND2(a, b, c, d, k, s, i) { \ + (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND3(a, b, c, d, k, s, i) { \ + (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define ROUND4(a, b, c, d, k, s, i) { \ + (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \ + (a) = SHIFT((a), (s)); \ + (a) = (b) + (a); \ +} + +#define Sa 7 +#define Sb 12 +#define Sc 17 +#define Sd 22 + +#define Se 5 +#define Sf 9 +#define Sg 14 +#define Sh 20 + +#define Si 4 +#define Sj 11 +#define Sk 16 +#define Sl 23 + +#define Sm 6 +#define Sn 10 +#define So 15 +#define Sp 21 + +#define MD5_A0 0x67452301 +#define MD5_B0 0xefcdab89 +#define MD5_C0 0x98badcfe +#define MD5_D0 0x10325476 + +/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */ +static const u_int32_t T[65] = { + 0, + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +static const u_int8_t md5_paddat[MD5_BUFLEN] = { + 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, +}; + +static void md5_calc __P((u_int8_t *, md5_ctxt *)); + +void md5_init(ctxt) + md5_ctxt *ctxt; +{ + ctxt->md5_n = 0; + ctxt->md5_i = 0; + ctxt->md5_sta = MD5_A0; + ctxt->md5_stb = MD5_B0; + ctxt->md5_stc = MD5_C0; + ctxt->md5_std = MD5_D0; + bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf)); +} + +void md5_loop(ctxt, input, len) + md5_ctxt *ctxt; + u_int8_t *input; + u_int len; /* number of bytes */ +{ + u_int gap, i; + + ctxt->md5_n += len * 8; /* byte to bit */ + gap = MD5_BUFLEN - ctxt->md5_i; + + if (len >= gap) { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + + for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) { + md5_calc((u_int8_t *)(input + i), ctxt); + } + + ctxt->md5_i = len - i; + bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i); + } else { + bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i), + len); + ctxt->md5_i += len; + } +} + +void md5_pad(ctxt) + md5_ctxt *ctxt; +{ + u_int gap; + + /* Don't count up padding. Keep md5_n. */ + gap = MD5_BUFLEN - ctxt->md5_i; + if (gap > 8) { + bcopy((void *)md5_paddat, + (void *)(ctxt->md5_buf + ctxt->md5_i), + gap - sizeof(ctxt->md5_n)); + } else { + /* including gap == 8 */ + bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i), + gap); + md5_calc(ctxt->md5_buf, ctxt); + bcopy((void *)(md5_paddat + gap), + (void *)ctxt->md5_buf, + MD5_BUFLEN - sizeof(ctxt->md5_n)); + } + + /* 8 byte word */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8); +#endif +#if BYTE_ORDER == BIG_ENDIAN + ctxt->md5_buf[56] = ctxt->md5_n8[7]; + ctxt->md5_buf[57] = ctxt->md5_n8[6]; + ctxt->md5_buf[58] = ctxt->md5_n8[5]; + ctxt->md5_buf[59] = ctxt->md5_n8[4]; + ctxt->md5_buf[60] = ctxt->md5_n8[3]; + ctxt->md5_buf[61] = ctxt->md5_n8[2]; + ctxt->md5_buf[62] = ctxt->md5_n8[1]; + ctxt->md5_buf[63] = ctxt->md5_n8[0]; +#endif + + md5_calc(ctxt->md5_buf, ctxt); +} + +void md5_result(digest, ctxt) + u_int8_t *digest; + md5_ctxt *ctxt; +{ + /* 4 byte words */ +#if BYTE_ORDER == LITTLE_ENDIAN + bcopy(&ctxt->md5_st8[0], digest, 16); +#endif +#if BYTE_ORDER == BIG_ENDIAN + digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2]; + digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0]; + digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6]; + digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4]; + digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10]; + digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8]; + digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14]; + digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12]; +#endif +} + +#if BYTE_ORDER == BIG_ENDIAN +u_int32_t X[16]; +#endif + +static void md5_calc(b64, ctxt) + u_int8_t *b64; + md5_ctxt *ctxt; +{ + u_int32_t A = ctxt->md5_sta; + u_int32_t B = ctxt->md5_stb; + u_int32_t C = ctxt->md5_stc; + u_int32_t D = ctxt->md5_std; +#if BYTE_ORDER == LITTLE_ENDIAN + u_int32_t *X = (u_int32_t *)b64; +#endif +#if BYTE_ORDER == BIG_ENDIAN + /* 4 byte words */ + /* what a brute force but fast! */ + u_int8_t *y = (u_int8_t *)X; + y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0]; + y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4]; + y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8]; + y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12]; + y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16]; + y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20]; + y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24]; + y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28]; + y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32]; + y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36]; + y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40]; + y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44]; + y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48]; + y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52]; + y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56]; + y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60]; +#endif + + ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2); + ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4); + ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6); + ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8); + ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10); + ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12); + ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14); + ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16); + + ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18); + ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20); + ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22); + ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24); + ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26); + ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28); + ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30); + ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32); + + ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34); + ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36); + ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38); + ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40); + ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42); + ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44); + ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46); + ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48); + + ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50); + ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52); + ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54); + ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56); + ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58); + ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60); + ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62); + ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64); + + ctxt->md5_sta += A; + ctxt->md5_stb += B; + ctxt->md5_stc += C; + ctxt->md5_std += D; +} diff --git a/ping6.tproj/md5.h b/ping6.tproj/md5.h new file mode 100644 index 0000000..b0752af --- /dev/null +++ b/ping6.tproj/md5.h @@ -0,0 +1,75 @@ +/* $KAME: md5.h,v 1.1 2000/05/27 06:18:21 itojun 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. 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. + */ + +#ifndef _NETINET6_MD5_H_ +#define _NETINET6_MD5_H_ + +#define MD5_BUFLEN 64 + +typedef struct { + union { + u_int32_t md5_state32[4]; + u_int8_t md5_state8[16]; + } md5_st; + +#define md5_sta md5_st.md5_state32[0] +#define md5_stb md5_st.md5_state32[1] +#define md5_stc md5_st.md5_state32[2] +#define md5_std md5_st.md5_state32[3] +#define md5_st8 md5_st.md5_state8 + + union { + u_int64_t md5_count64; + u_int8_t md5_count8[8]; + } md5_count; +#define md5_n md5_count.md5_count64 +#define md5_n8 md5_count.md5_count8 + + u_int md5_i; + u_int8_t md5_buf[MD5_BUFLEN]; +} md5_ctxt; + +extern void md5_init __P((md5_ctxt *)); +extern void md5_loop __P((md5_ctxt *, u_int8_t *, u_int)); +extern void md5_pad __P((md5_ctxt *)); +extern void md5_result __P((u_int8_t *, md5_ctxt *)); + +/* compatibility */ +#define MD5_CTX md5_ctxt +#define MD5Init(x) md5_init((x)) +#define MD5Update(x, y, z) md5_loop((x), (y), (z)) +#define MD5Final(x, y) \ +do { \ + md5_pad((y)); \ + md5_result((x), (y)); \ +} while (0) + +#endif /* ! _NETINET6_MD5_H_*/ diff --git a/ping6.tproj/ping6.8 b/ping6.tproj/ping6.8 new file mode 100644 index 0000000..384b9e7 --- /dev/null +++ b/ping6.tproj/ping6.8 @@ -0,0 +1,484 @@ +.\" $KAME: ping6.8,v 1.43 2001/06/28 06:54:29 suz 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. 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. +.\" +.\" $FreeBSD: src/sbin/ping6/ping6.8,v 1.3.2.8 2001/07/06 08:56:46 ume Exp $ +.\" +.Dd May 17, 1998 +.Dt PING6 8 +.Os +.Sh NAME +.Nm ping6 +.Nd send +.Tn ICMPv6 ECHO_REQUEST +packets to network hosts +.Sh SYNOPSIS +.Nm +.\" without ipsec, or new ipsec +.Op Fl dfHnNqRtvwW +.\" old ipsec +.\" .Op Fl AdEfnNqRtvwW +.Bk -words +.Op Fl a Ar addrtype +.Ek +.Bk -words +.Op Fl b Ar bufsiz +.Ek +.Bk -words +.Op Fl c Ar count +.Ek +.Bk -words +.Op Fl h Ar hoplimit +.Ek +.Bk -words +.Op Fl I Ar interface +.Ek +.Bk -words +.Op Fl i Ar wait +.Ek +.Bk -words +.Op Fl l Ar preload +.Ek +.Bk -words +.Op Fl p Ar pattern +.Ek +.Bk -words +.\" new ipsec +.Op Fl P Ar policy +.Ek +.Bk -words +.Op Fl S Ar sourceaddr +.Ek +.Bk -words +.Op Fl s Ar packetsize +.Ek +.Bk -words +.Op Ar hops...\& +.Ek +.Bk -words +.Ar host +.Ek +.Sh DESCRIPTION +.Nm +uses the +.Tn ICMPv6 +protocol's mandatory +.Tn ICMP6_ECHO_REQUEST +datagram to elicit an +.Tn ICMP6_ECHO_REPLY +from a host or gateway. +.Tn ICMP6_ECHO_REQUEST +datagrams (``pings'') have an IPv6 header, +and +.Tn ICMPv6 +header formatted as documented in RFC2463. +The options are as follows: +.Bl -tag -width Ds +.\" old ipsec +.\" .It Fl A +.\" Enables transport-mode IPsec authentication header +.\" .Pq experimental . +.It Fl a Ar addrtype +Generate ICMPv6 Node Information Node Addresses query, rather than echo-request. +.Ar addrtype +must be a string constructed of the following characters. +.Bl -tag -width Ds -compact +.It Ic a +requests all the responder's unicast addresses. +If the character is omitted, +only those addresses which belong to the interface which has the +responder's address are requests. +.It Ic c +requests responder's IPv4-compatible and IPv4-mapped addresses. +.It Ic g +requests responder's global-scope addresses. +.It Ic s +requests responder's site-local addresses. +.It Ic l +requests responder's link-local addresses. +.It Ic A +requests responder's anycast addresses. +Without this character, the responder will return unicast addresses only. +With this character, the responder will return anycast addresses only. +Note that the specification does not specify how to get responder's +anycast addresses. +This is an experimental option. +.El +.It Fl b Ar bufsiz +Set socket buffer size. +.It Fl c Ar count +Stop after sending +.Pq and receiving +.Ar count +.Tn ECHO_RESPONSE +packets. +.It Fl d +Set the +.Dv SO_DEBUG +option on the socket being used. +.\" .It Fl E +.\" Enables transport-mode IPsec encapsulated security payload +.\" .Pq experimental . +.It Fl f +Flood ping. +Outputs packets as fast as they come back or one hundred times per second, +whichever is more. +For every +.Tn ECHO_REQUEST +sent a period +.Dq .\& +is printed, while for every +.Tn ECHO_REPLY +received a backspace is printed. +This provides a rapid display of how many packets are being dropped. +Only the super-user may use this option. +.Bf -emphasis +This can be very hard on a network and should be used with caution. +.Ef +.It Fl H +Specifies to try reverse-lookup of IPv6 addresses. +The +.Nm +command does not try reverse-lookup unless the option is specified. +.It Fl h Ar hoplimit +Set the IPv6 hoplimit. +.It Fl I Ar interface +Source packets with the given interface address. +This flag applies if the ping destination is a multicast address, +or link-local/site-local unicast address. +.It Fl i Ar wait +Wait +.Ar wait +seconds +.Em between sending each packet . +The default is to wait for one second between each packet. +This option is incompatible with the +.Fl f +option. +.It Fl l Ar preload +If +.Ar preload +is specified, +.Nm +sends that many packets as fast as possible before falling into its normal +mode of behavior. +Only the super-user may use this option. +.It Fl n +Numeric output only. +No attempt will be made to lookup symbolic names from addresses in the reply. +.It Fl N +Probe node information multicast group +.Pq Li ff02::2:xxxx:xxxx . +.Ar host +must be string hostname of the target +.Pq must not be a numeric IPv6 address . +Node information multicast group will be computed based on given +.Ar host , +and will be used as the final destination. +Since node information multicast group is a link-local multicast group, +destination link needs to be specified by +.Fl I +option. +.It Fl p Ar pattern +You may specify up to 16 +.Dq pad +bytes to fill out the packet you send. +This is useful for diagnosing data-dependent problems in a network. +For example, +.Dq Li \-p ff +will cause the sent packet to be filled with all +ones. +.\" new ipsec +.It Fl P Ar policy +.Ar policy +specifies IPsec policy to be used for the probe. +.It Fl q +Quiet output. +Nothing is displayed except the summary lines at startup time and +when finished. +.It Fl R +Make the kernel believe that the target +.Ar host +.Po +or the first +.Ar hop +if you specify +.Ar hops +.Pc +is reachable, by injecting upper-layer reachability confirmation hint. +The option is meaningful only if the target +.Ar host +.Pq or the first hop +is a neighbor. +.It Fl S Ar sourceaddr +Specifies the source address of request packets. +The source address must be one of the unicast addresses of the sending node. +If the outgoing interface is specified by the +.Fl I +option as well, +.Ar sourceaddr +needs to be an address assigned to the specified interface. +.It Fl s Ar packetsize +Specifies the number of data bytes to be sent. +The default is 56, which translates into 64 +.Tn ICMP +data bytes when combined +with the 8 bytes of +.Tn ICMP +header data. +You may need to specify +.Fl b +as well to extend socket buffer size. +.It Fl t +Generate ICMPv6 Node Information supported query types query, +rather than echo-request. +.Fl s +has no effect if +.Fl t +is specified. +.It Fl v +Verbose output. +.Tn ICMP +packets other than +.Tn ECHO_RESPONSE +that are received are listed. +.It Fl w +Generate ICMPv6 Node Information DNS Name query, rather than echo-request. +.Fl s +has no effect if +.Fl w +is specified. +.It Fl W +Same as +.Fl w , +but with old packet format based on 03 draft. +This option is present for backward compatibility. +.Fl s +has no effect if +.Fl w +is specified. +.It Ar hops +IPv6 addresses for intermediate nodes, +which will be put into type 0 routing header. +.It Ar host +IPv6 adddress of the final destination node. +.El +.Pp +When using +.Nm +for fault isolation, it should first be run on the local host, to verify +that the local network interface is up and running. +Then, hosts and gateways further and further away should be +.Dq pinged . +Round-trip times and packet loss statistics are computed. +If duplicate packets are received, they are not included in the packet +loss calculation, although the round trip time of these packets is used +in calculating the round-trip time statistics. +When the specified number of packets have been sent +.Pq and received +or if the program is terminated with a +.Dv SIGINT , +a brief summary is displayed, showing the number of packets sent and +received, and the minimum, maximum, mean, and standard deviation of +the round-trip times. +.Pp +This program is intended for use in network testing, measurement and +management. +Because of the load it can impose on the network, it is unwise to use +.Nm +during normal operations or from automated scripts. +.\" .Sh ICMP PACKET DETAILS +.\" An IP header without options is 20 bytes. +.\" An +.\" .Tn ICMP +.\" .Tn ECHO_REQUEST +.\" packet contains an additional 8 bytes worth of +.\" .Tn ICMP +.\" header followed by an arbitrary amount of data. +.\" When a +.\" .Ar packetsize +.\" is given, this indicated the size of this extra piece of data +.\" .Pq the default is 56 . +.\" Thus the amount of data received inside of an IP packet of type +.\" .Tn ICMP +.\" .Tn ECHO_REPLY +.\" will always be 8 bytes more than the requested data space +.\" .Pq the Tn ICMP header . +.\" .Pp +.\" If the data space is at least eight bytes large, +.\" .Nm +.\" uses the first eight bytes of this space to include a timestamp which +.\" it uses in the computation of round trip times. +.\" If less than eight bytes of pad are specified, no round trip times are +.\" given. +.Sh DUPLICATE AND DAMAGED PACKETS +.Nm +will report duplicate and damaged packets. +Duplicate packets should never occur when pinging a unicast address, +and seem to be caused by +inappropriate link-level retransmissions. +Duplicates may occur in many situations and are rarely +.Pq if ever +a good sign, although the presence of low levels of duplicates may not +always be cause for alarm. +Duplicates are expected when pinging a broadcast or multicast address, +since they are not really duplicates but replies from different hosts +to the same request. +.Pp +Damaged packets are obviously serious cause for alarm and often +indicate broken hardware somewhere in the +.Nm +packet's path +.Pq in the network or in the hosts . +.Sh TRYING DIFFERENT DATA PATTERNS +The +(inter)network +layer should never treat packets differently depending on the data +contained in the data portion. +Unfortunately, data-dependent problems have been known to sneak into +networks and remain undetected for long periods of time. +In many cases the particular pattern that will have problems is something +that does not have sufficient +.Dq transitions , +such as all ones or all zeros, or a pattern right at the edge, such as +almost all zeros. +It is not +necessarily enough to specify a data pattern of all zeros (for example) +on the command line because the pattern that is of interest is +at the data link level, and the relationship between what you type and +what the controllers transmit can be complicated. +.Pp +This means that if you have a data-dependent problem you will probably +have to do a lot of testing to find it. +If you are lucky, you may manage to find a file that either +cannot +be sent across your network or that takes much longer to transfer than +other similar length files. +You can then examine this file for repeated patterns that you can test +using the +.Fl p +option of +.Nm . +.Sh RETURN VALUES +.Nm +returns 0 on success (the host is alive), +and non-zero if the arguments are incorrect or the host is not responding. +.Sh EXAMPLES +Normally, +.Xr ping6 8 +works just like +.Xr ping 8 +would work; the following will send ICMPv6 echo request to +.Li dst.foo.com . +.Bd -literal -offset indent +ping6 -n dst.foo.com +.Ed +.Pp +The following will probe hostnames for all nodes on the network link attached to +.Li wi0 +interface. +The address +.Li ff02::1 +is named the link-local all-node multicast address, and the packet would +reach every node on the network link. +.Bd -literal -offset indent +ping6 -w ff02::1%wi0 +.Ed +.Pp +The following will probe addresses assigned to the destination node, +.Li dst.foo.com . +.Bd -literal -offset indent +ping6 -a agl dst.foo.com +.Ed +.Pp +.Sh SEE ALSO +.Xr netstat 1 , +.Xr icmp6 4 , +.Xr inet6 4 , +.Xr ip6 4 , +.Xr ifconfig 8 , +.Xr ping 8 , +.Xr routed 8 , +.Xr traceroute 8 , +.Xr traceroute6 8 +.Rs +.%A A. Conta +.%A S. Deering +.%T "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification" +.%N RFC2463 +.%D December 1998 +.Re +.Rs +.%A Matt Crawford +.%T "IPv6 Node Information Queries" +.%N draft-ietf-ipngwg-icmp-name-lookups-07.txt +.%D August 2000 +.%O work in progress material +.Re +.Sh BUGS +There have been many discussions on why we separate +.Xr ping6 8 +and +.Xr ping 8 . +Some people argued that it would be more convenient to uniform the +ping command for both IPv4 and IPv6. +The followings are an answer to the request. +.Pp +From a developer's point of view: +since the underling raw sockets API is totally different between IPv4 +and IPv6, we would end up having two types of code base. +There would actually be less benefit to uniform the two commands +into a single command from the developer's standpoint. +.Pp +From an operator's point of view: unlike ordinary network applications +like remote login tools, we are usually aware of address family when using +network management tools. +We do not just want to know the reachability to the host, but want to know the +reachability to the host via a particular network protocol such as +IPv6. +Thus, even if we had a unified +.Xr ping 8 +command for both IPv4 and IPv6, we would usually type a +.Fl 6 +or +.Fl 4 +option (or something like those) to specify the particular address family. +This essentially means that we have two different commands. +.Sh HISTORY +The +.Xr ping 8 +command appeared in +.Bx 4.3 . +The +.Nm +command with IPv6 support first appeared in WIDE Hydrangea IPv6 protocol stack +kit. +.Pp +IPv6 and IPsec support based on the KAME Project (http://www.kame.net/) stack +was initially integrated into +.Fx 4.0 diff --git a/ping6.tproj/ping6.c b/ping6.tproj/ping6.c new file mode 100644 index 0000000..b49a37b --- /dev/null +++ b/ping6.tproj/ping6.c @@ -0,0 +1,2718 @@ +/* $KAME: ping6.c,v 1.126 2001/05/17 03:39:08 itojun 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. 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. + */ + +/* BSDI ping.c,v 2.3 1996/01/21 17:56:50 jch Exp */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; +#endif +static const char rcsid[] = + "$FreeBSD: src/sbin/ping6/ping6.c,v 1.4.2.6 2001/07/06 08:56:47 ume Exp $"; +#endif /* not lint */ + +/* + * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, + * measure round-trip-delays and packet loss across network paths. + * + * Author - + * Mike Muuss + * U. S. Army Ballistic Research Laboratory + * December, 1983 + * + * Status - + * Public Domain. Distribution Unlimited. + * Bugs - + * More statistics could always be gathered. + * This program has to run SUID to ROOT to access the ICMP socket. + */ +/* + * NOTE: + * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics + * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link* + * while IPV6_PKTINFO specifies *interface*. Link is defined as collection of + * network attached to 1 or more interfaces) + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#if defined(__OpenBSD__) || defined(__NetBSD__) +#include +#endif +#include +#include +#include +#include +#include + +#ifdef IPSEC +#include +#include +#endif + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#include +#else +#include "md5.h" +#endif + +#define MAXPACKETLEN 131072 +#define IP6LEN 40 +#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */ +#define ICMP6ECHOTMLEN sizeof(struct timeval) +#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8) +/* FQDN case, 64 bits of nonce + 32 bits ttl */ +#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) +#define EXTRA 256 /* for AH and various other headers. weird. */ +#define DEFDATALEN ICMP6ECHOTMLEN +#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN +#define NROUTES 9 /* number of record route slots */ + +#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ +#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ +#define SET(bit) (A(bit) |= B(bit)) +#define CLR(bit) (A(bit) &= (~B(bit))) +#define TST(bit) (A(bit) & B(bit)) + +#define F_FLOOD 0x0001 +#define F_INTERVAL 0x0002 +#define F_PINGFILLED 0x0008 +#define F_QUIET 0x0010 +#define F_RROUTE 0x0020 +#define F_SO_DEBUG 0x0040 +#define F_VERBOSE 0x0100 +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC +#define F_POLICY 0x0400 +#else +#define F_AUTHHDR 0x0200 +#define F_ENCRYPT 0x0400 +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ +#define F_NODEADDR 0x0800 +#define F_FQDN 0x1000 +#define F_INTERFACE 0x2000 +#define F_SRCADDR 0x4000 +#ifdef IPV6_REACHCONF +#define F_REACHCONF 0x8000 +#endif +#define F_HOSTNAME 0x10000 +#define F_FQDNOLD 0x20000 +#define F_NIGROUP 0x40000 +#define F_SUPTYPES 0x80000 +#define F_NOMINMTU 0x100000 +#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) +u_int options; + +#define IN6LEN sizeof(struct in6_addr) +#define SA6LEN sizeof(struct sockaddr_in6) +#define DUMMY_PORT 10101 + +#define SIN6(s) ((struct sockaddr_in6 *)(s)) + +/* + * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum + * number of received sequence numbers we can keep track of. Change 128 + * to 8192 for complete accuracy... + */ +#define MAX_DUP_CHK (8 * 8192) +int mx_dup_ck = MAX_DUP_CHK; +char rcvd_tbl[MAX_DUP_CHK / 8]; + +struct addrinfo *res; +struct sockaddr_in6 dst; /* who to ping6 */ +struct sockaddr_in6 src; /* src addr of this packet */ +int datalen = DEFDATALEN; +int s; /* socket file descriptor */ +u_char outpack[MAXPACKETLEN]; +char BSPACE = '\b'; /* characters written for flood */ +char DOT = '.'; +char *hostname; +int ident; /* process id to identify our packets */ +u_int8_t nonce[8]; /* nonce field for node information */ +struct in6_addr srcaddr; +int hoplimit = -1; /* hoplimit */ +int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */ + +/* counters */ +long npackets; /* max packets to transmit */ +long nreceived; /* # of packets we got back */ +long nrepeats; /* number of duplicates */ +long ntransmitted; /* sequence # for outbound packets = #sent */ +struct timeval interval = {1, 0}; /* interval between packets */ + +/* timing */ +int timing; /* flag to do timing */ +double tmin = 999999999.0; /* minimum round trip time */ +double tmax = 0.0; /* maximum round trip time */ +double tsum = 0.0; /* sum of all times, for doing average */ +#if defined(__OpenBSD__) || defined(__NetBSD__) +double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ +#endif + +/* for node addresses */ +u_short naflags; + +/* for ancillary data(advanced API) */ +struct msghdr smsghdr; +struct iovec smsgiov; +char *scmsg = 0; + +volatile int signo; +volatile sig_atomic_t seenalrm; +volatile sig_atomic_t seenint; +#ifdef SIGINFO +volatile sig_atomic_t seeninfo; +#endif + +int main __P((int, char *[])); +void fill __P((char *, char *)); +int get_hoplim __P((struct msghdr *)); +int get_pathmtu __P((struct msghdr *)); +void set_pathmtu __P((int)); +struct in6_pktinfo *get_rcvpktinfo __P((struct msghdr *)); +void onsignal __P((int)); +void retransmit __P((void)); +void onint __P((int)); +size_t pingerlen __P((void)); +int pinger __P((void)); +const char *pr_addr __P((struct sockaddr *, int)); +void pr_icmph __P((struct icmp6_hdr *, u_char *)); +void pr_iph __P((struct ip6_hdr *)); +void pr_suptypes __P((struct icmp6_nodeinfo *, size_t)); +void pr_nodeaddr __P((struct icmp6_nodeinfo *, int)); +int myechoreply __P((const struct icmp6_hdr *)); +int mynireply __P((const struct icmp6_nodeinfo *)); +char *dnsdecode __P((const u_char **, const u_char *, const u_char *, + u_char *, size_t)); +void pr_pack __P((u_char *, int, struct msghdr *)); +void pr_exthdrs __P((struct msghdr *)); +void pr_ip6opt __P((void *)); +void pr_rthdr __P((void *)); +int pr_bitrange __P((u_int32_t, int, int)); +void pr_retip __P((struct ip6_hdr *, u_char *)); +void summary __P((void)); +void tvsub __P((struct timeval *, struct timeval *)); +int setpolicy __P((int, char *)); +char *nigroup __P((char *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct itimerval itimer; + struct sockaddr_in6 from; + struct timeval timeout, *tv; + struct addrinfo hints; + fd_set *fdmaskp; + int fdmasks; + register int cc, i; + int ch, fromlen, hold, packlen, preload, optval, ret_ga; + u_char *datap, *packet; + char *e, *target, *ifname = NULL; + int ip6optlen = 0; + struct cmsghdr *scmsgp = NULL; + int sockbufsize = 0; + int usepktinfo = 0; + struct in6_pktinfo *pktinfo = NULL; +#ifdef USE_RFC2292BIS + struct ip6_rthdr *rthdr = NULL; +#endif +#ifdef IPSEC_POLICY_IPSEC + char *policy_in = NULL; + char *policy_out = NULL; +#endif + double intval; + size_t rthlen; + + /* just to be sure */ + memset(&smsghdr, 0, sizeof(&smsghdr)); + memset(&smsgiov, 0, sizeof(&smsgiov)); + + preload = 0; + datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; +#ifndef IPSEC +#define ADDOPTS +#else +#ifdef IPSEC_POLICY_IPSEC +#define ADDOPTS "P:" +#else +#define ADDOPTS "AE" +#endif /*IPSEC_POLICY_IPSEC*/ +#endif + while ((ch = getopt(argc, argv, + "a:b:c:dfHh:I:i:l:mnNp:qRS:s:tvwW" ADDOPTS)) != -1) { +#undef ADDOPTS + switch (ch) { + case 'a': + { + char *cp; + + options &= ~F_NOUSERDATA; + options |= F_NODEADDR; + for (cp = optarg; *cp != '\0'; cp++) { + switch (*cp) { + case 'a': + naflags |= NI_NODEADDR_FLAG_ALL; + break; + case 'c': + case 'C': + naflags |= NI_NODEADDR_FLAG_COMPAT; + break; + case 'l': + case 'L': + naflags |= NI_NODEADDR_FLAG_LINKLOCAL; + break; + case 's': + case 'S': + naflags |= NI_NODEADDR_FLAG_SITELOCAL; + break; + case 'g': + case 'G': + naflags |= NI_NODEADDR_FLAG_GLOBAL; + break; + case 'A': /* experimental. not in the spec */ +#ifdef NI_NODEADDR_FLAG_ANYCAST + naflags |= NI_NODEADDR_FLAG_ANYCAST; + break; +#else + errx(1, +"-a A is not supported on the platform"); + /*NOTREACHED*/ +#endif + default: + usage(); + /*NOTREACHED*/ + } + } + break; + } + case 'b': +#if defined(SO_SNDBUF) && defined(SO_RCVBUF) + sockbufsize = atoi(optarg); +#else + err(1, +"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported"); +#endif + break; + case 'c': + npackets = strtol(optarg, &e, 10); + if (npackets <= 0 || *optarg == '\0' || *e != '\0') + errx(1, + "illegal number of packets -- %s", optarg); + break; + case 'd': + options |= F_SO_DEBUG; + break; + case 'f': + if (getuid()) { + errno = EPERM; + errx(1, "Must be superuser to flood ping"); + } + options |= F_FLOOD; + setbuf(stdout, (char *)NULL); + break; + case 'H': + options |= F_HOSTNAME; + break; + case 'h': /* hoplimit */ + hoplimit = strtol(optarg, &e, 10); + if (255 < hoplimit || hoplimit < -1) + errx(1, + "illegal hoplimit -- %s", optarg); + break; + case 'I': + ifname = optarg; + options |= F_INTERFACE; +#ifndef USE_SIN6_SCOPE_ID + usepktinfo++; +#endif + break; + case 'i': /* wait between sending packets */ + intval = strtod(optarg, &e); + if (*optarg == '\0' || *e != '\0') + errx(1, "illegal timing interval %s", optarg); + if (intval < 1 && getuid()) { + errx(1, "%s: only root may use interval < 1s", + strerror(EPERM)); + } + interval.tv_sec = (long)intval; + interval.tv_usec = + (long)((intval - interval.tv_sec) * 1000000); + if (interval.tv_sec < 0) + errx(1, "illegal timing interval %s", optarg); + /* less than 1/hz does not make sense */ + if (interval.tv_sec == 0 && interval.tv_usec < 10000) { + warnx("too small interval, raised to 0.01"); + interval.tv_usec = 10000; + } + options |= F_INTERVAL; + break; + case 'l': + if (getuid()) { + errno = EPERM; + errx(1, "Must be superuser to preload"); + } + preload = strtol(optarg, &e, 10); + if (preload < 0 || *optarg == '\0' || *e != '\0') + errx(1, "illegal preload value -- %s", optarg); + break; + case 'm': +#ifdef IPV6_USE_MIN_MTU + options |= F_NOMINMTU; + break; +#else + errx(1, "-%c is not supported on this platform", ch); + /*NOTREACHED*/ +#endif + case 'n': + options &= ~F_HOSTNAME; + break; + case 'N': + options |= F_NIGROUP; + break; + case 'p': /* fill buffer with user pattern */ + options |= F_PINGFILLED; + fill((char *)datap, optarg); + break; + case 'q': + options |= F_QUIET; + break; + case 'R': +#ifdef IPV6_REACHCONF + options |= F_REACHCONF; + break; +#else + errx(1, "-R is not supported in this configuration"); +#endif + case 'S': + /* XXX: use getaddrinfo? */ + if (inet_pton(AF_INET6, optarg, (void *)&srcaddr) != 1) + errx(1, "invalid IPv6 address: %s", optarg); + options |= F_SRCADDR; + usepktinfo++; + break; + case 's': /* size of packet to send */ + datalen = strtol(optarg, &e, 10); + if (datalen <= 0 || *optarg == '\0' || *e != '\0') + errx(1, "illegal datalen value -- %s", optarg); + if (datalen > MAXDATALEN) { + errx(1, + "datalen value too large, maximum is %d", + MAXDATALEN); + } + break; + case 't': + options &= ~F_NOUSERDATA; + options |= F_SUPTYPES; + break; + case 'v': + options |= F_VERBOSE; + break; + case 'w': + options &= ~F_NOUSERDATA; + options |= F_FQDN; + break; + case 'W': + options &= ~F_NOUSERDATA; + options |= F_FQDNOLD; + break; +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + case 'P': + options |= F_POLICY; + if (!strncmp("in", optarg, 2)) { + if ((policy_in = strdup(optarg)) == NULL) + errx(1, "strdup"); + } else if (!strncmp("out", optarg, 3)) { + if ((policy_out = strdup(optarg)) == NULL) + errx(1, "strdup"); + } else + errx(1, "invalid security policy"); + break; +#else + case 'A': + options |= F_AUTHHDR; + break; + case 'E': + options |= F_ENCRYPT; + break; +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ + default: + usage(); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); + /*NOTREACHED*/ + } + + if (argc > 1) { +#ifdef IPV6_RECVRTHDR /* 2292bis */ + rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, + argc - 1)); +#else /* RFC2292 */ + rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1); +#endif + if (rthlen == 0) { + errx(1, "too many intermediate hops"); + /*NOTREACHED*/ + } + ip6optlen += rthlen; + } + + if (options & F_NIGROUP) { + target = nigroup(argv[argc - 1]); + if (target == NULL) { + usage(); + /*NOTREACHED*/ + } + } else + target = argv[argc - 1]; + + /* getaddrinfo */ + bzero(&hints, sizeof(struct addrinfo)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_RAW; + hints.ai_protocol = IPPROTO_ICMPV6; + + ret_ga = getaddrinfo(target, NULL, &hints, &res); + if (ret_ga) { + fprintf(stderr, "ping6: %s\n", gai_strerror(ret_ga)); + exit(1); + } + if (res->ai_canonname) + hostname = res->ai_canonname; + else + hostname = target; + + if (!res->ai_addr) + errx(1, "getaddrinfo failed"); + + (void)memcpy(&dst, res->ai_addr, res->ai_addrlen); + + res->ai_socktype = SOCK_RAW; + res->ai_protocol = IPPROTO_ICMPV6; + + if ((s = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + err(1, "socket"); + + /* + * let the kerel pass extension headers of incoming packets, + * for privileged socket options + */ + if ((options & F_VERBOSE) != 0) { + int opton = 1; + +#ifdef IPV6_RECVHOPOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVHOPOPTS)"); +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_HOPOPTS)"); +#endif +#ifdef IPV6_RECVDSTOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVDSTOPTS)"); +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_DSTOPTS)"); +#endif +#ifdef IPV6_RECVRTHDRDSTOPTS + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); +#endif + } + + /* revoke root privilege */ + seteuid(getuid()); + setuid(getuid()); + + if (options & F_FLOOD && options & F_INTERVAL) + errx(1, "-f and -i incompatible options"); + + if ((options & F_NOUSERDATA) == 0) { + if (datalen >= sizeof(struct timeval)) { + /* we can time transfer */ + timing = 1; + } else + timing = 0; + /* in F_VERBOSE case, we may get non-echoreply packets*/ + if (options & F_VERBOSE) + packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; + else + packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA; + } else { + /* suppress timing for node information query */ + timing = 0; + datalen = 2048; + packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA; + } + + if (!(packet = (u_char *)malloc((u_int)packlen))) + err(1, "Unable to allocate packet"); + if (!(options & F_PINGFILLED)) + for (i = ICMP6ECHOLEN; i < packlen; ++i) + *datap++ = i; + + ident = getpid() & 0xFFFF; +#ifndef __OpenBSD__ + gettimeofday(&timeout, NULL); + srand((unsigned int)(timeout.tv_sec ^ timeout.tv_usec ^ (long)ident)); + memset(nonce, 0, sizeof(nonce)); + for (i = 0; i < sizeof(nonce); i += sizeof(int)) + *((int *)&nonce[i]) = rand(); +#else + memset(nonce, 0, sizeof(nonce)); + for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t)) + *((u_int32_t *)&nonce[i]) = arc4random(); +#endif + + hold = 1; + + if (options & F_SO_DEBUG) + (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, + sizeof(hold)); + optval = IPV6_DEFHLIM; + if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) + if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &optval, sizeof(optval)) == -1) + err(1, "IPV6_MULTICAST_HOPS"); +#ifdef IPV6_USE_MIN_MTU + if ((options & F_NOMINMTU) == 0) { + optval = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_USE_MIN_MTU)"); + } +#ifdef IPV6_RECVPATHMTU + else { + optval = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_RECVPATHMTU)"); + } +#endif /* IPV6_RECVPATHMTU */ +#endif /* IPV6_USE_MIN_MTU */ + +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + if (options & F_POLICY) { + if (setpolicy(s, policy_in) < 0) + errx(1, "%s", ipsec_strerror()); + if (setpolicy(s, policy_out) < 0) + errx(1, "%s", ipsec_strerror()); + } +#else + if (options & F_AUTHHDR) { + optval = IPSEC_LEVEL_REQUIRE; +#ifdef IPV6_AUTH_TRANS_LEVEL + if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); +#else /* old def */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_AUTH_LEVEL)"); +#endif + } + if (options & F_ENCRYPT) { + optval = IPSEC_LEVEL_REQUIRE; + if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); + } +#endif /*IPSEC_POLICY_IPSEC*/ +#endif + +#ifdef ICMP6_FILTER + { + struct icmp6_filter filt; + if (!(options & F_VERBOSE)) { + ICMP6_FILTER_SETBLOCKALL(&filt); + if ((options & F_FQDN) || (options & F_FQDNOLD) || + (options & F_NODEADDR) || (options & F_SUPTYPES)) + ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); + else + ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); + } else { + ICMP6_FILTER_SETPASSALL(&filt); + } + if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + sizeof(filt)) < 0) + err(1, "setsockopt(ICMP6_FILTER)"); + } +#endif /*ICMP6_FILTER*/ + + /* let the kerel pass extension headers of incoming packets */ + if ((options & F_VERBOSE) != 0) { + int opton = 1; + +#ifdef IPV6_RECVRTHDR + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RECVRTHDR)"); +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton, + sizeof(opton))) + err(1, "setsockopt(IPV6_RTHDR)"); +#endif + } + +/* + optval = 1; + if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) + if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &optval, sizeof(optval)) == -1) + err(1, "IPV6_MULTICAST_LOOP"); +*/ + + /* Specify the outgoing interface and/or the source address */ + if (usepktinfo) + ip6optlen += CMSG_SPACE(sizeof(struct in6_pktinfo)); + + if (hoplimit != -1) + ip6optlen += CMSG_SPACE(sizeof(int)); + +#ifdef IPV6_REACHCONF + if (options & F_REACHCONF) + ip6optlen += CMSG_SPACE(0); +#endif + + /* set IP6 packet options */ + if (ip6optlen) { + if ((scmsg = (char *)malloc(ip6optlen)) == 0) + errx(1, "can't allocate enough memory"); + smsghdr.msg_control = (caddr_t)scmsg; + smsghdr.msg_controllen = ip6optlen; + scmsgp = (struct cmsghdr *)scmsg; + } + if (usepktinfo) { + pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp)); + memset(pktinfo, 0, sizeof(*pktinfo)); + scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_PKTINFO; + scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } + + /* set the outgoing interface */ + if (ifname) { +#ifndef USE_SIN6_SCOPE_ID + /* pktinfo must have already been allocated */ + if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0) + errx(1, "%s: invalid interface name", ifname); +#else + if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0) + errx(1, "%s: invalid interface name", ifname); +#endif + } + /* set the source address */ + if (options & F_SRCADDR)/* pktinfo must be valid */ + pktinfo->ipi6_addr = srcaddr; + + if (hoplimit != -1) { + scmsgp->cmsg_len = CMSG_LEN(sizeof(int)); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_HOPLIMIT; + *(int *)(CMSG_DATA(scmsgp)) = hoplimit; + + scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } +#ifdef IPV6_REACHCONF + if (options & F_REACHCONF) { + scmsgp->cmsg_len = CMSG_LEN(0); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_REACHCONF; + + scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } +#endif + + if (argc > 1) { /* some intermediate addrs are specified */ + int hops, error; +#ifdef USE_RFC2292BIS + int rthdrlen; +#endif + +#ifdef USE_RFC2292BIS + rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1); + scmsgp->cmsg_len = CMSG_LEN(rthdrlen); + scmsgp->cmsg_level = IPPROTO_IPV6; + scmsgp->cmsg_type = IPV6_RTHDR; + rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp); + rthdr = inet6_rth_init((void *)rthdr, rthdrlen, + IPV6_RTHDR_TYPE_0, argc - 1); + if (rthdr == NULL) + errx(1, "can't initialize rthdr"); +#else /* old advanced API */ + if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp, + IPV6_RTHDR_TYPE_0)) == 0) + errx(1, "can't initialize rthdr"); +#endif /* USE_RFC2292BIS */ + + for (hops = 0; hops < argc - 1; hops++) { + struct addrinfo *iaip; + + if ((error = getaddrinfo(argv[hops], NULL, &hints, + &iaip))) + errx(1, "%s", gai_strerror(error)); + if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6) + errx(1, + "bad addr family of an intermediate addr"); + +#ifdef USE_RFC2292BIS + if (inet6_rth_add(rthdr, + &(SIN6(iaip->ai_addr))->sin6_addr)) + errx(1, "can't add an intermediate node"); +#else /* old advanced API */ + if (inet6_rthdr_add(scmsgp, + &(SIN6(iaip->ai_addr))->sin6_addr, + IPV6_RTHDR_LOOSE)) + errx(1, "can't add an intermediate node"); +#endif /* USE_RFC2292BIS */ + freeaddrinfo(iaip); + } + +#ifndef USE_RFC2292BIS + if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE)) + errx(1, "can't set the last flag"); +#endif + + scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); + } + + { + /* + * source selection + */ + int dummy, len = sizeof(src); + + if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + err(1, "UDP socket"); + + src.sin6_family = AF_INET6; + src.sin6_addr = dst.sin6_addr; + src.sin6_port = ntohs(DUMMY_PORT); + src.sin6_scope_id = dst.sin6_scope_id; + +#ifdef USE_RFC2292BIS + if (pktinfo && + setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO, + (void *)pktinfo, sizeof(*pktinfo))) + err(1, "UDP setsockopt(IPV6_PKTINFO)"); + + if (hoplimit != -1 && + setsockopt(dummy, IPPROTO_IPV6, IPV6_HOPLIMIT, + (void *)&hoplimit, sizeof(hoplimit))) + err(1, "UDP setsockopt(IPV6_HOPLIMIT)"); + + if (rthdr && + setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR, + (void *)rthdr, (rthdr->ip6r_len + 1) << 3)) + err(1, "UDP setsockopt(IPV6_RTHDR)"); +#else /* old advanced API */ + if (smsghdr.msg_control && + setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS, + (void *)smsghdr.msg_control, smsghdr.msg_controllen)) + err(1, "UDP setsockopt(IPV6_PKTOPTIONS)"); +#endif + + if (connect(dummy, (struct sockaddr *)&src, len) < 0) + err(1, "UDP connect"); + + if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0) + err(1, "getsockname"); + + close(dummy); + } + +#if defined(SO_SNDBUF) && defined(SO_RCVBUF) + if (sockbufsize) { + if (datalen > sockbufsize) + warnx("you need -b to increase socket buffer size"); + if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, + sizeof(sockbufsize)) < 0) + err(1, "setsockopt(SO_SNDBUF)"); + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize, + sizeof(sockbufsize)) < 0) + err(1, "setsockopt(SO_RCVBUF)"); + } + else { + if (datalen > 8 * 1024) /*XXX*/ + warnx("you need -b to increase socket buffer size"); + /* + * When pinging the broadcast address, you can get a lot of + * answers. Doing something so evil is useful if you are trying + * to stress the ethernet, or just want to fill the arp cache + * to get some stuff for /etc/ethers. + */ + hold = 48 * 1024; + setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, + sizeof(hold)); + } +#endif + + optval = 1; +#ifndef USE_SIN6_SCOPE_ID +#ifdef IPV6_RECVPKTINFO + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */ +#endif +#endif /* USE_SIN6_SCOPE_ID */ +#ifdef IPV6_RECVHOPLIMIT + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ +#else /* old adv. API */ + if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, + sizeof(optval)) < 0) + warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ +#endif + + printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), + (unsigned long)(pingerlen() - 8)); + printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); + printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); + + while (preload--) /* Fire off them quickies. */ + (void)pinger(); + + (void)signal(SIGINT, onsignal); +#ifdef SIGINFO + (void)signal(SIGINFO, onsignal); +#endif + + if ((options & F_FLOOD) == 0) { + (void)signal(SIGALRM, onsignal); + itimer.it_interval = interval; + itimer.it_value = interval; + (void)setitimer(ITIMER_REAL, &itimer, NULL); + retransmit(); + } + + fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); + if ((fdmaskp = malloc(fdmasks)) == NULL) + err(1, "malloc"); + + signo = seenalrm = seenint = 0; +#ifdef SIGINFO + seeninfo = 0; +#endif + + for (;;) { + struct msghdr m; + struct cmsghdr *cm; + u_char buf[1024]; + struct iovec iov[2]; + + /* signal handling */ + if (seenalrm) { + retransmit(); + seenalrm = 0; + continue; + } + if (seenint) { + onint(SIGINT); + seenint = 0; + continue; + } +#ifdef SIGINFO + if (seeninfo) { + summary(); + seeninfo = 0; + continue; + } +#endif + + if (options & F_FLOOD) { + (void)pinger(); + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + tv = &timeout; + } else + tv = NULL; + memset(fdmaskp, 0, fdmasks); + FD_SET(s, fdmaskp); + cc = select(s + 1, fdmaskp, NULL, NULL, tv); + if (cc < 0) { + if (errno != EINTR) { + warn("select"); + sleep(1); + } + continue; + } else if (cc == 0) + continue; + + fromlen = sizeof(from); + m.msg_name = (caddr_t)&from; + m.msg_namelen = sizeof(from); + memset(&iov, 0, sizeof(iov)); + iov[0].iov_base = (caddr_t)packet; + iov[0].iov_len = packlen; + m.msg_iov = iov; + m.msg_iovlen = 1; + cm = (struct cmsghdr *)buf; + m.msg_control = (caddr_t)buf; + m.msg_controllen = sizeof(buf); + + cc = recvmsg(s, &m, 0); + if (cc < 0) { + if (errno != EINTR) { + warn("recvmsg"); + sleep(1); + } + continue; + } else if (cc == 0) { + int mtu; + + /* + * receive control messages only. Process the + * exceptions (currently the only possiblity is + * a path MTU notification.) + */ + if ((mtu = get_pathmtu(&m)) > 0) { + if ((options & F_VERBOSE) != 0) { + printf("new path MTU (%d) is " + "notified\n", mtu); + } + set_pathmtu(mtu); + } + continue; + } else { + /* + * an ICMPv6 message (probably an echoreply) arrived. + */ + pr_pack(packet, cc, &m); + } + if (npackets && nreceived >= npackets) + break; + } + summary(); + exit(nreceived == 0); +} + +void +onsignal(sig) + int sig; +{ + signo = sig; + switch (sig) { + case SIGALRM: + seenalrm++; + break; + case SIGINT: + seenint++; + break; +#ifdef SIGINFO + case SIGINFO: + seeninfo++; + break; +#endif + } +} + +/* + * retransmit -- + * This routine transmits another ping6. + */ +void +retransmit() +{ + struct itimerval itimer; + + if (pinger() == 0) + return; + + /* + * If we're not transmitting any more packets, change the timer + * to wait two round-trip times if we've received any packets or + * ten seconds if we haven't. + */ +#define MAXWAIT 10 + if (nreceived) { + itimer.it_value.tv_sec = 2 * tmax / 1000; + if (itimer.it_value.tv_sec == 0) + itimer.it_value.tv_sec = 1; + } else + itimer.it_value.tv_sec = MAXWAIT; + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = 0; + itimer.it_value.tv_usec = 0; + + (void)signal(SIGALRM, onint); + (void)setitimer(ITIMER_REAL, &itimer, NULL); +} + +/* + * pinger -- + * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet + * will be added on by the kernel. The ID field is our UNIX process ID, + * and the sequence number is an ascending integer. The first 8 bytes + * of the data portion are used to hold a UNIX "timeval" struct in VAX + * byte-order, to compute the round-trip time. + */ +size_t +pingerlen() +{ + size_t l; + + if (options & F_FQDN) + l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + else if (options & F_FQDNOLD) + l = ICMP6_NIQLEN; + else if (options & F_NODEADDR) + l = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + else if (options & F_SUPTYPES) + l = ICMP6_NIQLEN; + else + l = ICMP6ECHOLEN + datalen; + + return l; +} + +int +pinger() +{ + struct icmp6_hdr *icp; + struct iovec iov[2]; + int i, cc; + struct icmp6_nodeinfo *nip; + int seq; + + if (npackets && ntransmitted >= npackets) + return(-1); /* no more transmission */ + + icp = (struct icmp6_hdr *)outpack; + nip = (struct icmp6_nodeinfo *)outpack; + memset(icp, 0, sizeof(*icp)); + icp->icmp6_cksum = 0; + seq = ntransmitted++; + CLR(seq % mx_dup_ck); + + if (options & F_FQDN) { + icp->icmp6_type = ICMP6_NI_QUERY; + icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; + nip->ni_qtype = htons(NI_QTYPE_FQDN); + nip->ni_flags = htons(0); + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + + memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, + sizeof(dst.sin6_addr)); + cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + datalen = 0; + } else if (options & F_FQDNOLD) { + /* packet format in 03 draft - no Subject data on queries */ + icp->icmp6_type = ICMP6_NI_QUERY; + icp->icmp6_code = 0; /* code field is always 0 */ + nip->ni_qtype = htons(NI_QTYPE_FQDN); + nip->ni_flags = htons(0); + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + + cc = ICMP6_NIQLEN; + datalen = 0; + } else if (options & F_NODEADDR) { + icp->icmp6_type = ICMP6_NI_QUERY; + icp->icmp6_code = ICMP6_NI_SUBJ_IPV6; + nip->ni_qtype = htons(NI_QTYPE_NODEADDR); + nip->ni_flags = naflags; + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + + memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr, + sizeof(dst.sin6_addr)); + cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr); + datalen = 0; + } else if (options & F_SUPTYPES) { + icp->icmp6_type = ICMP6_NI_QUERY; + icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/ + nip->ni_qtype = htons(NI_QTYPE_SUPTYPES); + /* we support compressed bitmap */ + nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS; + + memcpy(nip->icmp6_ni_nonce, nonce, + sizeof(nip->icmp6_ni_nonce)); + *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq); + cc = ICMP6_NIQLEN; + datalen = 0; + } else { + icp->icmp6_type = ICMP6_ECHO_REQUEST; + icp->icmp6_code = 0; + icp->icmp6_id = htons(ident); + icp->icmp6_seq = ntohs(seq); + if (timing) + (void)gettimeofday((struct timeval *) + &outpack[ICMP6ECHOLEN], NULL); + cc = ICMP6ECHOLEN + datalen; + } + +#ifdef DIAGNOSTIC + if (pingerlen() != cc) + errx(1, "internal error; length mismatch"); +#endif + + smsghdr.msg_name = (caddr_t)&dst; + smsghdr.msg_namelen = sizeof(dst); + memset(&iov, 0, sizeof(iov)); + iov[0].iov_base = (caddr_t)outpack; + iov[0].iov_len = cc; + smsghdr.msg_iov = iov; + smsghdr.msg_iovlen = 1; + + i = sendmsg(s, &smsghdr, 0); + + if (i < 0 || i != cc) { + if (i < 0) + warn("sendmsg"); + (void)printf("ping6: wrote %s %d chars, ret=%d\n", + hostname, cc, i); + } + if (!(options & F_QUIET) && options & F_FLOOD) + (void)write(STDOUT_FILENO, &DOT, 1); + + return(0); +} + +int +myechoreply(icp) + const struct icmp6_hdr *icp; +{ + if (ntohs(icp->icmp6_id) == ident) + return 1; + else + return 0; +} + +int +mynireply(nip) + const struct icmp6_nodeinfo *nip; +{ + if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t), + nonce + sizeof(u_int16_t), + sizeof(nonce) - sizeof(u_int16_t)) == 0) + return 1; + else + return 0; +} + +char * +dnsdecode(sp, ep, base, buf, bufsiz) + const u_char **sp; + const u_char *ep; + const u_char *base; /*base for compressed name*/ + u_char *buf; + size_t bufsiz; +{ + int i; + const u_char *cp; + char cresult[MAXDNAME + 1]; + const u_char *comp; + int l; + + cp = *sp; + *buf = '\0'; + + if (cp >= ep) + return NULL; + while (cp < ep) { + i = *cp; + if (i == 0 || cp != *sp) { + if (strlcat(buf, ".", bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + } + if (i == 0) + break; + cp++; + + if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) { + /* DNS compression */ + if (!base) + return NULL; + + comp = base + (i & 0x3f); + if (dnsdecode(&comp, cp, base, cresult, + sizeof(cresult)) == NULL) + return NULL; + if (strlcat(buf, cresult, bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + break; + } else if ((i & 0x3f) == i) { + if (i > ep - cp) + return NULL; /*source overrun*/ + while (i-- > 0 && cp < ep) { + l = snprintf(cresult, sizeof(cresult), + isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff); + if (l >= sizeof(cresult)) + return NULL; + if (strlcat(buf, cresult, bufsiz) >= bufsiz) + return NULL; /*result overrun*/ + cp++; + } + } else + return NULL; /*invalid label*/ + } + if (i != 0) + return NULL; /*not terminated*/ + cp++; + *sp = cp; + return buf; +} + +/* + * pr_pack -- + * Print out the packet, if it came from us. This logic is necessary + * because ALL readers of the ICMP socket get a copy of ALL ICMP packets + * which arrive ('tis only fair). This permits multiple copies of this + * program to be run without having intermingled output (or statistics!). + */ +void +pr_pack(buf, cc, mhdr) + u_char *buf; + int cc; + struct msghdr *mhdr; +{ +#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) + struct icmp6_hdr *icp; + struct icmp6_nodeinfo *ni; + int i; + int hoplim; + struct sockaddr *from; + int fromlen; + u_char *cp = NULL, *dp, *end = buf + cc; + struct in6_pktinfo *pktinfo = NULL; + struct timeval tv, *tp; + double triptime = 0; + int dupflag; + size_t off; + int oldfqdn; + u_int16_t seq; + char dnsname[MAXDNAME + 1]; + + (void)gettimeofday(&tv, NULL); + + if (!mhdr || !mhdr->msg_name || + mhdr->msg_namelen != sizeof(struct sockaddr_in6) || + ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) { + if (options & F_VERBOSE) + warnx("invalid peername\n"); + return; + } + from = (struct sockaddr *)mhdr->msg_name; + fromlen = mhdr->msg_namelen; + if (cc < sizeof(struct icmp6_hdr)) { + if (options & F_VERBOSE) + warnx("packet too short (%d bytes) from %s\n", cc, + pr_addr(from, fromlen)); + return; + } + icp = (struct icmp6_hdr *)buf; + ni = (struct icmp6_nodeinfo *)buf; + off = 0; + + if ((hoplim = get_hoplim(mhdr)) == -1) { + warnx("failed to get receiving hop limit"); + return; + } + if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) { + warnx("failed to get receiving pakcet information"); + return; + } + + if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) { + seq = ntohs(icp->icmp6_seq); + ++nreceived; + if (timing) { + tp = (struct timeval *)(icp + 1); + tvsub(&tv, tp); + triptime = ((double)tv.tv_sec) * 1000.0 + + ((double)tv.tv_usec) / 1000.0; + tsum += triptime; +#if defined(__OpenBSD__) || defined(__NetBSD__) + tsumsq += triptime * triptime; +#endif + if (triptime < tmin) + tmin = triptime; + if (triptime > tmax) + tmax = triptime; + } + + if (TST(seq % mx_dup_ck)) { + ++nrepeats; + --nreceived; + dupflag = 1; + } else { + SET(seq % mx_dup_ck); + dupflag = 0; + } + + if (options & F_QUIET) + return; + + if (options & F_FLOOD) + (void)write(STDOUT_FILENO, &BSPACE, 1); + else { + (void)printf("%d bytes from %s, icmp_seq=%u", cc, + pr_addr(from, fromlen), seq); + (void)printf(" hlim=%d", hoplim); + if ((options & F_VERBOSE) != 0) { + struct sockaddr_in6 dstsa; + + memset(&dstsa, 0, sizeof(dstsa)); + dstsa.sin6_family = AF_INET6; +#ifdef SIN6_LEN + dstsa.sin6_len = sizeof(dstsa); +#endif + dstsa.sin6_scope_id = pktinfo->ipi6_ifindex; + dstsa.sin6_addr = pktinfo->ipi6_addr; + (void)printf(" dst=%s", + pr_addr((struct sockaddr *)&dstsa, + sizeof(dstsa))); + } + if (timing) + (void)printf(" time=%g ms", triptime); + if (dupflag) + (void)printf("(DUP!)"); + /* check the data */ + cp = buf + off + ICMP6ECHOLEN + ICMP6ECHOTMLEN; + dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN; + for (i = 8; cp < end; ++i, ++cp, ++dp) { + if (*cp != *dp) { + (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp); + break; + } + } + } + } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) { + seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce); + ++nreceived; + if (TST(seq % mx_dup_ck)) { + ++nrepeats; + --nreceived; + dupflag = 1; + } else { + SET(seq % mx_dup_ck); + dupflag = 0; + } + + if (options & F_QUIET) + return; + + (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); + + switch (ntohs(ni->ni_code)) { + case ICMP6_NI_SUCCESS: + break; + case ICMP6_NI_REFUSED: + printf("refused, type 0x%x", ntohs(ni->ni_type)); + goto fqdnend; + case ICMP6_NI_UNKNOWN: + printf("unknown, type 0x%x", ntohs(ni->ni_type)); + goto fqdnend; + default: + printf("unknown code 0x%x, type 0x%x", + ntohs(ni->ni_code), ntohs(ni->ni_type)); + goto fqdnend; + } + + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + printf("NodeInfo NOOP"); + break; + case NI_QTYPE_SUPTYPES: + pr_suptypes(ni, end - (u_char *)ni); + break; + case NI_QTYPE_NODEADDR: + pr_nodeaddr(ni, end - (u_char *)ni); + break; + case NI_QTYPE_FQDN: + default: /* XXX: for backward compatibility */ + cp = (u_char *)ni + ICMP6_NIRLEN; + if (buf[off + ICMP6_NIRLEN] == + cc - off - ICMP6_NIRLEN - 1) + oldfqdn = 1; + else + oldfqdn = 0; + if (oldfqdn) { + cp++; /* skip length */ + while (cp < end) { + safeputc(*cp & 0xff); + cp++; + } + } else { + i = 0; + while (cp < end) { + if (dnsdecode((const u_char **)&cp, end, + (const u_char *)(ni + 1), dnsname, + sizeof(dnsname)) == NULL) { + printf("???"); + break; + } + /* + * name-lookup special handling for + * truncated name + */ + if (cp + 1 <= end && !*cp && + strlen(dnsname) > 0) { + dnsname[strlen(dnsname) - 1] = '\0'; + cp++; + } + printf("%s%s", i > 0 ? "," : "", + dnsname); + } + } + if (options & F_VERBOSE) { + int32_t ttl; + int comma = 0; + + (void)printf(" ("); /*)*/ + + switch (ni->ni_code) { + case ICMP6_NI_REFUSED: + (void)printf("refused"); + comma++; + break; + case ICMP6_NI_UNKNOWN: + (void)printf("unknwon qtype"); + comma++; + break; + } + + if ((end - (u_char *)ni) < ICMP6_NIRLEN) { + /* case of refusion, unknown */ + /*(*/ + putchar(')'); + goto fqdnend; + } + ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]); + if (comma) + printf(","); + if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) { + (void)printf("TTL=%d:meaningless", + (int)ttl); + } else { + if (ttl < 0) { + (void)printf("TTL=%d:invalid", + ttl); + } else + (void)printf("TTL=%d", ttl); + } + comma++; + + if (oldfqdn) { + if (comma) + printf(","); + printf("03 draft"); + comma++; + } else { + cp = (u_char *)ni + ICMP6_NIRLEN; + if (cp == end) { + if (comma) + printf(","); + printf("no name"); + comma++; + } + } + + if (buf[off + ICMP6_NIRLEN] != + cc - off - ICMP6_NIRLEN - 1 && oldfqdn) { + if (comma) + printf(","); + (void)printf("invalid namelen:%d/%lu", + buf[off + ICMP6_NIRLEN], + (u_long)cc - off - ICMP6_NIRLEN - 1); + comma++; + } + /*(*/ + putchar(')'); + } + fqdnend: + ; + } + } else { + /* We've got something other than an ECHOREPLY */ + if (!(options & F_VERBOSE)) + return; + (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen)); + pr_icmph(icp, end); + } + + if (!(options & F_FLOOD)) { + (void)putchar('\n'); + if (options & F_VERBOSE) + pr_exthdrs(mhdr); + (void)fflush(stdout); + } +#undef safeputc +} + +void +pr_exthdrs(mhdr) + struct msghdr *mhdr; +{ + struct cmsghdr *cm; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_level != IPPROTO_IPV6) + continue; + + switch (cm->cmsg_type) { + case IPV6_HOPOPTS: + printf(" HbH Options: "); + pr_ip6opt(CMSG_DATA(cm)); + break; + case IPV6_DSTOPTS: +#ifdef IPV6_RTHDRDSTOPTS + case IPV6_RTHDRDSTOPTS: +#endif + printf(" Dst Options: "); + pr_ip6opt(CMSG_DATA(cm)); + break; + case IPV6_RTHDR: + printf(" Routing: "); + pr_rthdr(CMSG_DATA(cm)); + break; + } + } +} + +#ifdef USE_RFC2292BIS +void +pr_ip6opt(void *extbuf) +{ + struct ip6_hbh *ext; + int currentlen; + u_int8_t type; + size_t extlen, len; + void *databuf; + size_t offset; + u_int16_t value2; + u_int32_t value4; + + ext = (struct ip6_hbh *)extbuf; + extlen = (ext->ip6h_len + 1) * 8; + printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt, + (unsigned int)ext->ip6h_len, (unsigned long)extlen); + + currentlen = 0; + while (1) { + currentlen = inet6_opt_next(extbuf, extlen, currentlen, + &type, &len, &databuf); + if (currentlen == -1) + break; + switch (type) { + /* + * Note that inet6_opt_next automatically skips any padding + * optins. + */ + case IP6OPT_JUMBO: + offset = 0; + offset = inet6_opt_get_val(databuf, offset, + &value4, sizeof(value4)); + printf(" Jumbo Payload Opt: Length %u\n", + (u_int32_t)ntohl(value4)); + break; + case IP6OPT_ROUTER_ALERT: + offset = 0; + offset = inet6_opt_get_val(databuf, offset, + &value2, sizeof(value2)); + printf(" Router Alert Opt: Type %u\n", + ntohs(value2)); + break; + default: + printf(" Received Opt %u len %lu\n", + type, (unsigned long)len); + break; + } + } + return; +} +#else /* !USE_RFC2292BIS */ +/* ARGSUSED */ +void +pr_ip6opt(void *extbuf) +{ + putchar('\n'); + return; +} +#endif /* USE_RFC2292BIS */ + +#ifdef USE_RFC2292BIS +void +pr_rthdr(void *extbuf) +{ + struct in6_addr *in6; + char ntopbuf[INET6_ADDRSTRLEN]; + struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf; + int i, segments; + + /* print fixed part of the header */ + printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt, + rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type); + if ((segments = inet6_rth_segments(extbuf)) >= 0) + printf("%d segments, ", segments); + else + printf("segments unknown, "); + printf("%d left\n", rh->ip6r_segleft); + + for (i = 0; i < segments; i++) { + in6 = inet6_rth_getaddr(extbuf, i); + if (in6 == NULL) + printf(" [%d]\n", i); + else { + if (!inet_ntop(AF_INET6, in6, ntopbuf, + sizeof(ntopbuf))) + strncpy(ntopbuf, "?", sizeof(ntopbuf)); + printf(" [%d]%s\n", i, ntopbuf); + } + } + + return; + +} + +#else /* !USE_RFC2292BIS */ +/* ARGSUSED */ +void +pr_rthdr(void *extbuf) +{ + putchar('\n'); + return; +} +#endif /* USE_RFC2292BIS */ + +int +pr_bitrange(v, s, ii) + u_int32_t v; + int s; + int ii; +{ + int off; + int i; + + off = 0; + while (off < 32) { + /* shift till we have 0x01 */ + if ((v & 0x01) == 0) { + if (ii > 1) + printf("-%u", s + off - 1); + ii = 0; + switch (v & 0x0f) { + case 0x00: + v >>= 4; + off += 4; + continue; + case 0x08: + v >>= 3; + off += 3; + continue; + case 0x04: case 0x0c: + v >>= 2; + off += 2; + continue; + default: + v >>= 1; + off += 1; + continue; + } + } + + /* we have 0x01 with us */ + for (i = 0; i < 32 - off; i++) { + if ((v & (0x01 << i)) == 0) + break; + } + if (!ii) + printf(" %u", s + off); + ii += i; + v >>= i; off += i; + } + return ii; +} + +void +pr_suptypes(ni, nilen) + struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */ + size_t nilen; +{ + size_t clen; + u_int32_t v; + const u_char *cp, *end; + u_int16_t cur; + struct cbit { + u_int16_t words; /*32bit count*/ + u_int16_t skip; + } cbit; +#define MAXQTYPES (1 << 16) + size_t off; + int b; + + cp = (u_char *)(ni + 1); + end = ((u_char *)ni) + nilen; + cur = 0; + b = 0; + + printf("NodeInfo Supported Qtypes"); + if (options & F_VERBOSE) { + if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) + printf(", compressed bitmap"); + else + printf(", raw bitmap"); + } + + while (cp < end) { + clen = (size_t)(end - cp); + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) { + if (clen == 0 || clen > MAXQTYPES / 8 || + clen % sizeof(v)) { + printf("???"); + return; + } + } else { + if (clen < sizeof(cbit) || clen % sizeof(v)) + return; + memcpy(&cbit, cp, sizeof(cbit)); + if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) > + clen) + return; + cp += sizeof(cbit); + clen = ntohs(cbit.words) * sizeof(v); + if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 > + MAXQTYPES) + return; + } + + for (off = 0; off < clen; off += sizeof(v)) { + memcpy(&v, cp + off, sizeof(v)); + v = (u_int32_t)ntohl(v); + b = pr_bitrange(v, (int)(cur + off * 8), b); + } + /* flush the remaining bits */ + b = pr_bitrange(0, (int)(cur + off * 8), b); + + cp += clen; + cur += clen * 8; + if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) + cur += ntohs(cbit.skip) * 32; + } +} + +void +pr_nodeaddr(ni, nilen) + struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */ + int nilen; +{ + u_char *cp = (u_char *)(ni + 1); + char ntop_buf[INET6_ADDRSTRLEN]; + int withttl = 0; + + nilen -= sizeof(struct icmp6_nodeinfo); + + if (options & F_VERBOSE) { + switch (ni->ni_code) { + case ICMP6_NI_REFUSED: + (void)printf("refused"); + break; + case ICMP6_NI_UNKNOWN: + (void)printf("unknown qtype"); + break; + } + if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE) + (void)printf(" truncated"); + } + putchar('\n'); + if (nilen <= 0) + printf(" no address\n"); + + /* + * In icmp-name-lookups 05 and later, TTL of each returned address + * is contained in the resposne. We try to detect the version + * by the length of the data, but note that the detection algorithm + * is incomplete. We assume the latest draft by default. + */ + if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0) + withttl = 1; + while (nilen > 0) { + u_int32_t ttl; + + if (withttl) { + /* XXX: alignment? */ + ttl = (u_int32_t)ntohl(*(u_int32_t *)cp); + cp += sizeof(u_int32_t); + nilen -= sizeof(u_int32_t); + } + + if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) == + NULL) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf(" %s", ntop_buf); + if (withttl) { + if (ttl == 0xffffffff) { + /* + * XXX: can this convention be applied to all + * type of TTL (i.e. non-ND TTL)? + */ + printf("(TTL=infty)"); + } + else + printf("(TTL=%u)", ttl); + } + putchar('\n'); + + nilen -= sizeof(struct in6_addr); + cp += sizeof(struct in6_addr); + } +} + +int +get_hoplim(mhdr) + struct msghdr *mhdr; +{ + struct cmsghdr *cm; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(-1); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_HOPLIMIT && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + return(*(int *)CMSG_DATA(cm)); + } + + return(-1); +} + +struct in6_pktinfo * +get_rcvpktinfo(mhdr) + struct msghdr *mhdr; +{ + struct cmsghdr *cm; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(NULL); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO && + cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) + return((struct in6_pktinfo *)CMSG_DATA(cm)); + } + + return(NULL); +} + +int +get_pathmtu(mhdr) + struct msghdr *mhdr; +{ +#ifdef IPV6_RECVPATHMTU + struct cmsghdr *cm; + struct ip6_mtuinfo *mtuctl = NULL; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_len == 0) + return(0); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PATHMTU && + cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) { + mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm); + + /* + * If the notified destination is different from + * the one we are pinging, just ignore the info. + * We check the scope ID only when both notified value + * and our own value have non-0 values, because we may + * have used the default scope zone ID for sending, + * in which case the scope ID value is 0. + */ + if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr, + &dst.sin6_addr) || + (mtuctl->ip6m_addr.sin6_scope_id && + dst.sin6_scope_id && + mtuctl->ip6m_addr.sin6_scope_id != + dst.sin6_scope_id)) { + if ((options & F_VERBOSE) != 0) { + printf("path MTU for %s is notified. " + "(ignored)\n", + pr_addr((struct sockaddr *)&mtuctl->ip6m_addr, + sizeof(mtuctl->ip6m_addr))); + } + return(0); + } + + /* + * Ignore an invalid MTU. XXX: can we just believe + * the kernel check? + */ + if (mtuctl->ip6m_mtu < IPV6_MMTU) + return(0); + + /* notification for our destination. return the MTU. */ + return((int)mtuctl->ip6m_mtu); + } + } +#endif + return(0); +} + +void +set_pathmtu(mtu) + int mtu; +{ +#ifdef IPV6_USE_MTU + static int firsttime = 1; + struct cmsghdr *cm; + + if (firsttime) { + int oldlen = smsghdr.msg_controllen; + char *oldbuf = smsghdr.msg_control; + + /* XXX: We need to enlarge control message buffer */ + firsttime = 0; /* prevent further enlargement */ + + smsghdr.msg_controllen = oldlen + CMSG_SPACE(sizeof(int)); + if ((smsghdr.msg_control = + (char *)malloc(smsghdr.msg_controllen)) == NULL) + err(1, "set_pathmtu: malloc"); + cm = (struct cmsghdr *)CMSG_FIRSTHDR(&smsghdr); + cm->cmsg_len = CMSG_LEN(sizeof(int)); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_USE_MTU; + + cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm); + if (oldlen) + memcpy((void *)cm, (void *)oldbuf, oldlen); + + free(oldbuf); + } + + /* + * look for a cmsgptr that points MTU structure. + * XXX: this procedure seems redundant at this moment, but we'd better + * keep the code generic enough for future extensions. + */ + for (cm = CMSG_FIRSTHDR(&smsghdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&smsghdr, cm)) { + if (cm->cmsg_len == 0) /* XXX: paranoid check */ + errx(1, "set_pathmtu: internal error"); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_USE_MTU && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + break; + } + + if (cm == NULL) + errx(1, "set_pathmtu: internal error: no space for path MTU"); + + *(int *)CMSG_DATA(cm) = mtu; +#endif +} + +/* + * tvsub -- + * Subtract 2 timeval structs: out = out - in. Out is assumed to + * be >= in. + */ +void +tvsub(out, in) + register struct timeval *out, *in; +{ + if ((out->tv_usec -= in->tv_usec) < 0) { + --out->tv_sec; + out->tv_usec += 1000000; + } + out->tv_sec -= in->tv_sec; +} + +/* + * onint -- + * SIGINT handler. + */ +/* ARGSUSED */ +void +onint(notused) + int notused; +{ + summary(); + + (void)signal(SIGINT, SIG_DFL); + (void)kill(getpid(), SIGINT); + + /* NOTREACHED */ + exit(1); +} + +/* + * summary -- + * Print out statistics. + */ +void +summary() +{ + + (void)printf("\n--- %s ping6 statistics ---\n", hostname); + (void)printf("%ld packets transmitted, ", ntransmitted); + (void)printf("%ld packets received, ", nreceived); + if (nrepeats) + (void)printf("+%ld duplicates, ", nrepeats); + if (ntransmitted) { + if (nreceived > ntransmitted) + (void)printf("-- somebody's printing up packets!"); + else + (void)printf("%d%% packet loss", + (int) (((ntransmitted - nreceived) * 100) / + ntransmitted)); + } + (void)putchar('\n'); + if (nreceived && timing) { + /* Only display average to microseconds */ + double num = nreceived + nrepeats; + double avg = tsum / num; +#if defined(__OpenBSD__) || defined(__NetBSD__) + double dev = sqrt(tsumsq / num - avg * avg); + (void)printf( + "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n", + tmin, avg, tmax, dev); +#else + (void)printf( + "round-trip min/avg/max = %.3f/%.3f/%.3f ms\n", + tmin, avg, tmax); +#endif + (void)fflush(stdout); + } + (void)fflush(stdout); +} + +/*subject type*/ +static char *niqcode[] = { + "IPv6 address", + "DNS label", /*or empty*/ + "IPv4 address", +}; + +/*result code*/ +static char *nircode[] = { + "Success", "Refused", "Unknown", +}; + + +/* + * pr_icmph -- + * Print a descriptive string about an ICMP header. + */ +void +pr_icmph(icp, end) + struct icmp6_hdr *icp; + u_char *end; +{ + char ntop_buf[INET6_ADDRSTRLEN]; + struct nd_redirect *red; + struct icmp6_nodeinfo *ni; + char dnsname[MAXDNAME + 1]; + const u_char *cp; + size_t l; + + switch (icp->icmp6_type) { + case ICMP6_DST_UNREACH: + switch (icp->icmp6_code) { + case ICMP6_DST_UNREACH_NOROUTE: + (void)printf("No Route to Destination\n"); + break; + case ICMP6_DST_UNREACH_ADMIN: + (void)printf("Destination Administratively " + "Unreachable\n"); + break; + case ICMP6_DST_UNREACH_BEYONDSCOPE: + (void)printf("Destination Unreachable Beyond Scope\n"); + break; + case ICMP6_DST_UNREACH_ADDR: + (void)printf("Destination Host Unreachable\n"); + break; + case ICMP6_DST_UNREACH_NOPORT: + (void)printf("Destination Port Unreachable\n"); + break; + default: + (void)printf("Destination Unreachable, Bad Code: %d\n", + icp->icmp6_code); + break; + } + /* Print returned IP header information */ + pr_retip((struct ip6_hdr *)(icp + 1), end); + break; + case ICMP6_PACKET_TOO_BIG: + (void)printf("Packet too big mtu = %d\n", + (int)ntohl(icp->icmp6_mtu)); + pr_retip((struct ip6_hdr *)(icp + 1), end); + break; + case ICMP6_TIME_EXCEEDED: + switch (icp->icmp6_code) { + case ICMP6_TIME_EXCEED_TRANSIT: + (void)printf("Time to live exceeded\n"); + break; + case ICMP6_TIME_EXCEED_REASSEMBLY: + (void)printf("Frag reassembly time exceeded\n"); + break; + default: + (void)printf("Time exceeded, Bad Code: %d\n", + icp->icmp6_code); + break; + } + pr_retip((struct ip6_hdr *)(icp + 1), end); + break; + case ICMP6_PARAM_PROB: + (void)printf("Parameter problem: "); + switch (icp->icmp6_code) { + case ICMP6_PARAMPROB_HEADER: + (void)printf("Erroneous Header "); + break; + case ICMP6_PARAMPROB_NEXTHEADER: + (void)printf("Unknown Nextheader "); + break; + case ICMP6_PARAMPROB_OPTION: + (void)printf("Unrecognized Option "); + break; + default: + (void)printf("Bad code(%d) ", icp->icmp6_code); + break; + } + (void)printf("pointer = 0x%02x\n", + (u_int32_t)ntohl(icp->icmp6_pptr)); + pr_retip((struct ip6_hdr *)(icp + 1), end); + break; + case ICMP6_ECHO_REQUEST: + (void)printf("Echo Request"); + /* XXX ID + Seq + Data */ + break; + case ICMP6_ECHO_REPLY: + (void)printf("Echo Reply"); + /* XXX ID + Seq + Data */ + break; + case ICMP6_MEMBERSHIP_QUERY: + (void)printf("Listener Query"); + break; + case ICMP6_MEMBERSHIP_REPORT: + (void)printf("Listener Report"); + break; + case ICMP6_MEMBERSHIP_REDUCTION: + (void)printf("Listener Done"); + break; + case ND_ROUTER_SOLICIT: + (void)printf("Router Solicitation"); + break; + case ND_ROUTER_ADVERT: + (void)printf("Router Advertisement"); + break; + case ND_NEIGHBOR_SOLICIT: + (void)printf("Neighbor Solicitation"); + break; + case ND_NEIGHBOR_ADVERT: + (void)printf("Neighbor Advertisement"); + break; + case ND_REDIRECT: + red = (struct nd_redirect *)icp; + (void)printf("Redirect\n"); + if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf, + sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + (void)printf("Destination: %s", ntop_buf); + if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf, + sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + (void)printf(" New Target: %s", ntop_buf); + break; + case ICMP6_NI_QUERY: + (void)printf("Node Information Query"); + /* XXX ID + Seq + Data */ + ni = (struct icmp6_nodeinfo *)icp; + l = end - (u_char *)(ni + 1); + printf(", "); + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + (void)printf("NOOP"); + break; + case NI_QTYPE_SUPTYPES: + (void)printf("Supported qtypes"); + break; + case NI_QTYPE_FQDN: + (void)printf("DNS name"); + break; + case NI_QTYPE_NODEADDR: + (void)printf("nodeaddr"); + break; + case NI_QTYPE_IPV4ADDR: + (void)printf("IPv4 nodeaddr"); + break; + default: + (void)printf("unknown qtype"); + break; + } + if (options & F_VERBOSE) { + switch (ni->ni_code) { + case ICMP6_NI_SUBJ_IPV6: + if (l == sizeof(struct in6_addr) && + inet_ntop(AF_INET6, ni + 1, ntop_buf, + sizeof(ntop_buf)) != NULL) { + (void)printf(", subject=%s(%s)", + niqcode[ni->ni_code], ntop_buf); + } else { +#if 1 + /* backward compat to -W */ + (void)printf(", oldfqdn"); +#else + (void)printf(", invalid"); +#endif + } + break; + case ICMP6_NI_SUBJ_FQDN: + if (end == (u_char *)(ni + 1)) { + (void)printf(", no subject"); + break; + } + printf(", subject=%s", niqcode[ni->ni_code]); + cp = (const u_char *)(ni + 1); + if (dnsdecode(&cp, end, NULL, dnsname, + sizeof(dnsname)) != NULL) + printf("(%s)", dnsname); + else + printf("(invalid)"); + break; + case ICMP6_NI_SUBJ_IPV4: + if (l == sizeof(struct in_addr) && + inet_ntop(AF_INET, ni + 1, ntop_buf, + sizeof(ntop_buf)) != NULL) { + (void)printf(", subject=%s(%s)", + niqcode[ni->ni_code], ntop_buf); + } else + (void)printf(", invalid"); + break; + default: + (void)printf(", invalid"); + break; + } + } + break; + case ICMP6_NI_REPLY: + (void)printf("Node Information Reply"); + /* XXX ID + Seq + Data */ + ni = (struct icmp6_nodeinfo *)icp; + printf(", "); + switch (ntohs(ni->ni_qtype)) { + case NI_QTYPE_NOOP: + (void)printf("NOOP"); + break; + case NI_QTYPE_SUPTYPES: + (void)printf("Supported qtypes"); + break; + case NI_QTYPE_FQDN: + (void)printf("DNS name"); + break; + case NI_QTYPE_NODEADDR: + (void)printf("nodeaddr"); + break; + case NI_QTYPE_IPV4ADDR: + (void)printf("IPv4 nodeaddr"); + break; + default: + (void)printf("unknown qtype"); + break; + } + if (options & F_VERBOSE) { + if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0])) + printf(", invalid"); + else + printf(", %s", nircode[ni->ni_code]); + } + break; + default: + (void)printf("Bad ICMP type: %d", icp->icmp6_type); + } +} + +/* + * pr_iph -- + * Print an IP6 header. + */ +void +pr_iph(ip6) + struct ip6_hdr *ip6; +{ + u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; + u_int8_t tc; + char ntop_buf[INET6_ADDRSTRLEN]; + + tc = *(&ip6->ip6_vfc + 1); /* XXX */ + tc = (tc >> 4) & 0x0f; + tc |= (ip6->ip6_vfc << 4); + + printf("Vr TC Flow Plen Nxt Hlim\n"); + printf(" %1x %02x %05x %04x %02x %02x\n", + (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow), + ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim); + if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf("%s->", ntop_buf); + if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf))) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + printf("%s\n", ntop_buf); +} + +/* + * pr_addr -- + * Return an ascii host address as a dotted quad and optionally with + * a hostname. + */ +const char * +pr_addr(addr, addrlen) + struct sockaddr *addr; + int addrlen; +{ + static char buf[NI_MAXHOST]; + int flag; + +#ifdef NI_WITHSCOPEID + flag = NI_WITHSCOPEID; +#else + flag = 0; +#endif + if ((options & F_HOSTNAME) == 0) + flag |= NI_NUMERICHOST; + + if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) + return (buf); + else + return "?"; +} + +/* + * pr_retip -- + * Dump some info on a returned (via ICMPv6) IPv6 packet. + */ +void +pr_retip(ip6, end) + struct ip6_hdr *ip6; + u_char *end; +{ + u_char *cp = (u_char *)ip6, nh; + int hlen; + + if (end - (u_char *)ip6 < sizeof(*ip6)) { + printf("IP6"); + goto trunc; + } + pr_iph(ip6); + hlen = sizeof(*ip6); + + nh = ip6->ip6_nxt; + cp += hlen; + while (end - cp >= 8) { + switch (nh) { + case IPPROTO_HOPOPTS: + printf("HBH "); + hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3; + nh = ((struct ip6_hbh *)cp)->ip6h_nxt; + break; + case IPPROTO_DSTOPTS: + printf("DSTOPT "); + hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3; + nh = ((struct ip6_dest *)cp)->ip6d_nxt; + break; + case IPPROTO_FRAGMENT: + printf("FRAG "); + hlen = sizeof(struct ip6_frag); + nh = ((struct ip6_frag *)cp)->ip6f_nxt; + break; + case IPPROTO_ROUTING: + printf("RTHDR "); + hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3; + nh = ((struct ip6_rthdr *)cp)->ip6r_nxt; + break; +#ifdef IPSEC + case IPPROTO_AH: + printf("AH "); + hlen = (((struct ah *)cp)->ah_len+2) << 2; + nh = ((struct ah *)cp)->ah_nxt; + break; +#endif + case IPPROTO_ICMPV6: + printf("ICMP6: type = %d, code = %d\n", + *cp, *(cp + 1)); + return; + case IPPROTO_ESP: + printf("ESP\n"); + return; + case IPPROTO_TCP: + printf("TCP: from port %u, to port %u (decimal)\n", + (*cp * 256 + *(cp + 1)), + (*(cp + 2) * 256 + *(cp + 3))); + return; + case IPPROTO_UDP: + printf("UDP: from port %u, to port %u (decimal)\n", + (*cp * 256 + *(cp + 1)), + (*(cp + 2) * 256 + *(cp + 3))); + return; + default: + printf("Unknown Header(%d)\n", nh); + return; + } + + if ((cp += hlen) >= end) + goto trunc; + } + if (end - cp < 8) + goto trunc; + + putchar('\n'); + return; + + trunc: + printf("...\n"); + return; +} + +void +fill(bp, patp) + char *bp, *patp; +{ + register int ii, jj, kk; + int pat[16]; + char *cp; + + for (cp = patp; *cp; cp++) + if (!isxdigit(*cp)) + errx(1, "patterns must be specified as hex digits"); + ii = sscanf(patp, + "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", + &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], + &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], + &pat[13], &pat[14], &pat[15]); + +/* xxx */ + if (ii > 0) + for (kk = 0; + kk <= MAXDATALEN - (8 + sizeof(struct timeval) + ii); + kk += ii) + for (jj = 0; jj < ii; ++jj) + bp[jj + kk] = pat[jj]; + if (!(options & F_QUIET)) { + (void)printf("PATTERN: 0x"); + for (jj = 0; jj < ii; ++jj) + (void)printf("%02x", bp[jj] & 0xFF); + (void)printf("\n"); + } +} + +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC +int +setpolicy(so, policy) + int so; + char *policy; +{ + char *buf; + + if (policy == NULL) + return 0; /* ignore */ + + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) + errx(1, "%s", ipsec_strerror()); + if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, + ipsec_get_policylen(buf)) < 0) + warnx("Unable to set IPSec policy"); + free(buf); + + return 0; +} +#endif +#endif + +char * +nigroup(name) + char *name; +{ + char *p; + unsigned char *q; + MD5_CTX ctxt; + u_int8_t digest[16]; + u_int8_t c; + size_t l; + char hbuf[NI_MAXHOST]; + struct in6_addr in6; + + p = strchr(name, '.'); + if (!p) + p = name + strlen(name); + l = p - name; + if (l > 63 || l > sizeof(hbuf) - 1) + return NULL; /*label too long*/ + strncpy(hbuf, name, l); + hbuf[(int)l] = '\0'; + + for (q = name; *q; q++) { + if (isupper(*q)) + *q = tolower(*q); + } + + /* generate 8 bytes of pseudo-random value. */ + bzero(&ctxt, sizeof(ctxt)); + MD5Init(&ctxt); + c = l & 0xff; + MD5Update(&ctxt, &c, sizeof(c)); + MD5Update(&ctxt, name, l); + MD5Final(digest, &ctxt); + + if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1) + return NULL; /*XXX*/ + bcopy(digest, &in6.s6_addr[12], 4); + + if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL) + return NULL; + + return strdup(hbuf); +} + +void +usage() +{ + (void)fprintf(stderr, + "usage: ping6 [-dfH" +#ifdef IPV6_USE_MIN_MTU + "m" +#endif + "nNqtvwW" +#ifdef IPV6_REACHCONF + "R" +#endif +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + "] [-P policy" +#else + "AE" +#endif +#endif + "] [-a [aAclsg]] [-b sockbufsiz] [-c count] \n" + "\t[-I interface] [-i wait] [-l preload] [-p pattern] " + "[-S sourceaddr]\n" + "\t[-s packetsize] [-h hoplimit] [hops...] host\n"); + exit(1); +} diff --git a/racoon.tproj/Makefile b/racoon.tproj/Makefile new file mode 100644 index 0000000..5582c9c --- /dev/null +++ b/racoon.tproj/Makefile @@ -0,0 +1,71 @@ +# +# Generated by the Apple Project Builder. +# +# NOTE: Do NOT change this file -- Project Builder maintains it. +# +# Put all of your customizations in files called Makefile.preamble +# and Makefile.postamble (both optional), and Makefile will include them. +# + +NAME = racoon + +PROJECTVERSION = 2.8 +PROJECT_TYPE = Tool + +HFILES = admin.h algorithm.h backupsa.h crypto_openssl.h dnssec.h\ + grabmyaddr.h gssapi.h handler.h ipsec_doi.h isakmp_agg.h\ + isakmp_base.h isakmp_ident.h isakmp_inf.h isakmp_newg.h\ + isakmp_quick.h isakmp.h localconf.h logger.h misc.h oakley.h\ + pfkey.h plog.h policy.h proposal.h remoteconf.h\ + rijndael-alg-fst.h rijndael-api-fst.h safefile.h sainfo.h\ + schedule.h session.h sha2.h sockmisc.h str2val.h strnames.h\ + vendorid.h vmbuf.h admin_var.h cftoken.h debug.h dhgroup.h\ + gcmalloc.h isakmp_var.h libpfkey.h netdb_dnssec.h\ + rijndael_local.h rijndael.h var.h + +OTHERLINKED = cfparse.y cftoken.l + +CFILES = admin.c algorithm.c backupsa.c crypto_openssl.c dnssec.c\ + getcertsbyname.c grabmyaddr.c gssapi.c handler.c ipsec_doi.c\ + isakmp.c isakmp_agg.c isakmp_base.c isakmp_ident.c\ + isakmp_inf.c isakmp_newg.c isakmp_quick.c key_debug.c\ + localconf.c logger.c main.c misc.c oakley.c pfkey.c\ + pfkey2.c pfkey_dump.c plog.c policy.c proposal.c\ + remoteconf.c rijndael-alg-fst.c rijndael-api-fst.c safefile.c\ + sainfo.c schedule.c session.c sha2.c sockmisc.c str2val.c\ + strnames.c vendorid.c vmbuf.c + +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble boxes-fst.dat\ + psk.txt racoon.8 racoon.conf racoon.conf.5 + +OTHERLINKEDOFILES = cfparse.o cftoken.o + +MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles +CODE_GEN_STYLE = DYNAMIC +MAKEFILE = tool.make +NEXTSTEP_INSTALLDIR = /usr/sbin +WINDOWS_INSTALLDIR = /Library/Executables +PDO_UNIX_INSTALLDIR = /bin +LIBS = -lcrypto -lipsec -lssl +DEBUG_LIBS = $(LIBS) +PROF_LIBS = $(LIBS) + + + + +NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc +WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc +PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc +NEXTSTEP_JAVA_COMPILER = /usr/bin/javac +WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe +PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac + +include $(MAKEFILEDIR)/platform.make + +-include Makefile.preamble + +include $(MAKEFILEDIR)/$(MAKEFILE) + +-include Makefile.postamble + +-include Makefile.dependencies diff --git a/racoon.tproj/Makefile.postamble b/racoon.tproj/Makefile.postamble new file mode 100644 index 0000000..4537084 --- /dev/null +++ b/racoon.tproj/Makefile.postamble @@ -0,0 +1,110 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGES: langages in which the project is written (default "English") +# English_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# +install-man-page: + install -d $(DSTROOT)/usr/share/man/man8 + install -d $(DSTROOT)/usr/share/man/man5 + install -c -m 644 racoon.8 $(DSTROOT)/usr/share/man/man8/racoon.8 + install -c -m 644 racoon.conf.5 $(DSTROOT)/usr/share/man/man5/racoon.conf.5 + +install-config-files: + install -d $(DSTROOT)/private/etc/racoon + install -c -m 644 racoon.conf $(DSTROOT)/private/etc/racoon/racoon.conf + install -c -m 600 psk.txt $(DSTROOT)/private/etc/racoon/psk.txt diff --git a/racoon.tproj/Makefile.preamble b/racoon.tproj/Makefile.preamble new file mode 100644 index 0000000..d80d596 --- /dev/null +++ b/racoon.tproj/Makefile.preamble @@ -0,0 +1,150 @@ +############################################################################### +# Makefile.preamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile for configuring the standard application makefiles +# associated with ProjectBuilder. It is included before the main makefile. +# In Makefile.preamble you set attributes for a project, so they are available +# to the project's makefiles. In contrast, you typically write additional rules or +# override built-in behavior in the Makefile.postamble. +# +# Each directory in a project tree (main project plus subprojects) should +# have its own Makefile.preamble and Makefile.postamble. +############################################################################### +# +# Before the main makefile is included for this project, you may set: +# +# MAKEFILEDIR: Directory in which to find $(MAKEFILE) +# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make) + +# Compiler/linker flags added to the defaults: The OTHER_* variables will be +# inherited by all nested sub-projects, but the LOCAL_ versions of the same +# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's +# Build Attributes inspector if at all possible. To override the default flags +# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The +# variables below are *inputs* to the build process and distinct from the override +# settings done (less often) in the Makefile.postamble. +# +# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler +# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m, +# .cc, .cxx, .C, and .M files. There is no need to respecify the +# flags in OTHER_MFLAGS, etc. +# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files +# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files +# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files +# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when +# precompiling header files +# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool +# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap +# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen +# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc +# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex +LOCAL_CFLAGS=-DHAVE_FUNCTION_MACRO=1 -DENABLE_IPV6=1 -DADVAPI=1 -DHAVE_GETADDRINFO=1 \ +-DHAVE_GETNAMEINFO=1 -DHAVE_LIBSSL=1 -DHAVE_LIBCRYPTO=1 -DHAVE_LIBL=1 -DHAVE_LIBY=1 \ +-DSTDC_HEADERS=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_UNISTD_H=1 \ +-DHAVE_STDARG_H=1 -DHAVE_VARARGS_H=1 -DHAVE_OPENSSL_RSA_H=1 -DHAVE_OPENSSL_PEM_H=1 \ +-DHAVE_OPENSSL_EVP_H=1 -DHAVE_OPENSSL_X509_H=1 -DHAVE_SIGNING_C=1 -DHAVE_OPENSSL_OPENSSLV_H=1 \ +-DTIME_WITH_SYS_TIME=1 -DRETSIGTYPE=void -DHAVE_VPRINTF=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_SELECT=1 \ +-DHAVE_SOCKET=1 -DHAVE_STRERROR=1 -DHAVE_STRTOL=1 -DHAVE_STRTOUL=1 -DHAVE_STRDUP=1 \ +-DHAVE_GETIFADDRS=1 -DINET6 -DHAVE_PFKEYV2 -O -DYIPS_DEBUG -DIPSEC -Dss_family=__ss_family \ +-Dss_len=__ss_len -DSYSCONFDIR=\"/etc/racoon\" -DYY_NO_UNPUT -I../ipsec + +LOCAL_YFLAGS= -d + +# These variables provide hooks enabling you to add behavior at almost every +# stage of the make: +# +# BEFORE_PREBUILD: targets to build before installing headers for a subproject +# AFTER_PREBUILD: targets to build after installing headers for a subproject +# BEFORE_BUILD_RECURSION: targets to make before building subprojects +# BEFORE_BUILD: targets to make before a build, but after subprojects +# AFTER_BUILD: targets to make after a build +# +# BEFORE_INSTALL: targets to build before installing the product +# AFTER_INSTALL: targets to build after installing the product +# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject +# AFTER_POSTINSTALL: targts to build after postinstalling every subproject +# +# BEFORE_INSTALLHDRS: targets to build before installing headers for a +# subproject +# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject +# BEFORE_INSTALLSRC: targets to build before installing source for a subproject +# AFTER_INSTALLSRC: targets to build after installing source for a subproject +# +# BEFORE_DEPEND: targets to build before building dependencies for a +# subproject +# AFTER_DEPEND: targets to build after building dependencies for a +# subproject +# +# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is +# updated every time the project is built. If NO, the dependency +# file is only built when the depend target is invoked. + +# Framework-related variables: +# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the framework's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables + +# Library-related variables: +# PUBLIC_HEADER_DIR: Determines where public exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. For library projects you should +# set this to something like /Developer/Headers/$(NAME). Do not set +# this variable for framework projects unless you do not want the +# header files included in the framework. +# PRIVATE_HEADER_DIR: Determines where private exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. +# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines +# whether the libraries produced are statically linked when they +# are used or if they are dynamically loadable. This defaults to +# DYNAMIC. +# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the library's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables +# +# INSTALL_AS_USER: owner of the intalled products (default root) +# INSTALL_AS_GROUP: group of the installed products (default wheel) +# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX) +# +# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be +# passed on the command line to recursive invocations of make. Note that +# the values in OTHER_*FLAGS are inherited by subprojects automatically -- +# you do not have to (and shouldn't) add OTHER_*FLAGS to +# OTHER_RECURSIVE_VARIABLES. + +# Additional headers to export beyond those in the PB.project: +# OTHER_PUBLIC_HEADERS +# OTHER_PROJECT_HEADERS +# OTHER_PRIVATE_HEADERS + +# Additional files for the project's product: <> +# OTHER_RESOURCES: (non-localized) resources for this project +# OTHER_OFILES: relocatables to be linked into this project +# OTHER_LIBS: more libraries to link against +# OTHER_PRODUCT_DEPENDS: other dependencies of this project +# OTHER_SOURCEFILES: other source files maintained by .pre/postamble +# OTHER_GARBAGE: additional files to be removed by `make clean' +OTHER_LIBS = -lfl + +# Set this to YES if you don't want a final libtool call for a library/framework. +# BUILD_OFILES_LIST_ONLY + +# To include a version string, project source must exist in a directory named +# $(NAME).%d[.%d][.%d] and the following line must be uncommented. +# OTHER_GENERATED_OFILES = $(VERS_OFILE) + +# This definition will suppress stripping of debug symbols when an executable +# is installed. By default it is YES. +# STRIP_ON_INSTALL = NO + +# Uncomment to suppress generation of a KeyValueCoding index when installing +# frameworks (This index is used by WOB and IB to determine keys available +# for an object). Set to YES by default. +# PREINDEX_FRAMEWORK = NO + +# Change this definition to install projects somewhere other than the +# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems +# and "" on other systems. +DSTROOT = $(HOME) +AFTER_INSTALL += install-man-page install-config-files diff --git a/racoon.tproj/PB.project b/racoon.tproj/PB.project new file mode 100644 index 0000000..c46b63a --- /dev/null +++ b/racoon.tproj/PB.project @@ -0,0 +1,130 @@ +{ + "DYNAMIC_CODE_GEN" = YES; + FILESTABLE = { + FRAMEWORKS = (); + "H_FILES" = ( + "admin.h", + "algorithm.h", + "backupsa.h", + "crypto_openssl.h", + "dnssec.h", + "grabmyaddr.h", + "gssapi.h", + "handler.h", + "ipsec_doi.h", + "isakmp_agg.h", + "isakmp_base.h", + "isakmp_ident.h", + "isakmp_inf.h", + "isakmp_newg.h", + "isakmp_quick.h", + "isakmp.h", + "localconf.h", + "logger.h", + "misc.h", + "oakley.h", + "pfkey.h", + "plog.h", + "policy.h", + "proposal.h", + "remoteconf.h", + "rijndael-alg-fst.h", + "rijndael-api-fst.h", + "safefile.h", + "sainfo.h", + "schedule.h", + "session.h", + "sha2.h", + "sockmisc.h", + "str2val.h", + "strnames.h", + "vendorid.h", + "vmbuf.h", + "admin_var.h", + "cftoken.h", + "debug.h", + "dhgroup.h", + "gcmalloc.h", + "isakmp_var.h", + "libpfkey.h", + "netdb_dnssec.h", + "rijndael_local.h", + "rijndael.h", + "var.h" + ); + "OTHER_LIBS" = (crypto, ipsec, ssl); + "OTHER_LINKED" = ( + "admin.c", + "algorithm.c", + "backupsa.c", + "cfparse.y", + "cftoken.l", + "crypto_openssl.c", + "dnssec.c", + "getcertsbyname.c", + "grabmyaddr.c", + "gssapi.c", + "handler.c", + "ipsec_doi.c", + "isakmp.c", + "isakmp_agg.c", + "isakmp_base.c", + "isakmp_ident.c", + "isakmp_inf.c", + "isakmp_newg.c", + "isakmp_quick.c", + "key_debug.c", + "localconf.c", + "logger.c", + "main.c", + "misc.c", + "oakley.c", + "pfkey.c", + "pfkey2.c", + "pfkey_dump.c", + "plog.c", + "policy.c", + "proposal.c", + "remoteconf.c", + "rijndael-alg-fst.c", + "rijndael-api-fst.c", + "safefile.c", + "sainfo.c", + "schedule.c", + "session.c", + "sha2.c", + "sockmisc.c", + "str2val.c", + "strnames.c", + "vendorid.c", + "vmbuf.c" + ); + "OTHER_SOURCES" = ( + "Makefile.preamble", + Makefile, + "Makefile.postamble", + "boxes-fst.dat", + "psk.txt", + "racoon.8", + "racoon.conf", + "racoon.conf.5" + ); + }; + LANGUAGE = English; + MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; + "NEXTSTEP_BUILDTOOL" = "/bin/gnumake"; + "NEXTSTEP_INSTALLDIR" = "/usr/sbin"; + "NEXTSTEP_JAVA_COMPILER" = "/usr/bin/javac"; + "NEXTSTEP_OBJCPLUS_COMPILER" = "/usr/bin/cc"; + "PDO_UNIX_BUILDTOOL" = "$NEXT_ROOT/Developer/bin/make"; + "PDO_UNIX_INSTALLDIR" = "/bin"; + "PDO_UNIX_JAVA_COMPILER" = "$(JDKBINDIR)/javac"; + "PDO_UNIX_OBJCPLUS_COMPILER" = "$(NEXTDEV_BIN)/gcc"; + PROJECTNAME = racoon; + PROJECTTYPE = Tool; + PROJECTVERSION = "2.8"; + "WINDOWS_BUILDTOOL" = "$NEXT_ROOT/Developer/Executables/make"; + "WINDOWS_INSTALLDIR" = "/Library/Executables"; + "WINDOWS_JAVA_COMPILER" = "$(JDKBINDIR)/javac.exe"; + "WINDOWS_OBJCPLUS_COMPILER" = "$(DEVDIR)/gcc"; +} diff --git a/racoon.tproj/admin.c b/racoon.tproj/admin.c new file mode 100644 index 0000000..575c556 --- /dev/null +++ b/racoon.tproj/admin.c @@ -0,0 +1,486 @@ +/* $KAME: admin.c,v 1.22 2001/04/03 15:51:54 thorpej 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. 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. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "localconf.h" +#include "remoteconf.h" +#include "grabmyaddr.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "pfkey.h" +#include "admin.h" +#include "admin_var.h" +#include "session.h" +#include "gcmalloc.h" + +static struct sockaddr_un sunaddr; +static int admin_process __P((int, char *)); +static int admin_reply __P((int, struct admin_com *, vchar_t *)); + +int +admin_handler() +{ + int so2; + struct sockaddr_storage from; + int fromlen = sizeof(from); + struct admin_com com; + char *combuf = NULL; + pid_t pid = -1; + int len, error = -1; + + so2 = accept(lcconf->sock_admin, (struct sockaddr *)&from, &fromlen); + if (so2 < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to accept admin command: %s\n", + strerror(errno)); + return -1; + } + + /* get buffer length */ + while ((len = recv(so2, (char *)&com, sizeof(com), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv admin command: %s\n", + strerror(errno)); + goto end; + } + + /* sanity check */ + if (len < sizeof(com)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid header length of admin command\n"); + goto end; + } + + /* get buffer to receive */ + if ((combuf = racoon_malloc(com.ac_len)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to alloc buffer for admin command\n"); + goto end; + } + + /* get real data */ + while ((len = recv(so2, combuf, com.ac_len, 0)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv admin command: %s\n", + strerror(errno)); + goto end; + } + + /* don't fork() because of reloading config. */ + if (com.ac_cmd == ADMIN_RELOAD_CONF) { + /* reload does not work at all! */ + signal_handler(SIGHUP); + goto end; + } + + /* fork for processing */ + if (!f_foreground) { + if ((pid = fork()) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to fork for admin processing: %s\n", + strerror(errno)); + goto end; + } + + /* parant's process. */ + if (pid != 0) { + error = 0; + goto end; + } + + /* child's process */ + admin_close(); + } + + /* exit in this function. */ + error = admin_process(so2, combuf); + + end: + (void)close(so2); + if (combuf) + racoon_free(combuf); + + /* exit if child's process. */ + if (pid == 0 && !f_foreground) + exit(error); + + return error; +} + +/* + * main child's process. + */ +static int +admin_process(so2, combuf) + int so2; + char *combuf; +{ + struct admin_com *com = (struct admin_com *)combuf; + vchar_t *buf = NULL; + int error = 0; + + com->ac_errno = 0; + + switch (com->ac_cmd) { + case ADMIN_RELOAD_CONF: + /* don't entered because of proccessing it in other place. */ + plog(LLV_ERROR, LOCATION, NULL, "should never reach here\n"); + goto bad; + + case ADMIN_SHOW_SCHED: + { + caddr_t p; + int len; + if (sched_dump(&p, &len) == -1) + com->ac_errno = -1; + buf = vmalloc(len); + if (buf == NULL) + com->ac_errno = -1; + memcpy(buf->v, p, len); + } + break; + case ADMIN_SHOW_SA: + case ADMIN_FLUSH_SA: + { + switch (com->ac_proto) { + case ADMIN_PROTO_ISAKMP: + switch (com->ac_cmd) { + case ADMIN_SHOW_SA: + buf = dumpph1(); + if (buf == NULL) + com->ac_errno = -1; + break; + case ADMIN_FLUSH_SA: + flushph1(); + break; + } + break; + case ADMIN_PROTO_IPSEC: + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + switch (com->ac_cmd) { + case ADMIN_SHOW_SA: + { + u_int p; + p = admin2pfkey_proto(com->ac_proto); + if (p == -1) + goto bad; + buf = pfkey_dump_sadb(p); + if (buf == NULL) + com->ac_errno = -1; + } + break; + case ADMIN_FLUSH_SA: + pfkey_flush_sadb(com->ac_proto); + break; + } + break; + + case ADMIN_PROTO_INTERNAL: + switch (com->ac_cmd) { + case ADMIN_SHOW_SA: + buf = NULL; /*XXX dumpph2(&error);*/ + if (buf == NULL) + com->ac_errno = error; + break; + case ADMIN_FLUSH_SA: + /*XXX flushph2();*/ + com->ac_errno = 0; + break; + } + break; + + default: + /* ignore */ + com->ac_errno = -1; + } + } + break; + + case ADMIN_DELETE_SA: + break; + + case ADMIN_ESTABLISH_SA: + { + struct sockaddr *dst; + struct sockaddr *src; + src = (struct sockaddr *) + &((struct admin_com_indexes *) + ((caddr_t)com + sizeof(*com)))->src; + dst = (struct sockaddr *) + &((struct admin_com_indexes *) + ((caddr_t)com + sizeof(*com)))->dst; + + switch (com->ac_proto) { + case ADMIN_PROTO_ISAKMP: + { + struct remoteconf *rmconf; + struct sockaddr *remote; + struct sockaddr *local; + + /* search appropreate configuration */ + rmconf = getrmconf(dst); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no configuration found " + "for %s\n", saddrwop2str(dst)); + com->ac_errno = -1; + break; + } + + /* get remote IP address and port number. */ + remote = dupsaddr(dst); + if (remote == NULL) { + com->ac_errno = -1; + break; + } + switch (remote->sa_family) { + case AF_INET: + ((struct sockaddr_in *)remote)->sin_port = + ((struct sockaddr_in *)rmconf->remote)->sin_port; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)remote)->sin6_port = + ((struct sockaddr_in6 *)rmconf->remote)->sin6_port; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", + remote->sa_family); + com->ac_errno = -1; + break; + } + + /* get local address */ + local = dupsaddr(src); + if (local == NULL) { + com->ac_errno = -1; + break; + } + switch (local->sa_family) { + case AF_INET: + ((struct sockaddr_in *)local)->sin_port = + getmyaddrsport(local); + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)local)->sin6_port = + getmyaddrsport(local); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", + local->sa_family); + com->ac_errno = -1; + break; + } + + + plog(LLV_INFO, LOCATION, NULL, + "accept a request to establish IKE-SA: " + "%s\n", saddrwop2str(remote)); + + /* begin ident mode */ + if (isakmp_ph1begin_i(rmconf, remote) < 0) { + com->ac_errno = -1; + break; + } + } + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + break; + default: + /* ignore */ + com->ac_errno = -1; + } + } + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid command: %d\n", com->ac_cmd); + com->ac_errno = -1; + } + + if (admin_reply(so2, com, buf) < 0) + goto bad; + + if (buf != NULL) + vfree(buf); + + return 0; + + bad: + if (buf != NULL) + vfree(buf); + return -1; +} + +static int +admin_reply(so, combuf, buf) + int so; + struct admin_com *combuf; + vchar_t *buf; +{ + int tlen; + char *retbuf = NULL; + + if (buf != NULL) + tlen = sizeof(*combuf) + buf->l; + else + tlen = sizeof(*combuf); + + retbuf = racoon_calloc(1, tlen); + if (retbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate admin buffer\n"); + return -1; + } + + memcpy(retbuf, combuf, sizeof(*combuf)); + ((struct admin_com *)retbuf)->ac_len = tlen; + + if (buf != NULL) + memcpy(retbuf + sizeof(*combuf), buf->v, buf->l); + + tlen = send(so, retbuf, tlen, 0); + racoon_free(retbuf); + if (tlen < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to send admin command: %s\n", + strerror(errno)); + return -1; + } + + return 0; +} + +/* ADMIN_PROTO -> SADB_SATYPE */ +int +admin2pfkey_proto(proto) + u_int proto; +{ + switch (proto) { + case ADMIN_PROTO_IPSEC: + return SADB_SATYPE_UNSPEC; + case ADMIN_PROTO_AH: + return SADB_SATYPE_AH; + case ADMIN_PROTO_ESP: + return SADB_SATYPE_ESP; + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported proto for admin: %d\n", proto); + return -1; + } + /*NOTREACHED*/ +} + +int +admin_init() +{ + memset(&sunaddr, 0, sizeof(sunaddr)); + sunaddr.sun_family = AF_UNIX; + snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path), + "%s", PORT_ADMIN); + + lcconf->sock_admin = socket(AF_UNIX, SOCK_STREAM, 0); + if (lcconf->sock_admin < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket: %s\n", strerror(errno)); + return -1; + } + + if (bind(lcconf->sock_admin, (struct sockaddr *)&sunaddr, + sizeof(sunaddr)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "bind(sockname:%s): %s\n", + sunaddr.sun_path, strerror(errno)); + (void)close(lcconf->sock_admin); + return -1; + } + + if (listen(lcconf->sock_admin, 5) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "listen(sockname:%s): %s\n", + sunaddr.sun_path, strerror(errno)); + (void)close(lcconf->sock_admin); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "open %s as racoon management.\n", sunaddr.sun_path); + + return 0; +} + +int +admin_close() +{ + close(lcconf->sock_admin); + unlink(sunaddr.sun_path); + return 0; +} diff --git a/racoon.tproj/admin.h b/racoon.tproj/admin.h new file mode 100644 index 0000000..8cf15ee --- /dev/null +++ b/racoon.tproj/admin.h @@ -0,0 +1,77 @@ +/* $KAME: admin.h,v 1.7 2000/09/13 04:50:23 itojun 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. 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. + */ + +/* command for administration. */ +/* NOTE: host byte order. */ +struct admin_com { + u_int16_t ac_len; /* total packet length including data */ + u_int16_t ac_cmd; + int16_t ac_errno; + u_int16_t ac_proto; +}; + +/* + * No data follows as the data. + * These don't use proto field. + */ +#define ADMIN_RELOAD_CONF 0x0001 +#define ADMIN_SHOW_SCHED 0x0002 + +/* + * No data follows as the data. + * These use proto field. + */ +#define ADMIN_SHOW_SA 0x0101 +#define ADMIN_FLUSH_SA 0x0102 + +/* + * The admin_com_indexes follows, see below. + */ +#define ADMIN_DELETE_SA 0x0201 +#define ADMIN_ESTABLISH_SA 0x0202 + +/* the value of proto */ +#define ADMIN_PROTO_ISAKMP 0x01ff +#define ADMIN_PROTO_IPSEC 0x02ff +#define ADMIN_PROTO_AH 0x0201 +#define ADMIN_PROTO_ESP 0x0202 +#define ADMIN_PROTO_INTERNAL 0x0301 + +struct admin_com_indexes { + u_int8_t prefs; + u_int8_t prefd; + u_int8_t ul_proto; + u_int8_t reserved; + struct sockaddr_storage src; + struct sockaddr_storage dst; +}; + +extern int admin2pfkey_proto __P((u_int)); diff --git a/racoon.tproj/admin_var.h b/racoon.tproj/admin_var.h new file mode 100644 index 0000000..ff3aea4 --- /dev/null +++ b/racoon.tproj/admin_var.h @@ -0,0 +1,36 @@ +/* $KAME: admin_var.h,v 1.3 2000/10/04 17:40:58 itojun 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. 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. + */ + +#define PORT_ADMIN "/tmp/.racoon" + +extern int admin_handler __P((void)); +extern int admin_init __P((void)); +extern int admin_close __P((void)); diff --git a/racoon.tproj/algorithm.c b/racoon.tproj/algorithm.c new file mode 100644 index 0000000..90e0824 --- /dev/null +++ b/racoon.tproj/algorithm.c @@ -0,0 +1,846 @@ +/* $KAME: algorithm.c,v 1.21 2001/10/05 02:42:55 sakane 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. 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. + */ + +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "crypto_openssl.h" +#include "dhgroup.h" +#include "algorithm.h" +#include "oakley.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "gcmalloc.h" + +static struct hash_algorithm oakley_hashdef[] = { +{ "md5", algtype_md5, OAKLEY_ATTR_HASH_ALG_MD5, + eay_md5_init, eay_md5_update, + eay_md5_final, eay_md5_hashlen, + eay_md5_one, }, +{ "sha1", algtype_sha1, OAKLEY_ATTR_HASH_ALG_SHA, + eay_sha1_init, eay_sha1_update, + eay_sha1_final, eay_sha1_hashlen, + eay_sha1_one, }, +{ "sha2_256", algtype_sha2_256, OAKLEY_ATTR_HASH_ALG_SHA2_256, + eay_sha2_256_init, eay_sha2_256_update, + eay_sha2_256_final, eay_sha2_256_hashlen, + eay_sha1_one, }, +{ "sha2_384", algtype_sha2_384, OAKLEY_ATTR_HASH_ALG_SHA2_384, + eay_sha2_384_init, eay_sha2_384_update, + eay_sha2_384_final, eay_sha2_384_hashlen, + eay_sha1_one, }, +{ "sha2_512", algtype_sha2_512, OAKLEY_ATTR_HASH_ALG_SHA2_512, + eay_sha2_512_init, eay_sha2_512_update, + eay_sha2_512_final, eay_sha2_512_hashlen, + eay_sha1_one, }, +}; + +static struct hmac_algorithm oakley_hmacdef[] = { +{ "hmac_md5", algtype_md5, OAKLEY_ATTR_HASH_ALG_MD5, + eay_hmacmd5_init, eay_hmacmd5_update, + eay_hmacmd5_final, NULL, + eay_hmacmd5_one, }, +{ "hmac_sha1", algtype_sha1, OAKLEY_ATTR_HASH_ALG_SHA, + eay_hmacsha1_init, eay_hmacsha1_update, + eay_hmacsha1_final, NULL, + eay_hmacsha1_one, }, +{ "hmac_sha2_256", algtype_sha2_256, OAKLEY_ATTR_HASH_ALG_SHA2_256, + eay_hmacsha2_256_init, eay_hmacsha2_256_update, + eay_hmacsha2_256_final, NULL, + eay_hmacsha2_256_one, }, +{ "hmac_sha2_384", algtype_sha2_384, OAKLEY_ATTR_HASH_ALG_SHA2_384, + eay_hmacsha2_384_init, eay_hmacsha2_384_update, + eay_hmacsha2_384_final, NULL, + eay_hmacsha2_384_one, }, +{ "hmac_sha2_512", algtype_sha2_512, OAKLEY_ATTR_HASH_ALG_SHA2_512, + eay_hmacsha2_512_init, eay_hmacsha2_512_update, + eay_hmacsha2_512_final, NULL, + eay_hmacsha2_512_one, }, +}; + +static struct enc_algorithm oakley_encdef[] = { +{ "des", algtype_des, OAKLEY_ATTR_ENC_ALG_DES, 8, + eay_des_encrypt, eay_des_decrypt, + eay_des_weakkey, eay_des_keylen, }, +#ifdef HAVE_OPENSSL_IDEA_H +{ "idea", algtype_idea, OAKLEY_ATTR_ENC_ALG_IDEA, 8, + eay_idea_encrypt, eay_idea_decrypt, + eay_idea_weakkey, eay_idea_keylen, }, +#endif +{ "blowfish", algtype_blowfish, OAKLEY_ATTR_ENC_ALG_BLOWFISH, 8, + eay_bf_encrypt, eay_bf_decrypt, + eay_bf_weakkey, eay_bf_keylen, }, +#ifdef HAVE_OPENSSL_RC5_H +{ "rc5", algtype_rc5, OAKLEY_ATTR_ENC_ALG_RC5, 8, + eay_rc5_encrypt, eay_rc5_decrypt, + eay_rc5_weakkey, eay_rc5_keylen, }, +#endif +{ "3des", algtype_3des, OAKLEY_ATTR_ENC_ALG_3DES, 8, + eay_3des_encrypt, eay_3des_decrypt, + eay_3des_weakkey, eay_3des_keylen, }, +{ "cast", algtype_cast128, OAKLEY_ATTR_ENC_ALG_CAST, 8, + eay_cast_encrypt, eay_cast_decrypt, + eay_cast_weakkey, eay_cast_keylen, }, +{ "aes", algtype_rijndael, OAKLEY_ATTR_ENC_ALG_AES, 16, + eay_aes_encrypt, eay_aes_decrypt, + eay_aes_weakkey, eay_aes_keylen, }, +}; + +static struct enc_algorithm ipsec_encdef[] = { +{ "des-iv64", algtype_des_iv64, IPSECDOI_ESP_DES_IV64, 8, + NULL, NULL, + NULL, eay_des_keylen, }, +{ "des", algtype_des, IPSECDOI_ESP_DES, 8, + NULL, NULL, + NULL, eay_des_keylen, }, +{ "3des", algtype_3des, IPSECDOI_ESP_3DES, 8, + NULL, NULL, + NULL, eay_3des_keylen, }, +#ifdef HAVE_OPENSSL_RC5_H +{ "rc5", algtype_rc5, IPSECDOI_ESP_RC5, 8, + NULL, NULL, + NULL, eay_rc5_keylen, }, +#endif +{ "cast", algtype_cast128, IPSECDOI_ESP_CAST, 8, + NULL, NULL, + NULL, eay_cast_keylen, }, +{ "blowfish", algtype_blowfish, IPSECDOI_ESP_BLOWFISH, 8, + NULL, NULL, + NULL, eay_bf_keylen, }, +{ "des-iv32", algtype_des_iv32, IPSECDOI_ESP_DES_IV32, 8, + NULL, NULL, + NULL, eay_des_keylen, }, +{ "null", algtype_null_enc, IPSECDOI_ESP_NULL, 8, + NULL, NULL, + NULL, eay_3des_keylen, }, +{ "rijndael", algtype_rijndael, IPSECDOI_ESP_RIJNDAEL, 16, + NULL, NULL, + NULL, eay_aes_keylen, }, +{ "twofish", algtype_twofish, IPSECDOI_ESP_TWOFISH, 16, + NULL, NULL, + NULL, eay_twofish_keylen, }, +#ifdef HAVE_OPENSSL_IDEA_H +{ "3idea", algtype_3idea, IPSECDOI_ESP_3IDEA, 8, + NULL, NULL, + NULL, NULL, }, +{ "idea", algtype_idea, IPSECDOI_ESP_IDEA, 8, + NULL, NULL, + NULL, NULL, }, +#endif +{ "rc4", algtype_rc4, IPSECDOI_ESP_RC4, 8, + NULL, NULL, + NULL, NULL, }, +}; + +static struct hmac_algorithm ipsec_hmacdef[] = { +{ "md5", algtype_hmac_md5, IPSECDOI_ATTR_AUTH_HMAC_MD5, + NULL, NULL, + NULL, eay_md5_hashlen, + NULL, }, +{ "sha1", algtype_hmac_sha1, IPSECDOI_ATTR_AUTH_HMAC_SHA1, + NULL, NULL, + NULL, eay_sha1_hashlen, + NULL, }, +{ "kpdk", algtype_kpdk, IPSECDOI_ATTR_AUTH_KPDK, + NULL, NULL, + NULL, eay_kpdk_hashlen, + NULL, }, +{ "null", algtype_non_auth, IPSECDOI_ATTR_AUTH_NONE, + NULL, NULL, + NULL, eay_null_hashlen, + NULL, }, +{ "hmac_sha2_256", algtype_hmac_sha2_256, IPSECDOI_ATTR_SHA2_256, + NULL, NULL, + NULL, eay_sha2_256_hashlen, + NULL, }, +{ "hmac_sha2_384", algtype_hmac_sha2_384, IPSECDOI_ATTR_SHA2_384, + NULL, NULL, + NULL, eay_sha2_384_hashlen, + NULL, }, +{ "hmac_sha2_512", algtype_hmac_sha2_512, IPSECDOI_ATTR_SHA2_512, + NULL, NULL, + NULL, eay_sha2_512_hashlen, + NULL, }, +}; + +static struct misc_algorithm ipsec_compdef[] = { +{ "oui", algtype_oui, IPSECDOI_IPCOMP_OUI, }, +{ "deflate", algtype_deflate, IPSECDOI_IPCOMP_DEFLATE, }, +{ "lzs", algtype_lzs, IPSECDOI_IPCOMP_LZS, }, +}; + +static struct misc_algorithm oakley_authdef[] = { +{ "psk", algtype_psk, OAKLEY_ATTR_AUTH_METHOD_PSKEY, }, +{ "dsssig", algtype_dsssig, OAKLEY_ATTR_AUTH_METHOD_DSSSIG, }, +{ "rsasig", algtype_rsasig, OAKLEY_ATTR_AUTH_METHOD_RSASIG, }, +{ "rsaenc", algtype_rsaenc, OAKLEY_ATTR_AUTH_METHOD_RSAENC, }, +{ "rsarev", algtype_rsarev, OAKLEY_ATTR_AUTH_METHOD_RSAREV, }, +{ "gssapi_krb", algtype_gssapikrb, OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB, }, +}; + +static struct dh_algorithm oakley_dhdef[] = { +{ "modp768", algtype_modp768, OAKLEY_ATTR_GRP_DESC_MODP768, + &dh_modp768, }, +{ "modp1024", algtype_modp1024, OAKLEY_ATTR_GRP_DESC_MODP1024, + &dh_modp1024, }, +{ "modp1536", algtype_modp1536, OAKLEY_ATTR_GRP_DESC_MODP1536, + &dh_modp1536, }, +{ "modp2048", algtype_modp2048, OAKLEY_ATTR_GRP_DESC_MODP2048, + &dh_modp2048, }, +{ "modp3072", algtype_modp3072, OAKLEY_ATTR_GRP_DESC_MODP3072, + &dh_modp3072, }, +{ "modp4096", algtype_modp4096, OAKLEY_ATTR_GRP_DESC_MODP4096, + &dh_modp4096, }, +{ "modp6144", algtype_modp6144, OAKLEY_ATTR_GRP_DESC_MODP6144, + &dh_modp6144, }, +{ "modp8192", algtype_modp8192, OAKLEY_ATTR_GRP_DESC_MODP8192, + &dh_modp8192, }, +}; + +static struct hash_algorithm *alg_oakley_hashdef __P((int)); +static struct hmac_algorithm *alg_oakley_hmacdef __P((int)); +static struct enc_algorithm *alg_oakley_encdef __P((int)); +static struct enc_algorithm *alg_ipsec_encdef __P((int)); +static struct hmac_algorithm *alg_ipsec_hmacdef __P((int)); +static struct dh_algorithm *alg_oakley_dhdef __P((int)); + +/* oakley hash algorithm */ +static struct hash_algorithm * +alg_oakley_hashdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_hashdef); i++) + if (doi == oakley_hashdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hash(%s)\n", + oakley_hashdef[i].name); + return &oakley_hashdef[i]; + } + return NULL; +} + +int +alg_oakley_hashdef_ok(doi) + int doi; +{ + struct hash_algorithm *f; + + f = alg_oakley_hashdef(doi); + if (f == NULL) + return 0; + + return 1; +} + +int +alg_oakley_hashdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_hashdef); i++) + if (type == oakley_hashdef[i].type) { + res = oakley_hashdef[i].doi; + break; + } + return res; +} + +int +alg_oakley_hashdef_hashlen(doi) + int doi; +{ + struct hash_algorithm *f; + + f = alg_oakley_hashdef(doi); + if (f == NULL || f->hashlen == NULL) + return NULL; + + return (f->hashlen)(); +} + +vchar_t * +alg_oakley_hashdef_one(doi, buf) + int doi; + vchar_t *buf; +{ + struct hash_algorithm *f; + + f = alg_oakley_hashdef(doi); + if (f == NULL || f->hashlen == NULL) + return NULL; + + return (f->one)(buf); +} + +/* oakley hmac algorithm */ +static struct hmac_algorithm * +alg_oakley_hmacdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++) + if (doi == oakley_hmacdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n", + oakley_hmacdef[i].name); + return &oakley_hmacdef[i]; + } + return NULL; +} + +int +alg_oakley_hmacdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_hmacdef); i++) + if (type == oakley_hmacdef[i].type) { + res = oakley_hmacdef[i].doi; + break; + } + return res; +} + +vchar_t * +alg_oakley_hmacdef_one(doi, key, buf) + int doi; + vchar_t *key, *buf; +{ + struct hmac_algorithm *f; + vchar_t *res; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + f = alg_oakley_hmacdef(doi); + if (f == NULL || f->one == NULL) + return NULL; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + res = (f->one)(key, buf); + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s size=%d): %8.6f", __FUNCTION__, + f->name, buf->l, timedelta(&start, &end)); +#endif + + return res; +} + +/* oakley encryption algorithm */ +static struct enc_algorithm * +alg_oakley_encdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_encdef); i++) + if (doi == oakley_encdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "encription(%s)\n", + oakley_encdef[i].name); + return &oakley_encdef[i]; + } + return NULL; +} + +int +alg_oakley_encdef_ok(doi) + int doi; +{ + struct enc_algorithm *f; + + f = alg_oakley_encdef(doi); + if (f == NULL) + return 0; + + return 1; +} + +int +alg_oakley_encdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_encdef); i++) + if (type == oakley_encdef[i].type) { + res = oakley_encdef[i].doi; + break; + } + return res; +} + +int +alg_oakley_encdef_keylen(doi, len) + int doi, len; +{ + struct enc_algorithm *f; + + f = alg_oakley_encdef(doi); + if (f == NULL || f->keylen == NULL) + return -1; + + return (f->keylen)(len); +} + +int +alg_oakley_encdef_blocklen(doi) + int doi; +{ + struct enc_algorithm *f; + + f = alg_oakley_encdef(doi); + if (f == NULL) + return -1; + + return f->blocklen; +} + +vchar_t * +alg_oakley_encdef_decrypt(doi, buf, key, iv) + int doi; + vchar_t *buf, *key, *iv; +{ + vchar_t *res; + struct enc_algorithm *f; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + f = alg_oakley_encdef(doi); + if (f == NULL || f->decrypt == NULL) + return NULL; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + res = (f->decrypt)(buf, key, iv); + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s klen=%d size=%d): %8.6f", __FUNCTION__, + f->name, key->l << 3, buf->l, timedelta(&start, &end)); +#endif + return res; +} + +vchar_t * +alg_oakley_encdef_encrypt(doi, buf, key, iv) + int doi; + vchar_t *buf, *key, *iv; +{ + vchar_t *res; + struct enc_algorithm *f; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + f = alg_oakley_encdef(doi); + if (f == NULL || f->encrypt == NULL) + return NULL; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + res = (f->encrypt)(buf, key, iv); + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s klen=%d size=%d): %8.6f", __FUNCTION__, + f->name, key->l << 3, buf->l, timedelta(&start, &end)); +#endif + return res; +} + +/* ipsec encryption algorithm */ +static struct enc_algorithm * +alg_ipsec_encdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(ipsec_encdef); i++) + if (doi == ipsec_encdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "encription(%s)\n", + ipsec_encdef[i].name); + return &ipsec_encdef[i]; + } + return NULL; +} + +int +alg_ipsec_encdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(ipsec_encdef); i++) + if (type == ipsec_encdef[i].type) { + res = ipsec_encdef[i].doi; + break; + } + return res; +} + +int +alg_ipsec_encdef_keylen(doi, len) + int doi, len; +{ + struct enc_algorithm *f; + + f = alg_ipsec_encdef(doi); + if (f == NULL || f->keylen == NULL) + return -1; + + return (f->keylen)(len); +} + +/* ipsec hmac algorithm */ +static struct hmac_algorithm * +alg_ipsec_hmacdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++) + if (doi == ipsec_hmacdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n", + oakley_hmacdef[i].name); + return &ipsec_hmacdef[i]; + } + return NULL; +} + +int +alg_ipsec_hmacdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(ipsec_hmacdef); i++) + if (type == ipsec_hmacdef[i].type) { + res = ipsec_hmacdef[i].doi; + break; + } + return res; +} + +int +alg_ipsec_hmacdef_hashlen(doi) + int doi; +{ + struct hmac_algorithm *f; + + f = alg_ipsec_hmacdef(doi); + if (f == NULL || f->hashlen == NULL) + return -1; + + return (f->hashlen)(); +} + +/* ip compression */ +int +alg_ipsec_compdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(ipsec_compdef); i++) + if (type == ipsec_compdef[i].type) { + res = ipsec_compdef[i].doi; + break; + } + return res; +} + +/* dh algorithm */ +static struct dh_algorithm * +alg_oakley_dhdef(doi) + int doi; +{ + int i; + + for (i = 0; i < ARRAYLEN(oakley_dhdef); i++) + if (doi == oakley_dhdef[i].doi) { + plog(LLV_DEBUG, LOCATION, NULL, "hmac(%s)\n", + oakley_dhdef[i].name); + return &oakley_dhdef[i]; + } + return NULL; +} + +int +alg_oakley_dhdef_ok(doi) + int doi; +{ + struct dh_algorithm *f; + + f = alg_oakley_dhdef(doi); + if (f == NULL) + return 0; + + return 1; +} + +int +alg_oakley_dhdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_dhdef); i++) + if (type == oakley_dhdef[i].type) { + res = oakley_dhdef[i].doi; + break; + } + return res; +} + +struct dhgroup * +alg_oakley_dhdef_group(doi) + int doi; +{ + struct dh_algorithm *f; + + f = alg_oakley_dhdef(doi); + if (f == NULL || f->dhgroup == NULL) + return NULL; + + return f->dhgroup; +} + +/* authentication method */ +int +alg_oakley_authdef_doi(type) + int type; +{ + int i, res = -1; + + for (i = 0; i < ARRAYLEN(oakley_authdef); i++) + if (type == oakley_authdef[i].type) { + res = oakley_authdef[i].doi; + break; + } + return res; +} + +/* + * give the default key length + * OUT: -1: NG + * 0: fixed key cipher, key length not allowed + * positive: default key length + */ +int +default_keylen(class, type) + int class, type; +{ + + switch (class) { + case algclass_isakmp_enc: + case algclass_ipsec_enc: + break; + default: + return 0; + } + + switch (type) { + case algtype_blowfish: + case algtype_rc5: + case algtype_cast128: + case algtype_rijndael: + case algtype_twofish: + return 128; + default: + return 0; + } +} + +/* + * check key length + * OUT: -1: NG + * 0: OK + */ +int +check_keylen(class, type, len) + int class, type, len; +{ + int badrange; + + switch (class) { + case algclass_isakmp_enc: + case algclass_ipsec_enc: + break; + default: + /* unknown class, punt */ + plog(LLV_ERROR, LOCATION, NULL, + "unknown algclass %d\n", class); + return -1; + } + + /* key length must be multiple of 8 bytes - RFC2451 2.2 */ + switch (type) { + case algtype_blowfish: + case algtype_rc5: + case algtype_cast128: + case algtype_rijndael: + case algtype_twofish: + if (len % 8 != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "key length %d is not multiple of 8\n", len); + return -1; + } + break; + } + + /* key length range */ + badrange = 0; + switch (type) { + case algtype_blowfish: + if (len < 40 || 448 < len) + badrange++; + break; + case algtype_rc5: + if (len < 40 || 2040 < len) + badrange++; + break; + case algtype_cast128: + if (len < 40 || 128 < len) + badrange++; + break; + case algtype_rijndael: + if (!(len == 128 || len == 192 || len == 256)) + badrange++; + break; + case algtype_twofish: + if (len < 40 || 256 < len) + badrange++; + break; + default: + if (len) { + plog(LLV_ERROR, LOCATION, NULL, + "key length is not allowed"); + return -1; + } + break; + } + if (badrange) { + plog(LLV_ERROR, LOCATION, NULL, + "key length out of range\n"); + return -1; + } + + return 0; +} + +/* + * convert algorithm type to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +algtype2doi(class, type) + int class, type; +{ + int res = -1; + + switch (class) { + case algclass_ipsec_enc: + res = alg_ipsec_encdef_doi(type); + break; + case algclass_ipsec_auth: + res = alg_ipsec_hmacdef_doi(type); + break; + case algclass_ipsec_comp: + res = alg_ipsec_compdef_doi(type); + break; + case algclass_isakmp_enc: + res = alg_oakley_encdef_doi(type); + break; + case algclass_isakmp_hash: + res = alg_oakley_hashdef_doi(type); + break; + case algclass_isakmp_dh: + res = alg_oakley_dhdef_doi(type); + break; + case algclass_isakmp_ameth: + res = alg_oakley_authdef_doi(type); + break; + } + return res; +} + +/* + * convert algorithm class to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +algclass2doi(class) + int class; +{ + switch (class) { + case algclass_ipsec_enc: + return IPSECDOI_PROTO_IPSEC_ESP; + case algclass_ipsec_auth: + return IPSECDOI_ATTR_AUTH; + case algclass_ipsec_comp: + return IPSECDOI_PROTO_IPCOMP; + case algclass_isakmp_enc: + return OAKLEY_ATTR_ENC_ALG; + case algclass_isakmp_hash: + return OAKLEY_ATTR_HASH_ALG; + case algclass_isakmp_dh: + return OAKLEY_ATTR_GRP_DESC; + case algclass_isakmp_ameth: + return OAKLEY_ATTR_AUTH_METHOD; + default: + return -1; + } + /*NOTREACHED*/ + return -1; +} diff --git a/racoon.tproj/algorithm.h b/racoon.tproj/algorithm.h new file mode 100644 index 0000000..91a8734 --- /dev/null +++ b/racoon.tproj/algorithm.h @@ -0,0 +1,191 @@ +/* $KAME: algorithm.h,v 1.19 2001/08/16 06:17:12 sakane 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. 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. + */ + +/* algorithm class */ +enum { + algclass_ipsec_enc, + algclass_ipsec_auth, + algclass_ipsec_comp, + algclass_isakmp_enc, + algclass_isakmp_hash, + algclass_isakmp_dh, + algclass_isakmp_ameth, /* authentication method. */ +#define MAXALGCLASS 7 +}; + +#define ALG_DEFAULT_KEYLEN 64 + +#define ALGTYPE_NOTHING 0 + +/* algorithm type */ +enum { + algtype_nothing = 0, + + /* enc */ + algtype_des_iv64, + algtype_des, + algtype_3des, + algtype_rc5, + algtype_idea, + algtype_cast128, + algtype_blowfish, + algtype_3idea, + algtype_des_iv32, + algtype_rc4, + algtype_null_enc, + algtype_rijndael, + algtype_twofish, + + /* ipsec auth */ + algtype_hmac_md5, + algtype_hmac_sha1, + algtype_des_mac, + algtype_kpdk, + algtype_non_auth, + algtype_hmac_sha2_256, + algtype_hmac_sha2_384, + algtype_hmac_sha2_512, + + /* ipcomp */ + algtype_oui, + algtype_deflate, + algtype_lzs, + + /* hash */ + algtype_md5, + algtype_sha1, + algtype_tiger, + algtype_sha2_256, + algtype_sha2_384, + algtype_sha2_512, + + /* dh_group */ + algtype_modp768, + algtype_modp1024, + algtype_ec2n155, + algtype_ec2n185, + algtype_modp1536, + algtype_modp2048, + algtype_modp3072, + algtype_modp4096, + algtype_modp6144, + algtype_modp8192, + + /* authentication method. */ + algtype_psk, + algtype_dsssig, + algtype_rsasig, + algtype_rsaenc, + algtype_rsarev, + algtype_gssapikrb +}; + +struct hmac_algorithm { + char *name; + int type; + int doi; + caddr_t (*init) __P((vchar_t *)); + void (*update) __P((caddr_t, vchar_t *)); + vchar_t *(*final) __P((caddr_t)); + int (*hashlen) __P((void)); + vchar_t *(*one) __P((vchar_t *, vchar_t *)); +}; + +struct hash_algorithm { + char *name; + int type; + int doi; + caddr_t (*init) __P((void)); + void (*update) __P((caddr_t, vchar_t *)); + vchar_t *(*final) __P((caddr_t)); + int (*hashlen) __P((void)); + vchar_t *(*one) __P((vchar_t *)); +}; + +struct enc_algorithm { + char *name; + int type; + int doi; + int blocklen; + vchar_t *(*encrypt) __P((vchar_t *, vchar_t *, vchar_t *)); + vchar_t *(*decrypt) __P((vchar_t *, vchar_t *, vchar_t *)); + int (*weakkey) __P((vchar_t *)); + int (*keylen) __P((int)); +}; + +/* dh group */ +struct dh_algorithm { + char *name; + int type; + int doi; + struct dhgroup *dhgroup; +}; + +/* ipcomp, auth meth, dh group */ +struct misc_algorithm { + char *name; + int type; + int doi; +}; + +extern int alg_oakley_hashdef_ok __P((int)); +extern int alg_oakley_hashdef_doi __P((int)); +extern int alg_oakley_hashdef_hashlen __P((int)); +extern vchar_t *alg_oakley_hashdef_one __P((int, vchar_t *)); + +extern int alg_oakley_hmacdef_doi __P((int)); +extern vchar_t *alg_oakley_hmacdef_one __P((int, vchar_t *, vchar_t *)); + +extern int alg_oakley_encdef_ok __P((int)); +extern int alg_oakley_encdef_doi __P((int)); +extern int alg_oakley_encdef_keylen __P((int, int)); +extern int alg_oakley_encdef_blocklen __P((int)); +extern vchar_t *alg_oakley_encdef_decrypt __P((int, vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *alg_oakley_encdef_encrypt __P((int, vchar_t *, vchar_t *, vchar_t *)); + +extern int alg_ipsec_encdef_doi __P((int)); +extern int alg_ipsec_encdef_keylen __P((int, int)); + +extern int alg_ipsec_hmacdef_doi __P((int)); +extern int alg_ipsec_hmacdef_hashlen __P((int)); + +extern int alg_ipsec_compdef_doi __P((int)); + +extern int alg_oakley_dhdef_doi __P((int)); +extern int alg_oakley_dhdef_ok __P((int)); +extern struct dhgroup *alg_oakley_dhdef_group __P((int)); + +extern int alg_oakley_authdef_doi __P((int)); + +extern int default_keylen __P((int, int)); +extern int check_keylen __P((int, int, int)); +extern int algtype2doi __P((int, int)); +extern int algclass2doi __P((int)); diff --git a/racoon.tproj/backupsa.c b/racoon.tproj/backupsa.c new file mode 100644 index 0000000..96a4ff6 --- /dev/null +++ b/racoon.tproj/backupsa.c @@ -0,0 +1,485 @@ +/* $KAME: backupsa.c,v 1.15 2001/11/16 04:08:10 sakane 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. 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. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#ifdef IPV6_INRIA_VERSION +#include +#else +#include +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "str2val.h" +#include "plog.h" +#include "debug.h" + +#include "localconf.h" +#include "sockmisc.h" +#include "safefile.h" +#include "backupsa.h" +#include "libpfkey.h" + +/* + * (time string)%(sa parameter) + * (time string) := ex. Nov 24 18:22:48 1986 + * (sa parameter) := + * src dst satype spi mode reqid wsize \ + * e_type e_keylen a_type a_keylen flags \ + * l_alloc l_bytes l_addtime l_usetime seq keymat + */ +static char *format = "%b %d %T %Y"; /* time format */ +static char *strmon[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static char *str2tmx __P((char *, struct tm *)); +static int str2num __P((char *, int)); + +/* + * output the sa parameter. + */ +int +backupsa_to_file(satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + char buf[1024]; + struct tm *tm; + time_t t; + char *p, *k; + int len, l, i; + FILE *fp; + + p = buf; + len = sizeof(buf); + + t = time(NULL); + tm = localtime(&t); + l = strftime(p, len, format, tm); + p += l; + len -= l; + if (len < 0) + goto err; + + l = snprintf(p, len, "%%"); + if (l < 0 || l >= len) + goto err; + p += l; + len -= l; + if (len < 0) + goto err; + + i = getnameinfo(src, src->sa_len, p, len, NULL, 0, NIFLAGS); + if (i != 0) + goto err; + l = strlen(p); + p += l; + len -= l; + if (len < 0) + goto err; + + l = snprintf(p, len, " "); + if (l < 0 || l >= len) + goto err; + p += l; + len -= l; + if (len < 0) + goto err; + + i = getnameinfo(dst, dst->sa_len, p, len, NULL, 0, NIFLAGS); + if (i != 0) + goto err; + l = strlen(p); + p += l; + len -= l; + if (len < 0) + goto err; + + l = snprintf(p, len, + " %u %lu %u %u %u " + "%u %u %u %u %u " + "%u %llu %llu %llu %u", + satype, (unsigned long)ntohl(spi), mode, reqid, wsize, + e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, (unsigned long long)l_bytes, + (unsigned long long)l_addtime, (unsigned long long)l_usetime, + seq); + if (l < 0 || l >= len) + goto err; + p += l; + len -= l; + if (len < 0) + goto err; + + k = val2str(keymat, e_keylen + a_keylen); + l = snprintf(p, len, " %s", k); + if (l < 0 || l >= len) + goto err; + racoon_free(k); + p += l; + len -= l; + if (len < 0) + goto err; + + /* open the file and write the SA parameter */ + if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) != 0 || + (fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "a")) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to open the backup file %s.\n", + lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); + return -1; + } + fprintf(fp, "%s\n", buf); + fclose(fp); + + return 0; + +err: + plog(LLV_ERROR, LOCATION, NULL, + "SA cannot be saved to a file.\n"); + return -1; +} + +int +backupsa_from_file() +{ + FILE *fp; + char buf[512]; + struct tm tm; + time_t created, current; + char *p, *q; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + size_t keymatlen; + u_int wsize, e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; + int line; + + if (safefile(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], 1) == 0) + fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "r"); + else + fp = NULL; + if (fp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to open the backup file %s.\n", + lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); + return -1; + } + + current = time(NULL); + + for(line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) { + /* comment line */ + if (buf[0] == '#') + continue; + + memset(&tm, 0, sizeof(tm)); + p = str2tmx(buf, &tm); + if (*p != '%') { + err: + plog(LLV_ERROR, LOCATION, NULL, + "illegal format line#%d in %s: %s\n", + line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf); + continue; + } + created = mktime(&tm); + p++; + + for (q = p; *q != '\0' && !isspace(*q); q++) + ; + *q = '\0'; + src = str2saddr(p, NULL); + if (src == NULL) + goto err; + p = q + 1; + + for (q = p; *q != '\0' && !isspace(*q); q++) + ; + *q = '\0'; + dst = str2saddr(p, NULL); + if (dst == NULL) { + racoon_free(src); + goto err; + } + p = q + 1; + +#define GETNEXTNUM(value, function) \ +do { \ + char *y; \ + for (q = p; *q != '\0' && !isspace(*q); q++) \ + ; \ + *q = '\0'; \ + (value) = function(p, &y, 10); \ + if ((value) == 0 && *y != '\0') \ + goto err; \ + p = q + 1; \ +} while (0); + + GETNEXTNUM(satype, strtoul); + GETNEXTNUM(spi, strtoul); + spi = ntohl(spi); + GETNEXTNUM(mode, strtoul); + GETNEXTNUM(reqid, strtoul); + GETNEXTNUM(wsize, strtoul); + GETNEXTNUM(e_type, strtoul); + GETNEXTNUM(e_keylen, strtoul); + GETNEXTNUM(a_type, strtoul); + GETNEXTNUM(a_keylen, strtoul); + GETNEXTNUM(flags, strtoul); + GETNEXTNUM(l_alloc, strtoul); + GETNEXTNUM(l_bytes, strtouq); + GETNEXTNUM(l_addtime, strtouq); + GETNEXTNUM(l_usetime, strtouq); + GETNEXTNUM(seq, strtoul); + +#undef GETNEXTNUM + + keymat = str2val(p, 16, &keymatlen); + if (keymat == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "illegal format(keymat) line#%d in %s: %s\n", + line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], buf); + racoon_free(src); + racoon_free(dst); + continue; + } + + if (created + l_addtime < current) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore this line#%d in %s due to expiration\n", + line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); + racoon_free(src); + racoon_free(dst); + racoon_free(keymat); + continue; + } + l_addtime -= current - created; + + if (pfkey_send_add( + lcconf->sock_pfkey, + satype, + mode, + src, + dst, + spi, + reqid, + wsize, + keymat, + e_type, e_keylen, a_type, a_keylen, flags, + 0, l_bytes, l_addtime, 0, seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "restore SA filed line#%d in %s: %s\n", + line, lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], ipsec_strerror()); + } + racoon_free(src); + racoon_free(dst); + racoon_free(keymat); + } + + fclose(fp); + + /* + * There is a possibility that an abnormal system down will happen + * again before new negotiation will be started. so racoon clears + * the backup file here. it's ok that old SAs are remained in the + * file. any old SA will not be installed because racoon checks the + * lifetime and compare with current time. + */ + + return 0; +} + +int +backupsa_clean() +{ + FILE *fp; + + /* simply return if the file is not defined. */ + if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) + return 0; + + fp = fopen(lcconf->pathinfo[LC_PATHTYPE_BACKUPSA], "w+"); + if (fp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to clean the backup file %s.\n", + lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]); + return -1; + } + fclose(fp); + return 0; +} + +/* + * convert fixed string into the tm structure. + * The fixed string is like 'Nov 24 18:22:48 1986'. + * static char *format = "%b %d %T %Y"; + */ +static char * +str2tmx(char *p, struct tm *tm) +{ + int i, len; + + /* Month */ + for (i = 0; i < sizeof(strmon)/sizeof(strmon[0]); i++) { + if (strncasecmp(p, strmon[i], strlen(strmon[i])) == 0) { + tm->tm_mon = i; + break; + } + } + if (i == sizeof(strmon)/sizeof(strmon[0])) + return 0; + p += strlen(strmon[i]); + if (*p++ != ' ') + return 0; + + /* Day */ + len = 2; + tm->tm_mday = str2num(p, len); + if (tm->tm_mday == -1 || tm->tm_mday > 31) + return 0; + p += len; + if (*p++ != ' ') + return 0; + + /* Hour */ + len = 2; + tm->tm_hour = str2num(p, len); + if (tm->tm_hour == -1 || tm->tm_hour > 24) + return 0; + p += len; + if (*p++ != ':') + return 0; + + /* Min */ + len = 2; + tm->tm_min = str2num(p, len); + if (tm->tm_min == -1 || tm->tm_min > 60) + return 0; + p += len; + if (*p++ != ':') + return 0; + + /* Sec */ + len = 2; + tm->tm_sec = str2num(p, len); + if (tm->tm_sec == -1 || tm->tm_sec > 60) + return 0; + p += len; + if (*p++ != ' ') + return 0; + + /* Year */ + len = 4; + tm->tm_year = str2num(p, len); + if (tm->tm_year == -1 || tm->tm_year < 1900) + return 0; + tm->tm_year -= 1900; + p += len; + + return p; +} + +static int +str2num(p, len) + char *p; + int len; +{ + int res, i; + + res = 0; + for (i = len; i > 0; i--) { + if (!isdigit(*p)) + return -1; + res *= 10; + res += *p - '0'; + p++; + } + + return res; +} + +#ifdef TEST +#include +int +main() +{ + struct tm tm; + time_t t; + char *buf = "Nov 24 18:22:48 1986 "; + char *p; + + memset(&tm, 0, sizeof(tm)); + p = str2tmx(buf, &tm); + printf("[%x]\n", *p); + t = mktime(&tm); + if (t == -1) + printf("mktime failed."); + p = ctime(&t); + printf("[%s]\n", p); + + exit(0); +} +#endif diff --git a/racoon.tproj/backupsa.h b/racoon.tproj/backupsa.h new file mode 100644 index 0000000..42b1fe7 --- /dev/null +++ b/racoon.tproj/backupsa.h @@ -0,0 +1,37 @@ +/* $KAME: backupsa.h,v 1.1 2001/01/31 05:32:55 sakane 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. 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. + */ + +extern int backupsa_to_file __P((u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, + u_int32_t, u_int64_t, u_int64_t, u_int64_t, u_int32_t)); +extern int backupsa_from_file __P((void)); +extern int backupsa_clean __P((void)); diff --git a/racoon.tproj/boxes-fst.dat b/racoon.tproj/boxes-fst.dat new file mode 100644 index 0000000..50e6cb3 --- /dev/null +++ b/racoon.tproj/boxes-fst.dat @@ -0,0 +1,957 @@ +/* $KAME: boxes-fst.dat,v 1.6 2001/05/27 00:23:22 itojun Exp $ */ + +const word8 S[256] = { + 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, +202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, +183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, +208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, +205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, +224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, +231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, +186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, +112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, +225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, +140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 +}; + +#ifdef INTERMEDIATE_VALUE_KAT +static const word8 Si[256] = { + 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, +124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, + 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, + 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, +114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, +108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, +144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, +208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, + 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, +150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, + 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, +252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, + 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, + 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, +160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, + 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125 +}; +#endif /* INTERMEDIATE_VALUE_KAT */ + +union xtab { + word32 xt32[256]; + word8 xt8[256][4]; +}; + +static const union xtab xT1 = { + .xt8 = { +{0xc6,0x63,0x63,0xa5}, {0xf8,0x7c,0x7c,0x84}, {0xee,0x77,0x77,0x99}, {0xf6,0x7b,0x7b,0x8d}, +{0xff,0xf2,0xf2,0x0d}, {0xd6,0x6b,0x6b,0xbd}, {0xde,0x6f,0x6f,0xb1}, {0x91,0xc5,0xc5,0x54}, +{0x60,0x30,0x30,0x50}, {0x02,0x01,0x01,0x03}, {0xce,0x67,0x67,0xa9}, {0x56,0x2b,0x2b,0x7d}, +{0xe7,0xfe,0xfe,0x19}, {0xb5,0xd7,0xd7,0x62}, {0x4d,0xab,0xab,0xe6}, {0xec,0x76,0x76,0x9a}, +{0x8f,0xca,0xca,0x45}, {0x1f,0x82,0x82,0x9d}, {0x89,0xc9,0xc9,0x40}, {0xfa,0x7d,0x7d,0x87}, +{0xef,0xfa,0xfa,0x15}, {0xb2,0x59,0x59,0xeb}, {0x8e,0x47,0x47,0xc9}, {0xfb,0xf0,0xf0,0x0b}, +{0x41,0xad,0xad,0xec}, {0xb3,0xd4,0xd4,0x67}, {0x5f,0xa2,0xa2,0xfd}, {0x45,0xaf,0xaf,0xea}, +{0x23,0x9c,0x9c,0xbf}, {0x53,0xa4,0xa4,0xf7}, {0xe4,0x72,0x72,0x96}, {0x9b,0xc0,0xc0,0x5b}, +{0x75,0xb7,0xb7,0xc2}, {0xe1,0xfd,0xfd,0x1c}, {0x3d,0x93,0x93,0xae}, {0x4c,0x26,0x26,0x6a}, +{0x6c,0x36,0x36,0x5a}, {0x7e,0x3f,0x3f,0x41}, {0xf5,0xf7,0xf7,0x02}, {0x83,0xcc,0xcc,0x4f}, +{0x68,0x34,0x34,0x5c}, {0x51,0xa5,0xa5,0xf4}, {0xd1,0xe5,0xe5,0x34}, {0xf9,0xf1,0xf1,0x08}, +{0xe2,0x71,0x71,0x93}, {0xab,0xd8,0xd8,0x73}, {0x62,0x31,0x31,0x53}, {0x2a,0x15,0x15,0x3f}, +{0x08,0x04,0x04,0x0c}, {0x95,0xc7,0xc7,0x52}, {0x46,0x23,0x23,0x65}, {0x9d,0xc3,0xc3,0x5e}, +{0x30,0x18,0x18,0x28}, {0x37,0x96,0x96,0xa1}, {0x0a,0x05,0x05,0x0f}, {0x2f,0x9a,0x9a,0xb5}, +{0x0e,0x07,0x07,0x09}, {0x24,0x12,0x12,0x36}, {0x1b,0x80,0x80,0x9b}, {0xdf,0xe2,0xe2,0x3d}, +{0xcd,0xeb,0xeb,0x26}, {0x4e,0x27,0x27,0x69}, {0x7f,0xb2,0xb2,0xcd}, {0xea,0x75,0x75,0x9f}, +{0x12,0x09,0x09,0x1b}, {0x1d,0x83,0x83,0x9e}, {0x58,0x2c,0x2c,0x74}, {0x34,0x1a,0x1a,0x2e}, +{0x36,0x1b,0x1b,0x2d}, {0xdc,0x6e,0x6e,0xb2}, {0xb4,0x5a,0x5a,0xee}, {0x5b,0xa0,0xa0,0xfb}, +{0xa4,0x52,0x52,0xf6}, {0x76,0x3b,0x3b,0x4d}, {0xb7,0xd6,0xd6,0x61}, {0x7d,0xb3,0xb3,0xce}, +{0x52,0x29,0x29,0x7b}, {0xdd,0xe3,0xe3,0x3e}, {0x5e,0x2f,0x2f,0x71}, {0x13,0x84,0x84,0x97}, +{0xa6,0x53,0x53,0xf5}, {0xb9,0xd1,0xd1,0x68}, {0x00,0x00,0x00,0x00}, {0xc1,0xed,0xed,0x2c}, +{0x40,0x20,0x20,0x60}, {0xe3,0xfc,0xfc,0x1f}, {0x79,0xb1,0xb1,0xc8}, {0xb6,0x5b,0x5b,0xed}, +{0xd4,0x6a,0x6a,0xbe}, {0x8d,0xcb,0xcb,0x46}, {0x67,0xbe,0xbe,0xd9}, {0x72,0x39,0x39,0x4b}, +{0x94,0x4a,0x4a,0xde}, {0x98,0x4c,0x4c,0xd4}, {0xb0,0x58,0x58,0xe8}, {0x85,0xcf,0xcf,0x4a}, +{0xbb,0xd0,0xd0,0x6b}, {0xc5,0xef,0xef,0x2a}, {0x4f,0xaa,0xaa,0xe5}, {0xed,0xfb,0xfb,0x16}, +{0x86,0x43,0x43,0xc5}, {0x9a,0x4d,0x4d,0xd7}, {0x66,0x33,0x33,0x55}, {0x11,0x85,0x85,0x94}, +{0x8a,0x45,0x45,0xcf}, {0xe9,0xf9,0xf9,0x10}, {0x04,0x02,0x02,0x06}, {0xfe,0x7f,0x7f,0x81}, +{0xa0,0x50,0x50,0xf0}, {0x78,0x3c,0x3c,0x44}, {0x25,0x9f,0x9f,0xba}, {0x4b,0xa8,0xa8,0xe3}, +{0xa2,0x51,0x51,0xf3}, {0x5d,0xa3,0xa3,0xfe}, {0x80,0x40,0x40,0xc0}, {0x05,0x8f,0x8f,0x8a}, +{0x3f,0x92,0x92,0xad}, {0x21,0x9d,0x9d,0xbc}, {0x70,0x38,0x38,0x48}, {0xf1,0xf5,0xf5,0x04}, +{0x63,0xbc,0xbc,0xdf}, {0x77,0xb6,0xb6,0xc1}, {0xaf,0xda,0xda,0x75}, {0x42,0x21,0x21,0x63}, +{0x20,0x10,0x10,0x30}, {0xe5,0xff,0xff,0x1a}, {0xfd,0xf3,0xf3,0x0e}, {0xbf,0xd2,0xd2,0x6d}, +{0x81,0xcd,0xcd,0x4c}, {0x18,0x0c,0x0c,0x14}, {0x26,0x13,0x13,0x35}, {0xc3,0xec,0xec,0x2f}, +{0xbe,0x5f,0x5f,0xe1}, {0x35,0x97,0x97,0xa2}, {0x88,0x44,0x44,0xcc}, {0x2e,0x17,0x17,0x39}, +{0x93,0xc4,0xc4,0x57}, {0x55,0xa7,0xa7,0xf2}, {0xfc,0x7e,0x7e,0x82}, {0x7a,0x3d,0x3d,0x47}, +{0xc8,0x64,0x64,0xac}, {0xba,0x5d,0x5d,0xe7}, {0x32,0x19,0x19,0x2b}, {0xe6,0x73,0x73,0x95}, +{0xc0,0x60,0x60,0xa0}, {0x19,0x81,0x81,0x98}, {0x9e,0x4f,0x4f,0xd1}, {0xa3,0xdc,0xdc,0x7f}, +{0x44,0x22,0x22,0x66}, {0x54,0x2a,0x2a,0x7e}, {0x3b,0x90,0x90,0xab}, {0x0b,0x88,0x88,0x83}, +{0x8c,0x46,0x46,0xca}, {0xc7,0xee,0xee,0x29}, {0x6b,0xb8,0xb8,0xd3}, {0x28,0x14,0x14,0x3c}, +{0xa7,0xde,0xde,0x79}, {0xbc,0x5e,0x5e,0xe2}, {0x16,0x0b,0x0b,0x1d}, {0xad,0xdb,0xdb,0x76}, +{0xdb,0xe0,0xe0,0x3b}, {0x64,0x32,0x32,0x56}, {0x74,0x3a,0x3a,0x4e}, {0x14,0x0a,0x0a,0x1e}, +{0x92,0x49,0x49,0xdb}, {0x0c,0x06,0x06,0x0a}, {0x48,0x24,0x24,0x6c}, {0xb8,0x5c,0x5c,0xe4}, +{0x9f,0xc2,0xc2,0x5d}, {0xbd,0xd3,0xd3,0x6e}, {0x43,0xac,0xac,0xef}, {0xc4,0x62,0x62,0xa6}, +{0x39,0x91,0x91,0xa8}, {0x31,0x95,0x95,0xa4}, {0xd3,0xe4,0xe4,0x37}, {0xf2,0x79,0x79,0x8b}, +{0xd5,0xe7,0xe7,0x32}, {0x8b,0xc8,0xc8,0x43}, {0x6e,0x37,0x37,0x59}, {0xda,0x6d,0x6d,0xb7}, +{0x01,0x8d,0x8d,0x8c}, {0xb1,0xd5,0xd5,0x64}, {0x9c,0x4e,0x4e,0xd2}, {0x49,0xa9,0xa9,0xe0}, +{0xd8,0x6c,0x6c,0xb4}, {0xac,0x56,0x56,0xfa}, {0xf3,0xf4,0xf4,0x07}, {0xcf,0xea,0xea,0x25}, +{0xca,0x65,0x65,0xaf}, {0xf4,0x7a,0x7a,0x8e}, {0x47,0xae,0xae,0xe9}, {0x10,0x08,0x08,0x18}, +{0x6f,0xba,0xba,0xd5}, {0xf0,0x78,0x78,0x88}, {0x4a,0x25,0x25,0x6f}, {0x5c,0x2e,0x2e,0x72}, +{0x38,0x1c,0x1c,0x24}, {0x57,0xa6,0xa6,0xf1}, {0x73,0xb4,0xb4,0xc7}, {0x97,0xc6,0xc6,0x51}, +{0xcb,0xe8,0xe8,0x23}, {0xa1,0xdd,0xdd,0x7c}, {0xe8,0x74,0x74,0x9c}, {0x3e,0x1f,0x1f,0x21}, +{0x96,0x4b,0x4b,0xdd}, {0x61,0xbd,0xbd,0xdc}, {0x0d,0x8b,0x8b,0x86}, {0x0f,0x8a,0x8a,0x85}, +{0xe0,0x70,0x70,0x90}, {0x7c,0x3e,0x3e,0x42}, {0x71,0xb5,0xb5,0xc4}, {0xcc,0x66,0x66,0xaa}, +{0x90,0x48,0x48,0xd8}, {0x06,0x03,0x03,0x05}, {0xf7,0xf6,0xf6,0x01}, {0x1c,0x0e,0x0e,0x12}, +{0xc2,0x61,0x61,0xa3}, {0x6a,0x35,0x35,0x5f}, {0xae,0x57,0x57,0xf9}, {0x69,0xb9,0xb9,0xd0}, +{0x17,0x86,0x86,0x91}, {0x99,0xc1,0xc1,0x58}, {0x3a,0x1d,0x1d,0x27}, {0x27,0x9e,0x9e,0xb9}, +{0xd9,0xe1,0xe1,0x38}, {0xeb,0xf8,0xf8,0x13}, {0x2b,0x98,0x98,0xb3}, {0x22,0x11,0x11,0x33}, +{0xd2,0x69,0x69,0xbb}, {0xa9,0xd9,0xd9,0x70}, {0x07,0x8e,0x8e,0x89}, {0x33,0x94,0x94,0xa7}, +{0x2d,0x9b,0x9b,0xb6}, {0x3c,0x1e,0x1e,0x22}, {0x15,0x87,0x87,0x92}, {0xc9,0xe9,0xe9,0x20}, +{0x87,0xce,0xce,0x49}, {0xaa,0x55,0x55,0xff}, {0x50,0x28,0x28,0x78}, {0xa5,0xdf,0xdf,0x7a}, +{0x03,0x8c,0x8c,0x8f}, {0x59,0xa1,0xa1,0xf8}, {0x09,0x89,0x89,0x80}, {0x1a,0x0d,0x0d,0x17}, +{0x65,0xbf,0xbf,0xda}, {0xd7,0xe6,0xe6,0x31}, {0x84,0x42,0x42,0xc6}, {0xd0,0x68,0x68,0xb8}, +{0x82,0x41,0x41,0xc3}, {0x29,0x99,0x99,0xb0}, {0x5a,0x2d,0x2d,0x77}, {0x1e,0x0f,0x0f,0x11}, +{0x7b,0xb0,0xb0,0xcb}, {0xa8,0x54,0x54,0xfc}, {0x6d,0xbb,0xbb,0xd6}, {0x2c,0x16,0x16,0x3a} + } +}; +#define T1 xT1.xt8 + +static const union xtab xT2 = { + .xt8 = { +{0xa5,0xc6,0x63,0x63}, {0x84,0xf8,0x7c,0x7c}, {0x99,0xee,0x77,0x77}, {0x8d,0xf6,0x7b,0x7b}, +{0x0d,0xff,0xf2,0xf2}, {0xbd,0xd6,0x6b,0x6b}, {0xb1,0xde,0x6f,0x6f}, {0x54,0x91,0xc5,0xc5}, +{0x50,0x60,0x30,0x30}, {0x03,0x02,0x01,0x01}, {0xa9,0xce,0x67,0x67}, {0x7d,0x56,0x2b,0x2b}, +{0x19,0xe7,0xfe,0xfe}, {0x62,0xb5,0xd7,0xd7}, {0xe6,0x4d,0xab,0xab}, {0x9a,0xec,0x76,0x76}, +{0x45,0x8f,0xca,0xca}, {0x9d,0x1f,0x82,0x82}, {0x40,0x89,0xc9,0xc9}, {0x87,0xfa,0x7d,0x7d}, +{0x15,0xef,0xfa,0xfa}, {0xeb,0xb2,0x59,0x59}, {0xc9,0x8e,0x47,0x47}, {0x0b,0xfb,0xf0,0xf0}, +{0xec,0x41,0xad,0xad}, {0x67,0xb3,0xd4,0xd4}, {0xfd,0x5f,0xa2,0xa2}, {0xea,0x45,0xaf,0xaf}, +{0xbf,0x23,0x9c,0x9c}, {0xf7,0x53,0xa4,0xa4}, {0x96,0xe4,0x72,0x72}, {0x5b,0x9b,0xc0,0xc0}, +{0xc2,0x75,0xb7,0xb7}, {0x1c,0xe1,0xfd,0xfd}, {0xae,0x3d,0x93,0x93}, {0x6a,0x4c,0x26,0x26}, +{0x5a,0x6c,0x36,0x36}, {0x41,0x7e,0x3f,0x3f}, {0x02,0xf5,0xf7,0xf7}, {0x4f,0x83,0xcc,0xcc}, +{0x5c,0x68,0x34,0x34}, {0xf4,0x51,0xa5,0xa5}, {0x34,0xd1,0xe5,0xe5}, {0x08,0xf9,0xf1,0xf1}, +{0x93,0xe2,0x71,0x71}, {0x73,0xab,0xd8,0xd8}, {0x53,0x62,0x31,0x31}, {0x3f,0x2a,0x15,0x15}, +{0x0c,0x08,0x04,0x04}, {0x52,0x95,0xc7,0xc7}, {0x65,0x46,0x23,0x23}, {0x5e,0x9d,0xc3,0xc3}, +{0x28,0x30,0x18,0x18}, {0xa1,0x37,0x96,0x96}, {0x0f,0x0a,0x05,0x05}, {0xb5,0x2f,0x9a,0x9a}, +{0x09,0x0e,0x07,0x07}, {0x36,0x24,0x12,0x12}, {0x9b,0x1b,0x80,0x80}, {0x3d,0xdf,0xe2,0xe2}, +{0x26,0xcd,0xeb,0xeb}, {0x69,0x4e,0x27,0x27}, {0xcd,0x7f,0xb2,0xb2}, {0x9f,0xea,0x75,0x75}, +{0x1b,0x12,0x09,0x09}, {0x9e,0x1d,0x83,0x83}, {0x74,0x58,0x2c,0x2c}, {0x2e,0x34,0x1a,0x1a}, +{0x2d,0x36,0x1b,0x1b}, {0xb2,0xdc,0x6e,0x6e}, {0xee,0xb4,0x5a,0x5a}, {0xfb,0x5b,0xa0,0xa0}, +{0xf6,0xa4,0x52,0x52}, {0x4d,0x76,0x3b,0x3b}, {0x61,0xb7,0xd6,0xd6}, {0xce,0x7d,0xb3,0xb3}, +{0x7b,0x52,0x29,0x29}, {0x3e,0xdd,0xe3,0xe3}, {0x71,0x5e,0x2f,0x2f}, {0x97,0x13,0x84,0x84}, +{0xf5,0xa6,0x53,0x53}, {0x68,0xb9,0xd1,0xd1}, {0x00,0x00,0x00,0x00}, {0x2c,0xc1,0xed,0xed}, +{0x60,0x40,0x20,0x20}, {0x1f,0xe3,0xfc,0xfc}, {0xc8,0x79,0xb1,0xb1}, {0xed,0xb6,0x5b,0x5b}, +{0xbe,0xd4,0x6a,0x6a}, {0x46,0x8d,0xcb,0xcb}, {0xd9,0x67,0xbe,0xbe}, {0x4b,0x72,0x39,0x39}, +{0xde,0x94,0x4a,0x4a}, {0xd4,0x98,0x4c,0x4c}, {0xe8,0xb0,0x58,0x58}, {0x4a,0x85,0xcf,0xcf}, +{0x6b,0xbb,0xd0,0xd0}, {0x2a,0xc5,0xef,0xef}, {0xe5,0x4f,0xaa,0xaa}, {0x16,0xed,0xfb,0xfb}, +{0xc5,0x86,0x43,0x43}, {0xd7,0x9a,0x4d,0x4d}, {0x55,0x66,0x33,0x33}, {0x94,0x11,0x85,0x85}, +{0xcf,0x8a,0x45,0x45}, {0x10,0xe9,0xf9,0xf9}, {0x06,0x04,0x02,0x02}, {0x81,0xfe,0x7f,0x7f}, +{0xf0,0xa0,0x50,0x50}, {0x44,0x78,0x3c,0x3c}, {0xba,0x25,0x9f,0x9f}, {0xe3,0x4b,0xa8,0xa8}, +{0xf3,0xa2,0x51,0x51}, {0xfe,0x5d,0xa3,0xa3}, {0xc0,0x80,0x40,0x40}, {0x8a,0x05,0x8f,0x8f}, +{0xad,0x3f,0x92,0x92}, {0xbc,0x21,0x9d,0x9d}, {0x48,0x70,0x38,0x38}, {0x04,0xf1,0xf5,0xf5}, +{0xdf,0x63,0xbc,0xbc}, {0xc1,0x77,0xb6,0xb6}, {0x75,0xaf,0xda,0xda}, {0x63,0x42,0x21,0x21}, +{0x30,0x20,0x10,0x10}, {0x1a,0xe5,0xff,0xff}, {0x0e,0xfd,0xf3,0xf3}, {0x6d,0xbf,0xd2,0xd2}, +{0x4c,0x81,0xcd,0xcd}, {0x14,0x18,0x0c,0x0c}, {0x35,0x26,0x13,0x13}, {0x2f,0xc3,0xec,0xec}, +{0xe1,0xbe,0x5f,0x5f}, {0xa2,0x35,0x97,0x97}, {0xcc,0x88,0x44,0x44}, {0x39,0x2e,0x17,0x17}, +{0x57,0x93,0xc4,0xc4}, {0xf2,0x55,0xa7,0xa7}, {0x82,0xfc,0x7e,0x7e}, {0x47,0x7a,0x3d,0x3d}, +{0xac,0xc8,0x64,0x64}, {0xe7,0xba,0x5d,0x5d}, {0x2b,0x32,0x19,0x19}, {0x95,0xe6,0x73,0x73}, +{0xa0,0xc0,0x60,0x60}, {0x98,0x19,0x81,0x81}, {0xd1,0x9e,0x4f,0x4f}, {0x7f,0xa3,0xdc,0xdc}, +{0x66,0x44,0x22,0x22}, {0x7e,0x54,0x2a,0x2a}, {0xab,0x3b,0x90,0x90}, {0x83,0x0b,0x88,0x88}, +{0xca,0x8c,0x46,0x46}, {0x29,0xc7,0xee,0xee}, {0xd3,0x6b,0xb8,0xb8}, {0x3c,0x28,0x14,0x14}, +{0x79,0xa7,0xde,0xde}, {0xe2,0xbc,0x5e,0x5e}, {0x1d,0x16,0x0b,0x0b}, {0x76,0xad,0xdb,0xdb}, +{0x3b,0xdb,0xe0,0xe0}, {0x56,0x64,0x32,0x32}, {0x4e,0x74,0x3a,0x3a}, {0x1e,0x14,0x0a,0x0a}, +{0xdb,0x92,0x49,0x49}, {0x0a,0x0c,0x06,0x06}, {0x6c,0x48,0x24,0x24}, {0xe4,0xb8,0x5c,0x5c}, +{0x5d,0x9f,0xc2,0xc2}, {0x6e,0xbd,0xd3,0xd3}, {0xef,0x43,0xac,0xac}, {0xa6,0xc4,0x62,0x62}, +{0xa8,0x39,0x91,0x91}, {0xa4,0x31,0x95,0x95}, {0x37,0xd3,0xe4,0xe4}, {0x8b,0xf2,0x79,0x79}, +{0x32,0xd5,0xe7,0xe7}, {0x43,0x8b,0xc8,0xc8}, {0x59,0x6e,0x37,0x37}, {0xb7,0xda,0x6d,0x6d}, +{0x8c,0x01,0x8d,0x8d}, {0x64,0xb1,0xd5,0xd5}, {0xd2,0x9c,0x4e,0x4e}, {0xe0,0x49,0xa9,0xa9}, +{0xb4,0xd8,0x6c,0x6c}, {0xfa,0xac,0x56,0x56}, {0x07,0xf3,0xf4,0xf4}, {0x25,0xcf,0xea,0xea}, +{0xaf,0xca,0x65,0x65}, {0x8e,0xf4,0x7a,0x7a}, {0xe9,0x47,0xae,0xae}, {0x18,0x10,0x08,0x08}, +{0xd5,0x6f,0xba,0xba}, {0x88,0xf0,0x78,0x78}, {0x6f,0x4a,0x25,0x25}, {0x72,0x5c,0x2e,0x2e}, +{0x24,0x38,0x1c,0x1c}, {0xf1,0x57,0xa6,0xa6}, {0xc7,0x73,0xb4,0xb4}, {0x51,0x97,0xc6,0xc6}, +{0x23,0xcb,0xe8,0xe8}, {0x7c,0xa1,0xdd,0xdd}, {0x9c,0xe8,0x74,0x74}, {0x21,0x3e,0x1f,0x1f}, +{0xdd,0x96,0x4b,0x4b}, {0xdc,0x61,0xbd,0xbd}, {0x86,0x0d,0x8b,0x8b}, {0x85,0x0f,0x8a,0x8a}, +{0x90,0xe0,0x70,0x70}, {0x42,0x7c,0x3e,0x3e}, {0xc4,0x71,0xb5,0xb5}, {0xaa,0xcc,0x66,0x66}, +{0xd8,0x90,0x48,0x48}, {0x05,0x06,0x03,0x03}, {0x01,0xf7,0xf6,0xf6}, {0x12,0x1c,0x0e,0x0e}, +{0xa3,0xc2,0x61,0x61}, {0x5f,0x6a,0x35,0x35}, {0xf9,0xae,0x57,0x57}, {0xd0,0x69,0xb9,0xb9}, +{0x91,0x17,0x86,0x86}, {0x58,0x99,0xc1,0xc1}, {0x27,0x3a,0x1d,0x1d}, {0xb9,0x27,0x9e,0x9e}, +{0x38,0xd9,0xe1,0xe1}, {0x13,0xeb,0xf8,0xf8}, {0xb3,0x2b,0x98,0x98}, {0x33,0x22,0x11,0x11}, +{0xbb,0xd2,0x69,0x69}, {0x70,0xa9,0xd9,0xd9}, {0x89,0x07,0x8e,0x8e}, {0xa7,0x33,0x94,0x94}, +{0xb6,0x2d,0x9b,0x9b}, {0x22,0x3c,0x1e,0x1e}, {0x92,0x15,0x87,0x87}, {0x20,0xc9,0xe9,0xe9}, +{0x49,0x87,0xce,0xce}, {0xff,0xaa,0x55,0x55}, {0x78,0x50,0x28,0x28}, {0x7a,0xa5,0xdf,0xdf}, +{0x8f,0x03,0x8c,0x8c}, {0xf8,0x59,0xa1,0xa1}, {0x80,0x09,0x89,0x89}, {0x17,0x1a,0x0d,0x0d}, +{0xda,0x65,0xbf,0xbf}, {0x31,0xd7,0xe6,0xe6}, {0xc6,0x84,0x42,0x42}, {0xb8,0xd0,0x68,0x68}, +{0xc3,0x82,0x41,0x41}, {0xb0,0x29,0x99,0x99}, {0x77,0x5a,0x2d,0x2d}, {0x11,0x1e,0x0f,0x0f}, +{0xcb,0x7b,0xb0,0xb0}, {0xfc,0xa8,0x54,0x54}, {0xd6,0x6d,0xbb,0xbb}, {0x3a,0x2c,0x16,0x16} + } +}; +#define T2 xT2.xt8 + +static const union xtab xT3 = { + .xt8 = { +{0x63,0xa5,0xc6,0x63}, {0x7c,0x84,0xf8,0x7c}, {0x77,0x99,0xee,0x77}, {0x7b,0x8d,0xf6,0x7b}, +{0xf2,0x0d,0xff,0xf2}, {0x6b,0xbd,0xd6,0x6b}, {0x6f,0xb1,0xde,0x6f}, {0xc5,0x54,0x91,0xc5}, +{0x30,0x50,0x60,0x30}, {0x01,0x03,0x02,0x01}, {0x67,0xa9,0xce,0x67}, {0x2b,0x7d,0x56,0x2b}, +{0xfe,0x19,0xe7,0xfe}, {0xd7,0x62,0xb5,0xd7}, {0xab,0xe6,0x4d,0xab}, {0x76,0x9a,0xec,0x76}, +{0xca,0x45,0x8f,0xca}, {0x82,0x9d,0x1f,0x82}, {0xc9,0x40,0x89,0xc9}, {0x7d,0x87,0xfa,0x7d}, +{0xfa,0x15,0xef,0xfa}, {0x59,0xeb,0xb2,0x59}, {0x47,0xc9,0x8e,0x47}, {0xf0,0x0b,0xfb,0xf0}, +{0xad,0xec,0x41,0xad}, {0xd4,0x67,0xb3,0xd4}, {0xa2,0xfd,0x5f,0xa2}, {0xaf,0xea,0x45,0xaf}, +{0x9c,0xbf,0x23,0x9c}, {0xa4,0xf7,0x53,0xa4}, {0x72,0x96,0xe4,0x72}, {0xc0,0x5b,0x9b,0xc0}, +{0xb7,0xc2,0x75,0xb7}, {0xfd,0x1c,0xe1,0xfd}, {0x93,0xae,0x3d,0x93}, {0x26,0x6a,0x4c,0x26}, +{0x36,0x5a,0x6c,0x36}, {0x3f,0x41,0x7e,0x3f}, {0xf7,0x02,0xf5,0xf7}, {0xcc,0x4f,0x83,0xcc}, +{0x34,0x5c,0x68,0x34}, {0xa5,0xf4,0x51,0xa5}, {0xe5,0x34,0xd1,0xe5}, {0xf1,0x08,0xf9,0xf1}, +{0x71,0x93,0xe2,0x71}, {0xd8,0x73,0xab,0xd8}, {0x31,0x53,0x62,0x31}, {0x15,0x3f,0x2a,0x15}, +{0x04,0x0c,0x08,0x04}, {0xc7,0x52,0x95,0xc7}, {0x23,0x65,0x46,0x23}, {0xc3,0x5e,0x9d,0xc3}, +{0x18,0x28,0x30,0x18}, {0x96,0xa1,0x37,0x96}, {0x05,0x0f,0x0a,0x05}, {0x9a,0xb5,0x2f,0x9a}, +{0x07,0x09,0x0e,0x07}, {0x12,0x36,0x24,0x12}, {0x80,0x9b,0x1b,0x80}, {0xe2,0x3d,0xdf,0xe2}, +{0xeb,0x26,0xcd,0xeb}, {0x27,0x69,0x4e,0x27}, {0xb2,0xcd,0x7f,0xb2}, {0x75,0x9f,0xea,0x75}, +{0x09,0x1b,0x12,0x09}, {0x83,0x9e,0x1d,0x83}, {0x2c,0x74,0x58,0x2c}, {0x1a,0x2e,0x34,0x1a}, +{0x1b,0x2d,0x36,0x1b}, {0x6e,0xb2,0xdc,0x6e}, {0x5a,0xee,0xb4,0x5a}, {0xa0,0xfb,0x5b,0xa0}, +{0x52,0xf6,0xa4,0x52}, {0x3b,0x4d,0x76,0x3b}, {0xd6,0x61,0xb7,0xd6}, {0xb3,0xce,0x7d,0xb3}, +{0x29,0x7b,0x52,0x29}, {0xe3,0x3e,0xdd,0xe3}, {0x2f,0x71,0x5e,0x2f}, {0x84,0x97,0x13,0x84}, +{0x53,0xf5,0xa6,0x53}, {0xd1,0x68,0xb9,0xd1}, {0x00,0x00,0x00,0x00}, {0xed,0x2c,0xc1,0xed}, +{0x20,0x60,0x40,0x20}, {0xfc,0x1f,0xe3,0xfc}, {0xb1,0xc8,0x79,0xb1}, {0x5b,0xed,0xb6,0x5b}, +{0x6a,0xbe,0xd4,0x6a}, {0xcb,0x46,0x8d,0xcb}, {0xbe,0xd9,0x67,0xbe}, {0x39,0x4b,0x72,0x39}, +{0x4a,0xde,0x94,0x4a}, {0x4c,0xd4,0x98,0x4c}, {0x58,0xe8,0xb0,0x58}, {0xcf,0x4a,0x85,0xcf}, +{0xd0,0x6b,0xbb,0xd0}, {0xef,0x2a,0xc5,0xef}, {0xaa,0xe5,0x4f,0xaa}, {0xfb,0x16,0xed,0xfb}, +{0x43,0xc5,0x86,0x43}, {0x4d,0xd7,0x9a,0x4d}, {0x33,0x55,0x66,0x33}, {0x85,0x94,0x11,0x85}, +{0x45,0xcf,0x8a,0x45}, {0xf9,0x10,0xe9,0xf9}, {0x02,0x06,0x04,0x02}, {0x7f,0x81,0xfe,0x7f}, +{0x50,0xf0,0xa0,0x50}, {0x3c,0x44,0x78,0x3c}, {0x9f,0xba,0x25,0x9f}, {0xa8,0xe3,0x4b,0xa8}, +{0x51,0xf3,0xa2,0x51}, {0xa3,0xfe,0x5d,0xa3}, {0x40,0xc0,0x80,0x40}, {0x8f,0x8a,0x05,0x8f}, +{0x92,0xad,0x3f,0x92}, {0x9d,0xbc,0x21,0x9d}, {0x38,0x48,0x70,0x38}, {0xf5,0x04,0xf1,0xf5}, +{0xbc,0xdf,0x63,0xbc}, {0xb6,0xc1,0x77,0xb6}, {0xda,0x75,0xaf,0xda}, {0x21,0x63,0x42,0x21}, +{0x10,0x30,0x20,0x10}, {0xff,0x1a,0xe5,0xff}, {0xf3,0x0e,0xfd,0xf3}, {0xd2,0x6d,0xbf,0xd2}, +{0xcd,0x4c,0x81,0xcd}, {0x0c,0x14,0x18,0x0c}, {0x13,0x35,0x26,0x13}, {0xec,0x2f,0xc3,0xec}, +{0x5f,0xe1,0xbe,0x5f}, {0x97,0xa2,0x35,0x97}, {0x44,0xcc,0x88,0x44}, {0x17,0x39,0x2e,0x17}, +{0xc4,0x57,0x93,0xc4}, {0xa7,0xf2,0x55,0xa7}, {0x7e,0x82,0xfc,0x7e}, {0x3d,0x47,0x7a,0x3d}, +{0x64,0xac,0xc8,0x64}, {0x5d,0xe7,0xba,0x5d}, {0x19,0x2b,0x32,0x19}, {0x73,0x95,0xe6,0x73}, +{0x60,0xa0,0xc0,0x60}, {0x81,0x98,0x19,0x81}, {0x4f,0xd1,0x9e,0x4f}, {0xdc,0x7f,0xa3,0xdc}, +{0x22,0x66,0x44,0x22}, {0x2a,0x7e,0x54,0x2a}, {0x90,0xab,0x3b,0x90}, {0x88,0x83,0x0b,0x88}, +{0x46,0xca,0x8c,0x46}, {0xee,0x29,0xc7,0xee}, {0xb8,0xd3,0x6b,0xb8}, {0x14,0x3c,0x28,0x14}, +{0xde,0x79,0xa7,0xde}, {0x5e,0xe2,0xbc,0x5e}, {0x0b,0x1d,0x16,0x0b}, {0xdb,0x76,0xad,0xdb}, +{0xe0,0x3b,0xdb,0xe0}, {0x32,0x56,0x64,0x32}, {0x3a,0x4e,0x74,0x3a}, {0x0a,0x1e,0x14,0x0a}, +{0x49,0xdb,0x92,0x49}, {0x06,0x0a,0x0c,0x06}, {0x24,0x6c,0x48,0x24}, {0x5c,0xe4,0xb8,0x5c}, +{0xc2,0x5d,0x9f,0xc2}, {0xd3,0x6e,0xbd,0xd3}, {0xac,0xef,0x43,0xac}, {0x62,0xa6,0xc4,0x62}, +{0x91,0xa8,0x39,0x91}, {0x95,0xa4,0x31,0x95}, {0xe4,0x37,0xd3,0xe4}, {0x79,0x8b,0xf2,0x79}, +{0xe7,0x32,0xd5,0xe7}, {0xc8,0x43,0x8b,0xc8}, {0x37,0x59,0x6e,0x37}, {0x6d,0xb7,0xda,0x6d}, +{0x8d,0x8c,0x01,0x8d}, {0xd5,0x64,0xb1,0xd5}, {0x4e,0xd2,0x9c,0x4e}, {0xa9,0xe0,0x49,0xa9}, +{0x6c,0xb4,0xd8,0x6c}, {0x56,0xfa,0xac,0x56}, {0xf4,0x07,0xf3,0xf4}, {0xea,0x25,0xcf,0xea}, +{0x65,0xaf,0xca,0x65}, {0x7a,0x8e,0xf4,0x7a}, {0xae,0xe9,0x47,0xae}, {0x08,0x18,0x10,0x08}, +{0xba,0xd5,0x6f,0xba}, {0x78,0x88,0xf0,0x78}, {0x25,0x6f,0x4a,0x25}, {0x2e,0x72,0x5c,0x2e}, +{0x1c,0x24,0x38,0x1c}, {0xa6,0xf1,0x57,0xa6}, {0xb4,0xc7,0x73,0xb4}, {0xc6,0x51,0x97,0xc6}, +{0xe8,0x23,0xcb,0xe8}, {0xdd,0x7c,0xa1,0xdd}, {0x74,0x9c,0xe8,0x74}, {0x1f,0x21,0x3e,0x1f}, +{0x4b,0xdd,0x96,0x4b}, {0xbd,0xdc,0x61,0xbd}, {0x8b,0x86,0x0d,0x8b}, {0x8a,0x85,0x0f,0x8a}, +{0x70,0x90,0xe0,0x70}, {0x3e,0x42,0x7c,0x3e}, {0xb5,0xc4,0x71,0xb5}, {0x66,0xaa,0xcc,0x66}, +{0x48,0xd8,0x90,0x48}, {0x03,0x05,0x06,0x03}, {0xf6,0x01,0xf7,0xf6}, {0x0e,0x12,0x1c,0x0e}, +{0x61,0xa3,0xc2,0x61}, {0x35,0x5f,0x6a,0x35}, {0x57,0xf9,0xae,0x57}, {0xb9,0xd0,0x69,0xb9}, +{0x86,0x91,0x17,0x86}, {0xc1,0x58,0x99,0xc1}, {0x1d,0x27,0x3a,0x1d}, {0x9e,0xb9,0x27,0x9e}, +{0xe1,0x38,0xd9,0xe1}, {0xf8,0x13,0xeb,0xf8}, {0x98,0xb3,0x2b,0x98}, {0x11,0x33,0x22,0x11}, +{0x69,0xbb,0xd2,0x69}, {0xd9,0x70,0xa9,0xd9}, {0x8e,0x89,0x07,0x8e}, {0x94,0xa7,0x33,0x94}, +{0x9b,0xb6,0x2d,0x9b}, {0x1e,0x22,0x3c,0x1e}, {0x87,0x92,0x15,0x87}, {0xe9,0x20,0xc9,0xe9}, +{0xce,0x49,0x87,0xce}, {0x55,0xff,0xaa,0x55}, {0x28,0x78,0x50,0x28}, {0xdf,0x7a,0xa5,0xdf}, +{0x8c,0x8f,0x03,0x8c}, {0xa1,0xf8,0x59,0xa1}, {0x89,0x80,0x09,0x89}, {0x0d,0x17,0x1a,0x0d}, +{0xbf,0xda,0x65,0xbf}, {0xe6,0x31,0xd7,0xe6}, {0x42,0xc6,0x84,0x42}, {0x68,0xb8,0xd0,0x68}, +{0x41,0xc3,0x82,0x41}, {0x99,0xb0,0x29,0x99}, {0x2d,0x77,0x5a,0x2d}, {0x0f,0x11,0x1e,0x0f}, +{0xb0,0xcb,0x7b,0xb0}, {0x54,0xfc,0xa8,0x54}, {0xbb,0xd6,0x6d,0xbb}, {0x16,0x3a,0x2c,0x16} + } +}; +#define T3 xT3.xt8 + +static const union xtab xT4 = { + .xt8 = { +{0x63,0x63,0xa5,0xc6}, {0x7c,0x7c,0x84,0xf8}, {0x77,0x77,0x99,0xee}, {0x7b,0x7b,0x8d,0xf6}, +{0xf2,0xf2,0x0d,0xff}, {0x6b,0x6b,0xbd,0xd6}, {0x6f,0x6f,0xb1,0xde}, {0xc5,0xc5,0x54,0x91}, +{0x30,0x30,0x50,0x60}, {0x01,0x01,0x03,0x02}, {0x67,0x67,0xa9,0xce}, {0x2b,0x2b,0x7d,0x56}, +{0xfe,0xfe,0x19,0xe7}, {0xd7,0xd7,0x62,0xb5}, {0xab,0xab,0xe6,0x4d}, {0x76,0x76,0x9a,0xec}, +{0xca,0xca,0x45,0x8f}, {0x82,0x82,0x9d,0x1f}, {0xc9,0xc9,0x40,0x89}, {0x7d,0x7d,0x87,0xfa}, +{0xfa,0xfa,0x15,0xef}, {0x59,0x59,0xeb,0xb2}, {0x47,0x47,0xc9,0x8e}, {0xf0,0xf0,0x0b,0xfb}, +{0xad,0xad,0xec,0x41}, {0xd4,0xd4,0x67,0xb3}, {0xa2,0xa2,0xfd,0x5f}, {0xaf,0xaf,0xea,0x45}, +{0x9c,0x9c,0xbf,0x23}, {0xa4,0xa4,0xf7,0x53}, {0x72,0x72,0x96,0xe4}, {0xc0,0xc0,0x5b,0x9b}, +{0xb7,0xb7,0xc2,0x75}, {0xfd,0xfd,0x1c,0xe1}, {0x93,0x93,0xae,0x3d}, {0x26,0x26,0x6a,0x4c}, +{0x36,0x36,0x5a,0x6c}, {0x3f,0x3f,0x41,0x7e}, {0xf7,0xf7,0x02,0xf5}, {0xcc,0xcc,0x4f,0x83}, +{0x34,0x34,0x5c,0x68}, {0xa5,0xa5,0xf4,0x51}, {0xe5,0xe5,0x34,0xd1}, {0xf1,0xf1,0x08,0xf9}, +{0x71,0x71,0x93,0xe2}, {0xd8,0xd8,0x73,0xab}, {0x31,0x31,0x53,0x62}, {0x15,0x15,0x3f,0x2a}, +{0x04,0x04,0x0c,0x08}, {0xc7,0xc7,0x52,0x95}, {0x23,0x23,0x65,0x46}, {0xc3,0xc3,0x5e,0x9d}, +{0x18,0x18,0x28,0x30}, {0x96,0x96,0xa1,0x37}, {0x05,0x05,0x0f,0x0a}, {0x9a,0x9a,0xb5,0x2f}, +{0x07,0x07,0x09,0x0e}, {0x12,0x12,0x36,0x24}, {0x80,0x80,0x9b,0x1b}, {0xe2,0xe2,0x3d,0xdf}, +{0xeb,0xeb,0x26,0xcd}, {0x27,0x27,0x69,0x4e}, {0xb2,0xb2,0xcd,0x7f}, {0x75,0x75,0x9f,0xea}, +{0x09,0x09,0x1b,0x12}, {0x83,0x83,0x9e,0x1d}, {0x2c,0x2c,0x74,0x58}, {0x1a,0x1a,0x2e,0x34}, +{0x1b,0x1b,0x2d,0x36}, {0x6e,0x6e,0xb2,0xdc}, {0x5a,0x5a,0xee,0xb4}, {0xa0,0xa0,0xfb,0x5b}, +{0x52,0x52,0xf6,0xa4}, {0x3b,0x3b,0x4d,0x76}, {0xd6,0xd6,0x61,0xb7}, {0xb3,0xb3,0xce,0x7d}, +{0x29,0x29,0x7b,0x52}, {0xe3,0xe3,0x3e,0xdd}, {0x2f,0x2f,0x71,0x5e}, {0x84,0x84,0x97,0x13}, +{0x53,0x53,0xf5,0xa6}, {0xd1,0xd1,0x68,0xb9}, {0x00,0x00,0x00,0x00}, {0xed,0xed,0x2c,0xc1}, +{0x20,0x20,0x60,0x40}, {0xfc,0xfc,0x1f,0xe3}, {0xb1,0xb1,0xc8,0x79}, {0x5b,0x5b,0xed,0xb6}, +{0x6a,0x6a,0xbe,0xd4}, {0xcb,0xcb,0x46,0x8d}, {0xbe,0xbe,0xd9,0x67}, {0x39,0x39,0x4b,0x72}, +{0x4a,0x4a,0xde,0x94}, {0x4c,0x4c,0xd4,0x98}, {0x58,0x58,0xe8,0xb0}, {0xcf,0xcf,0x4a,0x85}, +{0xd0,0xd0,0x6b,0xbb}, {0xef,0xef,0x2a,0xc5}, {0xaa,0xaa,0xe5,0x4f}, {0xfb,0xfb,0x16,0xed}, +{0x43,0x43,0xc5,0x86}, {0x4d,0x4d,0xd7,0x9a}, {0x33,0x33,0x55,0x66}, {0x85,0x85,0x94,0x11}, +{0x45,0x45,0xcf,0x8a}, {0xf9,0xf9,0x10,0xe9}, {0x02,0x02,0x06,0x04}, {0x7f,0x7f,0x81,0xfe}, +{0x50,0x50,0xf0,0xa0}, {0x3c,0x3c,0x44,0x78}, {0x9f,0x9f,0xba,0x25}, {0xa8,0xa8,0xe3,0x4b}, +{0x51,0x51,0xf3,0xa2}, {0xa3,0xa3,0xfe,0x5d}, {0x40,0x40,0xc0,0x80}, {0x8f,0x8f,0x8a,0x05}, +{0x92,0x92,0xad,0x3f}, {0x9d,0x9d,0xbc,0x21}, {0x38,0x38,0x48,0x70}, {0xf5,0xf5,0x04,0xf1}, +{0xbc,0xbc,0xdf,0x63}, {0xb6,0xb6,0xc1,0x77}, {0xda,0xda,0x75,0xaf}, {0x21,0x21,0x63,0x42}, +{0x10,0x10,0x30,0x20}, {0xff,0xff,0x1a,0xe5}, {0xf3,0xf3,0x0e,0xfd}, {0xd2,0xd2,0x6d,0xbf}, +{0xcd,0xcd,0x4c,0x81}, {0x0c,0x0c,0x14,0x18}, {0x13,0x13,0x35,0x26}, {0xec,0xec,0x2f,0xc3}, +{0x5f,0x5f,0xe1,0xbe}, {0x97,0x97,0xa2,0x35}, {0x44,0x44,0xcc,0x88}, {0x17,0x17,0x39,0x2e}, +{0xc4,0xc4,0x57,0x93}, {0xa7,0xa7,0xf2,0x55}, {0x7e,0x7e,0x82,0xfc}, {0x3d,0x3d,0x47,0x7a}, +{0x64,0x64,0xac,0xc8}, {0x5d,0x5d,0xe7,0xba}, {0x19,0x19,0x2b,0x32}, {0x73,0x73,0x95,0xe6}, +{0x60,0x60,0xa0,0xc0}, {0x81,0x81,0x98,0x19}, {0x4f,0x4f,0xd1,0x9e}, {0xdc,0xdc,0x7f,0xa3}, +{0x22,0x22,0x66,0x44}, {0x2a,0x2a,0x7e,0x54}, {0x90,0x90,0xab,0x3b}, {0x88,0x88,0x83,0x0b}, +{0x46,0x46,0xca,0x8c}, {0xee,0xee,0x29,0xc7}, {0xb8,0xb8,0xd3,0x6b}, {0x14,0x14,0x3c,0x28}, +{0xde,0xde,0x79,0xa7}, {0x5e,0x5e,0xe2,0xbc}, {0x0b,0x0b,0x1d,0x16}, {0xdb,0xdb,0x76,0xad}, +{0xe0,0xe0,0x3b,0xdb}, {0x32,0x32,0x56,0x64}, {0x3a,0x3a,0x4e,0x74}, {0x0a,0x0a,0x1e,0x14}, +{0x49,0x49,0xdb,0x92}, {0x06,0x06,0x0a,0x0c}, {0x24,0x24,0x6c,0x48}, {0x5c,0x5c,0xe4,0xb8}, +{0xc2,0xc2,0x5d,0x9f}, {0xd3,0xd3,0x6e,0xbd}, {0xac,0xac,0xef,0x43}, {0x62,0x62,0xa6,0xc4}, +{0x91,0x91,0xa8,0x39}, {0x95,0x95,0xa4,0x31}, {0xe4,0xe4,0x37,0xd3}, {0x79,0x79,0x8b,0xf2}, +{0xe7,0xe7,0x32,0xd5}, {0xc8,0xc8,0x43,0x8b}, {0x37,0x37,0x59,0x6e}, {0x6d,0x6d,0xb7,0xda}, +{0x8d,0x8d,0x8c,0x01}, {0xd5,0xd5,0x64,0xb1}, {0x4e,0x4e,0xd2,0x9c}, {0xa9,0xa9,0xe0,0x49}, +{0x6c,0x6c,0xb4,0xd8}, {0x56,0x56,0xfa,0xac}, {0xf4,0xf4,0x07,0xf3}, {0xea,0xea,0x25,0xcf}, +{0x65,0x65,0xaf,0xca}, {0x7a,0x7a,0x8e,0xf4}, {0xae,0xae,0xe9,0x47}, {0x08,0x08,0x18,0x10}, +{0xba,0xba,0xd5,0x6f}, {0x78,0x78,0x88,0xf0}, {0x25,0x25,0x6f,0x4a}, {0x2e,0x2e,0x72,0x5c}, +{0x1c,0x1c,0x24,0x38}, {0xa6,0xa6,0xf1,0x57}, {0xb4,0xb4,0xc7,0x73}, {0xc6,0xc6,0x51,0x97}, +{0xe8,0xe8,0x23,0xcb}, {0xdd,0xdd,0x7c,0xa1}, {0x74,0x74,0x9c,0xe8}, {0x1f,0x1f,0x21,0x3e}, +{0x4b,0x4b,0xdd,0x96}, {0xbd,0xbd,0xdc,0x61}, {0x8b,0x8b,0x86,0x0d}, {0x8a,0x8a,0x85,0x0f}, +{0x70,0x70,0x90,0xe0}, {0x3e,0x3e,0x42,0x7c}, {0xb5,0xb5,0xc4,0x71}, {0x66,0x66,0xaa,0xcc}, +{0x48,0x48,0xd8,0x90}, {0x03,0x03,0x05,0x06}, {0xf6,0xf6,0x01,0xf7}, {0x0e,0x0e,0x12,0x1c}, +{0x61,0x61,0xa3,0xc2}, {0x35,0x35,0x5f,0x6a}, {0x57,0x57,0xf9,0xae}, {0xb9,0xb9,0xd0,0x69}, +{0x86,0x86,0x91,0x17}, {0xc1,0xc1,0x58,0x99}, {0x1d,0x1d,0x27,0x3a}, {0x9e,0x9e,0xb9,0x27}, +{0xe1,0xe1,0x38,0xd9}, {0xf8,0xf8,0x13,0xeb}, {0x98,0x98,0xb3,0x2b}, {0x11,0x11,0x33,0x22}, +{0x69,0x69,0xbb,0xd2}, {0xd9,0xd9,0x70,0xa9}, {0x8e,0x8e,0x89,0x07}, {0x94,0x94,0xa7,0x33}, +{0x9b,0x9b,0xb6,0x2d}, {0x1e,0x1e,0x22,0x3c}, {0x87,0x87,0x92,0x15}, {0xe9,0xe9,0x20,0xc9}, +{0xce,0xce,0x49,0x87}, {0x55,0x55,0xff,0xaa}, {0x28,0x28,0x78,0x50}, {0xdf,0xdf,0x7a,0xa5}, +{0x8c,0x8c,0x8f,0x03}, {0xa1,0xa1,0xf8,0x59}, {0x89,0x89,0x80,0x09}, {0x0d,0x0d,0x17,0x1a}, +{0xbf,0xbf,0xda,0x65}, {0xe6,0xe6,0x31,0xd7}, {0x42,0x42,0xc6,0x84}, {0x68,0x68,0xb8,0xd0}, +{0x41,0x41,0xc3,0x82}, {0x99,0x99,0xb0,0x29}, {0x2d,0x2d,0x77,0x5a}, {0x0f,0x0f,0x11,0x1e}, +{0xb0,0xb0,0xcb,0x7b}, {0x54,0x54,0xfc,0xa8}, {0xbb,0xbb,0xd6,0x6d}, {0x16,0x16,0x3a,0x2c} + } +}; +#define T4 xT4.xt8 + +static const union xtab xT5 = { + .xt8 = { +{0x51,0xf4,0xa7,0x50}, {0x7e,0x41,0x65,0x53}, {0x1a,0x17,0xa4,0xc3}, {0x3a,0x27,0x5e,0x96}, +{0x3b,0xab,0x6b,0xcb}, {0x1f,0x9d,0x45,0xf1}, {0xac,0xfa,0x58,0xab}, {0x4b,0xe3,0x03,0x93}, +{0x20,0x30,0xfa,0x55}, {0xad,0x76,0x6d,0xf6}, {0x88,0xcc,0x76,0x91}, {0xf5,0x02,0x4c,0x25}, +{0x4f,0xe5,0xd7,0xfc}, {0xc5,0x2a,0xcb,0xd7}, {0x26,0x35,0x44,0x80}, {0xb5,0x62,0xa3,0x8f}, +{0xde,0xb1,0x5a,0x49}, {0x25,0xba,0x1b,0x67}, {0x45,0xea,0x0e,0x98}, {0x5d,0xfe,0xc0,0xe1}, +{0xc3,0x2f,0x75,0x02}, {0x81,0x4c,0xf0,0x12}, {0x8d,0x46,0x97,0xa3}, {0x6b,0xd3,0xf9,0xc6}, +{0x03,0x8f,0x5f,0xe7}, {0x15,0x92,0x9c,0x95}, {0xbf,0x6d,0x7a,0xeb}, {0x95,0x52,0x59,0xda}, +{0xd4,0xbe,0x83,0x2d}, {0x58,0x74,0x21,0xd3}, {0x49,0xe0,0x69,0x29}, {0x8e,0xc9,0xc8,0x44}, +{0x75,0xc2,0x89,0x6a}, {0xf4,0x8e,0x79,0x78}, {0x99,0x58,0x3e,0x6b}, {0x27,0xb9,0x71,0xdd}, +{0xbe,0xe1,0x4f,0xb6}, {0xf0,0x88,0xad,0x17}, {0xc9,0x20,0xac,0x66}, {0x7d,0xce,0x3a,0xb4}, +{0x63,0xdf,0x4a,0x18}, {0xe5,0x1a,0x31,0x82}, {0x97,0x51,0x33,0x60}, {0x62,0x53,0x7f,0x45}, +{0xb1,0x64,0x77,0xe0}, {0xbb,0x6b,0xae,0x84}, {0xfe,0x81,0xa0,0x1c}, {0xf9,0x08,0x2b,0x94}, +{0x70,0x48,0x68,0x58}, {0x8f,0x45,0xfd,0x19}, {0x94,0xde,0x6c,0x87}, {0x52,0x7b,0xf8,0xb7}, +{0xab,0x73,0xd3,0x23}, {0x72,0x4b,0x02,0xe2}, {0xe3,0x1f,0x8f,0x57}, {0x66,0x55,0xab,0x2a}, +{0xb2,0xeb,0x28,0x07}, {0x2f,0xb5,0xc2,0x03}, {0x86,0xc5,0x7b,0x9a}, {0xd3,0x37,0x08,0xa5}, +{0x30,0x28,0x87,0xf2}, {0x23,0xbf,0xa5,0xb2}, {0x02,0x03,0x6a,0xba}, {0xed,0x16,0x82,0x5c}, +{0x8a,0xcf,0x1c,0x2b}, {0xa7,0x79,0xb4,0x92}, {0xf3,0x07,0xf2,0xf0}, {0x4e,0x69,0xe2,0xa1}, +{0x65,0xda,0xf4,0xcd}, {0x06,0x05,0xbe,0xd5}, {0xd1,0x34,0x62,0x1f}, {0xc4,0xa6,0xfe,0x8a}, +{0x34,0x2e,0x53,0x9d}, {0xa2,0xf3,0x55,0xa0}, {0x05,0x8a,0xe1,0x32}, {0xa4,0xf6,0xeb,0x75}, +{0x0b,0x83,0xec,0x39}, {0x40,0x60,0xef,0xaa}, {0x5e,0x71,0x9f,0x06}, {0xbd,0x6e,0x10,0x51}, +{0x3e,0x21,0x8a,0xf9}, {0x96,0xdd,0x06,0x3d}, {0xdd,0x3e,0x05,0xae}, {0x4d,0xe6,0xbd,0x46}, +{0x91,0x54,0x8d,0xb5}, {0x71,0xc4,0x5d,0x05}, {0x04,0x06,0xd4,0x6f}, {0x60,0x50,0x15,0xff}, +{0x19,0x98,0xfb,0x24}, {0xd6,0xbd,0xe9,0x97}, {0x89,0x40,0x43,0xcc}, {0x67,0xd9,0x9e,0x77}, +{0xb0,0xe8,0x42,0xbd}, {0x07,0x89,0x8b,0x88}, {0xe7,0x19,0x5b,0x38}, {0x79,0xc8,0xee,0xdb}, +{0xa1,0x7c,0x0a,0x47}, {0x7c,0x42,0x0f,0xe9}, {0xf8,0x84,0x1e,0xc9}, {0x00,0x00,0x00,0x00}, +{0x09,0x80,0x86,0x83}, {0x32,0x2b,0xed,0x48}, {0x1e,0x11,0x70,0xac}, {0x6c,0x5a,0x72,0x4e}, +{0xfd,0x0e,0xff,0xfb}, {0x0f,0x85,0x38,0x56}, {0x3d,0xae,0xd5,0x1e}, {0x36,0x2d,0x39,0x27}, +{0x0a,0x0f,0xd9,0x64}, {0x68,0x5c,0xa6,0x21}, {0x9b,0x5b,0x54,0xd1}, {0x24,0x36,0x2e,0x3a}, +{0x0c,0x0a,0x67,0xb1}, {0x93,0x57,0xe7,0x0f}, {0xb4,0xee,0x96,0xd2}, {0x1b,0x9b,0x91,0x9e}, +{0x80,0xc0,0xc5,0x4f}, {0x61,0xdc,0x20,0xa2}, {0x5a,0x77,0x4b,0x69}, {0x1c,0x12,0x1a,0x16}, +{0xe2,0x93,0xba,0x0a}, {0xc0,0xa0,0x2a,0xe5}, {0x3c,0x22,0xe0,0x43}, {0x12,0x1b,0x17,0x1d}, +{0x0e,0x09,0x0d,0x0b}, {0xf2,0x8b,0xc7,0xad}, {0x2d,0xb6,0xa8,0xb9}, {0x14,0x1e,0xa9,0xc8}, +{0x57,0xf1,0x19,0x85}, {0xaf,0x75,0x07,0x4c}, {0xee,0x99,0xdd,0xbb}, {0xa3,0x7f,0x60,0xfd}, +{0xf7,0x01,0x26,0x9f}, {0x5c,0x72,0xf5,0xbc}, {0x44,0x66,0x3b,0xc5}, {0x5b,0xfb,0x7e,0x34}, +{0x8b,0x43,0x29,0x76}, {0xcb,0x23,0xc6,0xdc}, {0xb6,0xed,0xfc,0x68}, {0xb8,0xe4,0xf1,0x63}, +{0xd7,0x31,0xdc,0xca}, {0x42,0x63,0x85,0x10}, {0x13,0x97,0x22,0x40}, {0x84,0xc6,0x11,0x20}, +{0x85,0x4a,0x24,0x7d}, {0xd2,0xbb,0x3d,0xf8}, {0xae,0xf9,0x32,0x11}, {0xc7,0x29,0xa1,0x6d}, +{0x1d,0x9e,0x2f,0x4b}, {0xdc,0xb2,0x30,0xf3}, {0x0d,0x86,0x52,0xec}, {0x77,0xc1,0xe3,0xd0}, +{0x2b,0xb3,0x16,0x6c}, {0xa9,0x70,0xb9,0x99}, {0x11,0x94,0x48,0xfa}, {0x47,0xe9,0x64,0x22}, +{0xa8,0xfc,0x8c,0xc4}, {0xa0,0xf0,0x3f,0x1a}, {0x56,0x7d,0x2c,0xd8}, {0x22,0x33,0x90,0xef}, +{0x87,0x49,0x4e,0xc7}, {0xd9,0x38,0xd1,0xc1}, {0x8c,0xca,0xa2,0xfe}, {0x98,0xd4,0x0b,0x36}, +{0xa6,0xf5,0x81,0xcf}, {0xa5,0x7a,0xde,0x28}, {0xda,0xb7,0x8e,0x26}, {0x3f,0xad,0xbf,0xa4}, +{0x2c,0x3a,0x9d,0xe4}, {0x50,0x78,0x92,0x0d}, {0x6a,0x5f,0xcc,0x9b}, {0x54,0x7e,0x46,0x62}, +{0xf6,0x8d,0x13,0xc2}, {0x90,0xd8,0xb8,0xe8}, {0x2e,0x39,0xf7,0x5e}, {0x82,0xc3,0xaf,0xf5}, +{0x9f,0x5d,0x80,0xbe}, {0x69,0xd0,0x93,0x7c}, {0x6f,0xd5,0x2d,0xa9}, {0xcf,0x25,0x12,0xb3}, +{0xc8,0xac,0x99,0x3b}, {0x10,0x18,0x7d,0xa7}, {0xe8,0x9c,0x63,0x6e}, {0xdb,0x3b,0xbb,0x7b}, +{0xcd,0x26,0x78,0x09}, {0x6e,0x59,0x18,0xf4}, {0xec,0x9a,0xb7,0x01}, {0x83,0x4f,0x9a,0xa8}, +{0xe6,0x95,0x6e,0x65}, {0xaa,0xff,0xe6,0x7e}, {0x21,0xbc,0xcf,0x08}, {0xef,0x15,0xe8,0xe6}, +{0xba,0xe7,0x9b,0xd9}, {0x4a,0x6f,0x36,0xce}, {0xea,0x9f,0x09,0xd4}, {0x29,0xb0,0x7c,0xd6}, +{0x31,0xa4,0xb2,0xaf}, {0x2a,0x3f,0x23,0x31}, {0xc6,0xa5,0x94,0x30}, {0x35,0xa2,0x66,0xc0}, +{0x74,0x4e,0xbc,0x37}, {0xfc,0x82,0xca,0xa6}, {0xe0,0x90,0xd0,0xb0}, {0x33,0xa7,0xd8,0x15}, +{0xf1,0x04,0x98,0x4a}, {0x41,0xec,0xda,0xf7}, {0x7f,0xcd,0x50,0x0e}, {0x17,0x91,0xf6,0x2f}, +{0x76,0x4d,0xd6,0x8d}, {0x43,0xef,0xb0,0x4d}, {0xcc,0xaa,0x4d,0x54}, {0xe4,0x96,0x04,0xdf}, +{0x9e,0xd1,0xb5,0xe3}, {0x4c,0x6a,0x88,0x1b}, {0xc1,0x2c,0x1f,0xb8}, {0x46,0x65,0x51,0x7f}, +{0x9d,0x5e,0xea,0x04}, {0x01,0x8c,0x35,0x5d}, {0xfa,0x87,0x74,0x73}, {0xfb,0x0b,0x41,0x2e}, +{0xb3,0x67,0x1d,0x5a}, {0x92,0xdb,0xd2,0x52}, {0xe9,0x10,0x56,0x33}, {0x6d,0xd6,0x47,0x13}, +{0x9a,0xd7,0x61,0x8c}, {0x37,0xa1,0x0c,0x7a}, {0x59,0xf8,0x14,0x8e}, {0xeb,0x13,0x3c,0x89}, +{0xce,0xa9,0x27,0xee}, {0xb7,0x61,0xc9,0x35}, {0xe1,0x1c,0xe5,0xed}, {0x7a,0x47,0xb1,0x3c}, +{0x9c,0xd2,0xdf,0x59}, {0x55,0xf2,0x73,0x3f}, {0x18,0x14,0xce,0x79}, {0x73,0xc7,0x37,0xbf}, +{0x53,0xf7,0xcd,0xea}, {0x5f,0xfd,0xaa,0x5b}, {0xdf,0x3d,0x6f,0x14}, {0x78,0x44,0xdb,0x86}, +{0xca,0xaf,0xf3,0x81}, {0xb9,0x68,0xc4,0x3e}, {0x38,0x24,0x34,0x2c}, {0xc2,0xa3,0x40,0x5f}, +{0x16,0x1d,0xc3,0x72}, {0xbc,0xe2,0x25,0x0c}, {0x28,0x3c,0x49,0x8b}, {0xff,0x0d,0x95,0x41}, +{0x39,0xa8,0x01,0x71}, {0x08,0x0c,0xb3,0xde}, {0xd8,0xb4,0xe4,0x9c}, {0x64,0x56,0xc1,0x90}, +{0x7b,0xcb,0x84,0x61}, {0xd5,0x32,0xb6,0x70}, {0x48,0x6c,0x5c,0x74}, {0xd0,0xb8,0x57,0x42} + } +}; +#define T5 xT5.xt8 + +static const union xtab xT6 = { + .xt8 = { +{0x50,0x51,0xf4,0xa7}, {0x53,0x7e,0x41,0x65}, {0xc3,0x1a,0x17,0xa4}, {0x96,0x3a,0x27,0x5e}, +{0xcb,0x3b,0xab,0x6b}, {0xf1,0x1f,0x9d,0x45}, {0xab,0xac,0xfa,0x58}, {0x93,0x4b,0xe3,0x03}, +{0x55,0x20,0x30,0xfa}, {0xf6,0xad,0x76,0x6d}, {0x91,0x88,0xcc,0x76}, {0x25,0xf5,0x02,0x4c}, +{0xfc,0x4f,0xe5,0xd7}, {0xd7,0xc5,0x2a,0xcb}, {0x80,0x26,0x35,0x44}, {0x8f,0xb5,0x62,0xa3}, +{0x49,0xde,0xb1,0x5a}, {0x67,0x25,0xba,0x1b}, {0x98,0x45,0xea,0x0e}, {0xe1,0x5d,0xfe,0xc0}, +{0x02,0xc3,0x2f,0x75}, {0x12,0x81,0x4c,0xf0}, {0xa3,0x8d,0x46,0x97}, {0xc6,0x6b,0xd3,0xf9}, +{0xe7,0x03,0x8f,0x5f}, {0x95,0x15,0x92,0x9c}, {0xeb,0xbf,0x6d,0x7a}, {0xda,0x95,0x52,0x59}, +{0x2d,0xd4,0xbe,0x83}, {0xd3,0x58,0x74,0x21}, {0x29,0x49,0xe0,0x69}, {0x44,0x8e,0xc9,0xc8}, +{0x6a,0x75,0xc2,0x89}, {0x78,0xf4,0x8e,0x79}, {0x6b,0x99,0x58,0x3e}, {0xdd,0x27,0xb9,0x71}, +{0xb6,0xbe,0xe1,0x4f}, {0x17,0xf0,0x88,0xad}, {0x66,0xc9,0x20,0xac}, {0xb4,0x7d,0xce,0x3a}, +{0x18,0x63,0xdf,0x4a}, {0x82,0xe5,0x1a,0x31}, {0x60,0x97,0x51,0x33}, {0x45,0x62,0x53,0x7f}, +{0xe0,0xb1,0x64,0x77}, {0x84,0xbb,0x6b,0xae}, {0x1c,0xfe,0x81,0xa0}, {0x94,0xf9,0x08,0x2b}, +{0x58,0x70,0x48,0x68}, {0x19,0x8f,0x45,0xfd}, {0x87,0x94,0xde,0x6c}, {0xb7,0x52,0x7b,0xf8}, +{0x23,0xab,0x73,0xd3}, {0xe2,0x72,0x4b,0x02}, {0x57,0xe3,0x1f,0x8f}, {0x2a,0x66,0x55,0xab}, +{0x07,0xb2,0xeb,0x28}, {0x03,0x2f,0xb5,0xc2}, {0x9a,0x86,0xc5,0x7b}, {0xa5,0xd3,0x37,0x08}, +{0xf2,0x30,0x28,0x87}, {0xb2,0x23,0xbf,0xa5}, {0xba,0x02,0x03,0x6a}, {0x5c,0xed,0x16,0x82}, +{0x2b,0x8a,0xcf,0x1c}, {0x92,0xa7,0x79,0xb4}, {0xf0,0xf3,0x07,0xf2}, {0xa1,0x4e,0x69,0xe2}, +{0xcd,0x65,0xda,0xf4}, {0xd5,0x06,0x05,0xbe}, {0x1f,0xd1,0x34,0x62}, {0x8a,0xc4,0xa6,0xfe}, +{0x9d,0x34,0x2e,0x53}, {0xa0,0xa2,0xf3,0x55}, {0x32,0x05,0x8a,0xe1}, {0x75,0xa4,0xf6,0xeb}, +{0x39,0x0b,0x83,0xec}, {0xaa,0x40,0x60,0xef}, {0x06,0x5e,0x71,0x9f}, {0x51,0xbd,0x6e,0x10}, +{0xf9,0x3e,0x21,0x8a}, {0x3d,0x96,0xdd,0x06}, {0xae,0xdd,0x3e,0x05}, {0x46,0x4d,0xe6,0xbd}, +{0xb5,0x91,0x54,0x8d}, {0x05,0x71,0xc4,0x5d}, {0x6f,0x04,0x06,0xd4}, {0xff,0x60,0x50,0x15}, +{0x24,0x19,0x98,0xfb}, {0x97,0xd6,0xbd,0xe9}, {0xcc,0x89,0x40,0x43}, {0x77,0x67,0xd9,0x9e}, +{0xbd,0xb0,0xe8,0x42}, {0x88,0x07,0x89,0x8b}, {0x38,0xe7,0x19,0x5b}, {0xdb,0x79,0xc8,0xee}, +{0x47,0xa1,0x7c,0x0a}, {0xe9,0x7c,0x42,0x0f}, {0xc9,0xf8,0x84,0x1e}, {0x00,0x00,0x00,0x00}, +{0x83,0x09,0x80,0x86}, {0x48,0x32,0x2b,0xed}, {0xac,0x1e,0x11,0x70}, {0x4e,0x6c,0x5a,0x72}, +{0xfb,0xfd,0x0e,0xff}, {0x56,0x0f,0x85,0x38}, {0x1e,0x3d,0xae,0xd5}, {0x27,0x36,0x2d,0x39}, +{0x64,0x0a,0x0f,0xd9}, {0x21,0x68,0x5c,0xa6}, {0xd1,0x9b,0x5b,0x54}, {0x3a,0x24,0x36,0x2e}, +{0xb1,0x0c,0x0a,0x67}, {0x0f,0x93,0x57,0xe7}, {0xd2,0xb4,0xee,0x96}, {0x9e,0x1b,0x9b,0x91}, +{0x4f,0x80,0xc0,0xc5}, {0xa2,0x61,0xdc,0x20}, {0x69,0x5a,0x77,0x4b}, {0x16,0x1c,0x12,0x1a}, +{0x0a,0xe2,0x93,0xba}, {0xe5,0xc0,0xa0,0x2a}, {0x43,0x3c,0x22,0xe0}, {0x1d,0x12,0x1b,0x17}, +{0x0b,0x0e,0x09,0x0d}, {0xad,0xf2,0x8b,0xc7}, {0xb9,0x2d,0xb6,0xa8}, {0xc8,0x14,0x1e,0xa9}, +{0x85,0x57,0xf1,0x19}, {0x4c,0xaf,0x75,0x07}, {0xbb,0xee,0x99,0xdd}, {0xfd,0xa3,0x7f,0x60}, +{0x9f,0xf7,0x01,0x26}, {0xbc,0x5c,0x72,0xf5}, {0xc5,0x44,0x66,0x3b}, {0x34,0x5b,0xfb,0x7e}, +{0x76,0x8b,0x43,0x29}, {0xdc,0xcb,0x23,0xc6}, {0x68,0xb6,0xed,0xfc}, {0x63,0xb8,0xe4,0xf1}, +{0xca,0xd7,0x31,0xdc}, {0x10,0x42,0x63,0x85}, {0x40,0x13,0x97,0x22}, {0x20,0x84,0xc6,0x11}, +{0x7d,0x85,0x4a,0x24}, {0xf8,0xd2,0xbb,0x3d}, {0x11,0xae,0xf9,0x32}, {0x6d,0xc7,0x29,0xa1}, +{0x4b,0x1d,0x9e,0x2f}, {0xf3,0xdc,0xb2,0x30}, {0xec,0x0d,0x86,0x52}, {0xd0,0x77,0xc1,0xe3}, +{0x6c,0x2b,0xb3,0x16}, {0x99,0xa9,0x70,0xb9}, {0xfa,0x11,0x94,0x48}, {0x22,0x47,0xe9,0x64}, +{0xc4,0xa8,0xfc,0x8c}, {0x1a,0xa0,0xf0,0x3f}, {0xd8,0x56,0x7d,0x2c}, {0xef,0x22,0x33,0x90}, +{0xc7,0x87,0x49,0x4e}, {0xc1,0xd9,0x38,0xd1}, {0xfe,0x8c,0xca,0xa2}, {0x36,0x98,0xd4,0x0b}, +{0xcf,0xa6,0xf5,0x81}, {0x28,0xa5,0x7a,0xde}, {0x26,0xda,0xb7,0x8e}, {0xa4,0x3f,0xad,0xbf}, +{0xe4,0x2c,0x3a,0x9d}, {0x0d,0x50,0x78,0x92}, {0x9b,0x6a,0x5f,0xcc}, {0x62,0x54,0x7e,0x46}, +{0xc2,0xf6,0x8d,0x13}, {0xe8,0x90,0xd8,0xb8}, {0x5e,0x2e,0x39,0xf7}, {0xf5,0x82,0xc3,0xaf}, +{0xbe,0x9f,0x5d,0x80}, {0x7c,0x69,0xd0,0x93}, {0xa9,0x6f,0xd5,0x2d}, {0xb3,0xcf,0x25,0x12}, +{0x3b,0xc8,0xac,0x99}, {0xa7,0x10,0x18,0x7d}, {0x6e,0xe8,0x9c,0x63}, {0x7b,0xdb,0x3b,0xbb}, +{0x09,0xcd,0x26,0x78}, {0xf4,0x6e,0x59,0x18}, {0x01,0xec,0x9a,0xb7}, {0xa8,0x83,0x4f,0x9a}, +{0x65,0xe6,0x95,0x6e}, {0x7e,0xaa,0xff,0xe6}, {0x08,0x21,0xbc,0xcf}, {0xe6,0xef,0x15,0xe8}, +{0xd9,0xba,0xe7,0x9b}, {0xce,0x4a,0x6f,0x36}, {0xd4,0xea,0x9f,0x09}, {0xd6,0x29,0xb0,0x7c}, +{0xaf,0x31,0xa4,0xb2}, {0x31,0x2a,0x3f,0x23}, {0x30,0xc6,0xa5,0x94}, {0xc0,0x35,0xa2,0x66}, +{0x37,0x74,0x4e,0xbc}, {0xa6,0xfc,0x82,0xca}, {0xb0,0xe0,0x90,0xd0}, {0x15,0x33,0xa7,0xd8}, +{0x4a,0xf1,0x04,0x98}, {0xf7,0x41,0xec,0xda}, {0x0e,0x7f,0xcd,0x50}, {0x2f,0x17,0x91,0xf6}, +{0x8d,0x76,0x4d,0xd6}, {0x4d,0x43,0xef,0xb0}, {0x54,0xcc,0xaa,0x4d}, {0xdf,0xe4,0x96,0x04}, +{0xe3,0x9e,0xd1,0xb5}, {0x1b,0x4c,0x6a,0x88}, {0xb8,0xc1,0x2c,0x1f}, {0x7f,0x46,0x65,0x51}, +{0x04,0x9d,0x5e,0xea}, {0x5d,0x01,0x8c,0x35}, {0x73,0xfa,0x87,0x74}, {0x2e,0xfb,0x0b,0x41}, +{0x5a,0xb3,0x67,0x1d}, {0x52,0x92,0xdb,0xd2}, {0x33,0xe9,0x10,0x56}, {0x13,0x6d,0xd6,0x47}, +{0x8c,0x9a,0xd7,0x61}, {0x7a,0x37,0xa1,0x0c}, {0x8e,0x59,0xf8,0x14}, {0x89,0xeb,0x13,0x3c}, +{0xee,0xce,0xa9,0x27}, {0x35,0xb7,0x61,0xc9}, {0xed,0xe1,0x1c,0xe5}, {0x3c,0x7a,0x47,0xb1}, +{0x59,0x9c,0xd2,0xdf}, {0x3f,0x55,0xf2,0x73}, {0x79,0x18,0x14,0xce}, {0xbf,0x73,0xc7,0x37}, +{0xea,0x53,0xf7,0xcd}, {0x5b,0x5f,0xfd,0xaa}, {0x14,0xdf,0x3d,0x6f}, {0x86,0x78,0x44,0xdb}, +{0x81,0xca,0xaf,0xf3}, {0x3e,0xb9,0x68,0xc4}, {0x2c,0x38,0x24,0x34}, {0x5f,0xc2,0xa3,0x40}, +{0x72,0x16,0x1d,0xc3}, {0x0c,0xbc,0xe2,0x25}, {0x8b,0x28,0x3c,0x49}, {0x41,0xff,0x0d,0x95}, +{0x71,0x39,0xa8,0x01}, {0xde,0x08,0x0c,0xb3}, {0x9c,0xd8,0xb4,0xe4}, {0x90,0x64,0x56,0xc1}, +{0x61,0x7b,0xcb,0x84}, {0x70,0xd5,0x32,0xb6}, {0x74,0x48,0x6c,0x5c}, {0x42,0xd0,0xb8,0x57} + } +}; +#define T6 xT6.xt8 + +static const union xtab xT7 = { + .xt8 = { +{0xa7,0x50,0x51,0xf4}, {0x65,0x53,0x7e,0x41}, {0xa4,0xc3,0x1a,0x17}, {0x5e,0x96,0x3a,0x27}, +{0x6b,0xcb,0x3b,0xab}, {0x45,0xf1,0x1f,0x9d}, {0x58,0xab,0xac,0xfa}, {0x03,0x93,0x4b,0xe3}, +{0xfa,0x55,0x20,0x30}, {0x6d,0xf6,0xad,0x76}, {0x76,0x91,0x88,0xcc}, {0x4c,0x25,0xf5,0x02}, +{0xd7,0xfc,0x4f,0xe5}, {0xcb,0xd7,0xc5,0x2a}, {0x44,0x80,0x26,0x35}, {0xa3,0x8f,0xb5,0x62}, +{0x5a,0x49,0xde,0xb1}, {0x1b,0x67,0x25,0xba}, {0x0e,0x98,0x45,0xea}, {0xc0,0xe1,0x5d,0xfe}, +{0x75,0x02,0xc3,0x2f}, {0xf0,0x12,0x81,0x4c}, {0x97,0xa3,0x8d,0x46}, {0xf9,0xc6,0x6b,0xd3}, +{0x5f,0xe7,0x03,0x8f}, {0x9c,0x95,0x15,0x92}, {0x7a,0xeb,0xbf,0x6d}, {0x59,0xda,0x95,0x52}, +{0x83,0x2d,0xd4,0xbe}, {0x21,0xd3,0x58,0x74}, {0x69,0x29,0x49,0xe0}, {0xc8,0x44,0x8e,0xc9}, +{0x89,0x6a,0x75,0xc2}, {0x79,0x78,0xf4,0x8e}, {0x3e,0x6b,0x99,0x58}, {0x71,0xdd,0x27,0xb9}, +{0x4f,0xb6,0xbe,0xe1}, {0xad,0x17,0xf0,0x88}, {0xac,0x66,0xc9,0x20}, {0x3a,0xb4,0x7d,0xce}, +{0x4a,0x18,0x63,0xdf}, {0x31,0x82,0xe5,0x1a}, {0x33,0x60,0x97,0x51}, {0x7f,0x45,0x62,0x53}, +{0x77,0xe0,0xb1,0x64}, {0xae,0x84,0xbb,0x6b}, {0xa0,0x1c,0xfe,0x81}, {0x2b,0x94,0xf9,0x08}, +{0x68,0x58,0x70,0x48}, {0xfd,0x19,0x8f,0x45}, {0x6c,0x87,0x94,0xde}, {0xf8,0xb7,0x52,0x7b}, +{0xd3,0x23,0xab,0x73}, {0x02,0xe2,0x72,0x4b}, {0x8f,0x57,0xe3,0x1f}, {0xab,0x2a,0x66,0x55}, +{0x28,0x07,0xb2,0xeb}, {0xc2,0x03,0x2f,0xb5}, {0x7b,0x9a,0x86,0xc5}, {0x08,0xa5,0xd3,0x37}, +{0x87,0xf2,0x30,0x28}, {0xa5,0xb2,0x23,0xbf}, {0x6a,0xba,0x02,0x03}, {0x82,0x5c,0xed,0x16}, +{0x1c,0x2b,0x8a,0xcf}, {0xb4,0x92,0xa7,0x79}, {0xf2,0xf0,0xf3,0x07}, {0xe2,0xa1,0x4e,0x69}, +{0xf4,0xcd,0x65,0xda}, {0xbe,0xd5,0x06,0x05}, {0x62,0x1f,0xd1,0x34}, {0xfe,0x8a,0xc4,0xa6}, +{0x53,0x9d,0x34,0x2e}, {0x55,0xa0,0xa2,0xf3}, {0xe1,0x32,0x05,0x8a}, {0xeb,0x75,0xa4,0xf6}, +{0xec,0x39,0x0b,0x83}, {0xef,0xaa,0x40,0x60}, {0x9f,0x06,0x5e,0x71}, {0x10,0x51,0xbd,0x6e}, +{0x8a,0xf9,0x3e,0x21}, {0x06,0x3d,0x96,0xdd}, {0x05,0xae,0xdd,0x3e}, {0xbd,0x46,0x4d,0xe6}, +{0x8d,0xb5,0x91,0x54}, {0x5d,0x05,0x71,0xc4}, {0xd4,0x6f,0x04,0x06}, {0x15,0xff,0x60,0x50}, +{0xfb,0x24,0x19,0x98}, {0xe9,0x97,0xd6,0xbd}, {0x43,0xcc,0x89,0x40}, {0x9e,0x77,0x67,0xd9}, +{0x42,0xbd,0xb0,0xe8}, {0x8b,0x88,0x07,0x89}, {0x5b,0x38,0xe7,0x19}, {0xee,0xdb,0x79,0xc8}, +{0x0a,0x47,0xa1,0x7c}, {0x0f,0xe9,0x7c,0x42}, {0x1e,0xc9,0xf8,0x84}, {0x00,0x00,0x00,0x00}, +{0x86,0x83,0x09,0x80}, {0xed,0x48,0x32,0x2b}, {0x70,0xac,0x1e,0x11}, {0x72,0x4e,0x6c,0x5a}, +{0xff,0xfb,0xfd,0x0e}, {0x38,0x56,0x0f,0x85}, {0xd5,0x1e,0x3d,0xae}, {0x39,0x27,0x36,0x2d}, +{0xd9,0x64,0x0a,0x0f}, {0xa6,0x21,0x68,0x5c}, {0x54,0xd1,0x9b,0x5b}, {0x2e,0x3a,0x24,0x36}, +{0x67,0xb1,0x0c,0x0a}, {0xe7,0x0f,0x93,0x57}, {0x96,0xd2,0xb4,0xee}, {0x91,0x9e,0x1b,0x9b}, +{0xc5,0x4f,0x80,0xc0}, {0x20,0xa2,0x61,0xdc}, {0x4b,0x69,0x5a,0x77}, {0x1a,0x16,0x1c,0x12}, +{0xba,0x0a,0xe2,0x93}, {0x2a,0xe5,0xc0,0xa0}, {0xe0,0x43,0x3c,0x22}, {0x17,0x1d,0x12,0x1b}, +{0x0d,0x0b,0x0e,0x09}, {0xc7,0xad,0xf2,0x8b}, {0xa8,0xb9,0x2d,0xb6}, {0xa9,0xc8,0x14,0x1e}, +{0x19,0x85,0x57,0xf1}, {0x07,0x4c,0xaf,0x75}, {0xdd,0xbb,0xee,0x99}, {0x60,0xfd,0xa3,0x7f}, +{0x26,0x9f,0xf7,0x01}, {0xf5,0xbc,0x5c,0x72}, {0x3b,0xc5,0x44,0x66}, {0x7e,0x34,0x5b,0xfb}, +{0x29,0x76,0x8b,0x43}, {0xc6,0xdc,0xcb,0x23}, {0xfc,0x68,0xb6,0xed}, {0xf1,0x63,0xb8,0xe4}, +{0xdc,0xca,0xd7,0x31}, {0x85,0x10,0x42,0x63}, {0x22,0x40,0x13,0x97}, {0x11,0x20,0x84,0xc6}, +{0x24,0x7d,0x85,0x4a}, {0x3d,0xf8,0xd2,0xbb}, {0x32,0x11,0xae,0xf9}, {0xa1,0x6d,0xc7,0x29}, +{0x2f,0x4b,0x1d,0x9e}, {0x30,0xf3,0xdc,0xb2}, {0x52,0xec,0x0d,0x86}, {0xe3,0xd0,0x77,0xc1}, +{0x16,0x6c,0x2b,0xb3}, {0xb9,0x99,0xa9,0x70}, {0x48,0xfa,0x11,0x94}, {0x64,0x22,0x47,0xe9}, +{0x8c,0xc4,0xa8,0xfc}, {0x3f,0x1a,0xa0,0xf0}, {0x2c,0xd8,0x56,0x7d}, {0x90,0xef,0x22,0x33}, +{0x4e,0xc7,0x87,0x49}, {0xd1,0xc1,0xd9,0x38}, {0xa2,0xfe,0x8c,0xca}, {0x0b,0x36,0x98,0xd4}, +{0x81,0xcf,0xa6,0xf5}, {0xde,0x28,0xa5,0x7a}, {0x8e,0x26,0xda,0xb7}, {0xbf,0xa4,0x3f,0xad}, +{0x9d,0xe4,0x2c,0x3a}, {0x92,0x0d,0x50,0x78}, {0xcc,0x9b,0x6a,0x5f}, {0x46,0x62,0x54,0x7e}, +{0x13,0xc2,0xf6,0x8d}, {0xb8,0xe8,0x90,0xd8}, {0xf7,0x5e,0x2e,0x39}, {0xaf,0xf5,0x82,0xc3}, +{0x80,0xbe,0x9f,0x5d}, {0x93,0x7c,0x69,0xd0}, {0x2d,0xa9,0x6f,0xd5}, {0x12,0xb3,0xcf,0x25}, +{0x99,0x3b,0xc8,0xac}, {0x7d,0xa7,0x10,0x18}, {0x63,0x6e,0xe8,0x9c}, {0xbb,0x7b,0xdb,0x3b}, +{0x78,0x09,0xcd,0x26}, {0x18,0xf4,0x6e,0x59}, {0xb7,0x01,0xec,0x9a}, {0x9a,0xa8,0x83,0x4f}, +{0x6e,0x65,0xe6,0x95}, {0xe6,0x7e,0xaa,0xff}, {0xcf,0x08,0x21,0xbc}, {0xe8,0xe6,0xef,0x15}, +{0x9b,0xd9,0xba,0xe7}, {0x36,0xce,0x4a,0x6f}, {0x09,0xd4,0xea,0x9f}, {0x7c,0xd6,0x29,0xb0}, +{0xb2,0xaf,0x31,0xa4}, {0x23,0x31,0x2a,0x3f}, {0x94,0x30,0xc6,0xa5}, {0x66,0xc0,0x35,0xa2}, +{0xbc,0x37,0x74,0x4e}, {0xca,0xa6,0xfc,0x82}, {0xd0,0xb0,0xe0,0x90}, {0xd8,0x15,0x33,0xa7}, +{0x98,0x4a,0xf1,0x04}, {0xda,0xf7,0x41,0xec}, {0x50,0x0e,0x7f,0xcd}, {0xf6,0x2f,0x17,0x91}, +{0xd6,0x8d,0x76,0x4d}, {0xb0,0x4d,0x43,0xef}, {0x4d,0x54,0xcc,0xaa}, {0x04,0xdf,0xe4,0x96}, +{0xb5,0xe3,0x9e,0xd1}, {0x88,0x1b,0x4c,0x6a}, {0x1f,0xb8,0xc1,0x2c}, {0x51,0x7f,0x46,0x65}, +{0xea,0x04,0x9d,0x5e}, {0x35,0x5d,0x01,0x8c}, {0x74,0x73,0xfa,0x87}, {0x41,0x2e,0xfb,0x0b}, +{0x1d,0x5a,0xb3,0x67}, {0xd2,0x52,0x92,0xdb}, {0x56,0x33,0xe9,0x10}, {0x47,0x13,0x6d,0xd6}, +{0x61,0x8c,0x9a,0xd7}, {0x0c,0x7a,0x37,0xa1}, {0x14,0x8e,0x59,0xf8}, {0x3c,0x89,0xeb,0x13}, +{0x27,0xee,0xce,0xa9}, {0xc9,0x35,0xb7,0x61}, {0xe5,0xed,0xe1,0x1c}, {0xb1,0x3c,0x7a,0x47}, +{0xdf,0x59,0x9c,0xd2}, {0x73,0x3f,0x55,0xf2}, {0xce,0x79,0x18,0x14}, {0x37,0xbf,0x73,0xc7}, +{0xcd,0xea,0x53,0xf7}, {0xaa,0x5b,0x5f,0xfd}, {0x6f,0x14,0xdf,0x3d}, {0xdb,0x86,0x78,0x44}, +{0xf3,0x81,0xca,0xaf}, {0xc4,0x3e,0xb9,0x68}, {0x34,0x2c,0x38,0x24}, {0x40,0x5f,0xc2,0xa3}, +{0xc3,0x72,0x16,0x1d}, {0x25,0x0c,0xbc,0xe2}, {0x49,0x8b,0x28,0x3c}, {0x95,0x41,0xff,0x0d}, +{0x01,0x71,0x39,0xa8}, {0xb3,0xde,0x08,0x0c}, {0xe4,0x9c,0xd8,0xb4}, {0xc1,0x90,0x64,0x56}, +{0x84,0x61,0x7b,0xcb}, {0xb6,0x70,0xd5,0x32}, {0x5c,0x74,0x48,0x6c}, {0x57,0x42,0xd0,0xb8} + } +}; +#define T7 xT7.xt8 + +static const union xtab xT8 = { + .xt8 = { +{0xf4,0xa7,0x50,0x51}, {0x41,0x65,0x53,0x7e}, {0x17,0xa4,0xc3,0x1a}, {0x27,0x5e,0x96,0x3a}, +{0xab,0x6b,0xcb,0x3b}, {0x9d,0x45,0xf1,0x1f}, {0xfa,0x58,0xab,0xac}, {0xe3,0x03,0x93,0x4b}, +{0x30,0xfa,0x55,0x20}, {0x76,0x6d,0xf6,0xad}, {0xcc,0x76,0x91,0x88}, {0x02,0x4c,0x25,0xf5}, +{0xe5,0xd7,0xfc,0x4f}, {0x2a,0xcb,0xd7,0xc5}, {0x35,0x44,0x80,0x26}, {0x62,0xa3,0x8f,0xb5}, +{0xb1,0x5a,0x49,0xde}, {0xba,0x1b,0x67,0x25}, {0xea,0x0e,0x98,0x45}, {0xfe,0xc0,0xe1,0x5d}, +{0x2f,0x75,0x02,0xc3}, {0x4c,0xf0,0x12,0x81}, {0x46,0x97,0xa3,0x8d}, {0xd3,0xf9,0xc6,0x6b}, +{0x8f,0x5f,0xe7,0x03}, {0x92,0x9c,0x95,0x15}, {0x6d,0x7a,0xeb,0xbf}, {0x52,0x59,0xda,0x95}, +{0xbe,0x83,0x2d,0xd4}, {0x74,0x21,0xd3,0x58}, {0xe0,0x69,0x29,0x49}, {0xc9,0xc8,0x44,0x8e}, +{0xc2,0x89,0x6a,0x75}, {0x8e,0x79,0x78,0xf4}, {0x58,0x3e,0x6b,0x99}, {0xb9,0x71,0xdd,0x27}, +{0xe1,0x4f,0xb6,0xbe}, {0x88,0xad,0x17,0xf0}, {0x20,0xac,0x66,0xc9}, {0xce,0x3a,0xb4,0x7d}, +{0xdf,0x4a,0x18,0x63}, {0x1a,0x31,0x82,0xe5}, {0x51,0x33,0x60,0x97}, {0x53,0x7f,0x45,0x62}, +{0x64,0x77,0xe0,0xb1}, {0x6b,0xae,0x84,0xbb}, {0x81,0xa0,0x1c,0xfe}, {0x08,0x2b,0x94,0xf9}, +{0x48,0x68,0x58,0x70}, {0x45,0xfd,0x19,0x8f}, {0xde,0x6c,0x87,0x94}, {0x7b,0xf8,0xb7,0x52}, +{0x73,0xd3,0x23,0xab}, {0x4b,0x02,0xe2,0x72}, {0x1f,0x8f,0x57,0xe3}, {0x55,0xab,0x2a,0x66}, +{0xeb,0x28,0x07,0xb2}, {0xb5,0xc2,0x03,0x2f}, {0xc5,0x7b,0x9a,0x86}, {0x37,0x08,0xa5,0xd3}, +{0x28,0x87,0xf2,0x30}, {0xbf,0xa5,0xb2,0x23}, {0x03,0x6a,0xba,0x02}, {0x16,0x82,0x5c,0xed}, +{0xcf,0x1c,0x2b,0x8a}, {0x79,0xb4,0x92,0xa7}, {0x07,0xf2,0xf0,0xf3}, {0x69,0xe2,0xa1,0x4e}, +{0xda,0xf4,0xcd,0x65}, {0x05,0xbe,0xd5,0x06}, {0x34,0x62,0x1f,0xd1}, {0xa6,0xfe,0x8a,0xc4}, +{0x2e,0x53,0x9d,0x34}, {0xf3,0x55,0xa0,0xa2}, {0x8a,0xe1,0x32,0x05}, {0xf6,0xeb,0x75,0xa4}, +{0x83,0xec,0x39,0x0b}, {0x60,0xef,0xaa,0x40}, {0x71,0x9f,0x06,0x5e}, {0x6e,0x10,0x51,0xbd}, +{0x21,0x8a,0xf9,0x3e}, {0xdd,0x06,0x3d,0x96}, {0x3e,0x05,0xae,0xdd}, {0xe6,0xbd,0x46,0x4d}, +{0x54,0x8d,0xb5,0x91}, {0xc4,0x5d,0x05,0x71}, {0x06,0xd4,0x6f,0x04}, {0x50,0x15,0xff,0x60}, +{0x98,0xfb,0x24,0x19}, {0xbd,0xe9,0x97,0xd6}, {0x40,0x43,0xcc,0x89}, {0xd9,0x9e,0x77,0x67}, +{0xe8,0x42,0xbd,0xb0}, {0x89,0x8b,0x88,0x07}, {0x19,0x5b,0x38,0xe7}, {0xc8,0xee,0xdb,0x79}, +{0x7c,0x0a,0x47,0xa1}, {0x42,0x0f,0xe9,0x7c}, {0x84,0x1e,0xc9,0xf8}, {0x00,0x00,0x00,0x00}, +{0x80,0x86,0x83,0x09}, {0x2b,0xed,0x48,0x32}, {0x11,0x70,0xac,0x1e}, {0x5a,0x72,0x4e,0x6c}, +{0x0e,0xff,0xfb,0xfd}, {0x85,0x38,0x56,0x0f}, {0xae,0xd5,0x1e,0x3d}, {0x2d,0x39,0x27,0x36}, +{0x0f,0xd9,0x64,0x0a}, {0x5c,0xa6,0x21,0x68}, {0x5b,0x54,0xd1,0x9b}, {0x36,0x2e,0x3a,0x24}, +{0x0a,0x67,0xb1,0x0c}, {0x57,0xe7,0x0f,0x93}, {0xee,0x96,0xd2,0xb4}, {0x9b,0x91,0x9e,0x1b}, +{0xc0,0xc5,0x4f,0x80}, {0xdc,0x20,0xa2,0x61}, {0x77,0x4b,0x69,0x5a}, {0x12,0x1a,0x16,0x1c}, +{0x93,0xba,0x0a,0xe2}, {0xa0,0x2a,0xe5,0xc0}, {0x22,0xe0,0x43,0x3c}, {0x1b,0x17,0x1d,0x12}, +{0x09,0x0d,0x0b,0x0e}, {0x8b,0xc7,0xad,0xf2}, {0xb6,0xa8,0xb9,0x2d}, {0x1e,0xa9,0xc8,0x14}, +{0xf1,0x19,0x85,0x57}, {0x75,0x07,0x4c,0xaf}, {0x99,0xdd,0xbb,0xee}, {0x7f,0x60,0xfd,0xa3}, +{0x01,0x26,0x9f,0xf7}, {0x72,0xf5,0xbc,0x5c}, {0x66,0x3b,0xc5,0x44}, {0xfb,0x7e,0x34,0x5b}, +{0x43,0x29,0x76,0x8b}, {0x23,0xc6,0xdc,0xcb}, {0xed,0xfc,0x68,0xb6}, {0xe4,0xf1,0x63,0xb8}, +{0x31,0xdc,0xca,0xd7}, {0x63,0x85,0x10,0x42}, {0x97,0x22,0x40,0x13}, {0xc6,0x11,0x20,0x84}, +{0x4a,0x24,0x7d,0x85}, {0xbb,0x3d,0xf8,0xd2}, {0xf9,0x32,0x11,0xae}, {0x29,0xa1,0x6d,0xc7}, +{0x9e,0x2f,0x4b,0x1d}, {0xb2,0x30,0xf3,0xdc}, {0x86,0x52,0xec,0x0d}, {0xc1,0xe3,0xd0,0x77}, +{0xb3,0x16,0x6c,0x2b}, {0x70,0xb9,0x99,0xa9}, {0x94,0x48,0xfa,0x11}, {0xe9,0x64,0x22,0x47}, +{0xfc,0x8c,0xc4,0xa8}, {0xf0,0x3f,0x1a,0xa0}, {0x7d,0x2c,0xd8,0x56}, {0x33,0x90,0xef,0x22}, +{0x49,0x4e,0xc7,0x87}, {0x38,0xd1,0xc1,0xd9}, {0xca,0xa2,0xfe,0x8c}, {0xd4,0x0b,0x36,0x98}, +{0xf5,0x81,0xcf,0xa6}, {0x7a,0xde,0x28,0xa5}, {0xb7,0x8e,0x26,0xda}, {0xad,0xbf,0xa4,0x3f}, +{0x3a,0x9d,0xe4,0x2c}, {0x78,0x92,0x0d,0x50}, {0x5f,0xcc,0x9b,0x6a}, {0x7e,0x46,0x62,0x54}, +{0x8d,0x13,0xc2,0xf6}, {0xd8,0xb8,0xe8,0x90}, {0x39,0xf7,0x5e,0x2e}, {0xc3,0xaf,0xf5,0x82}, +{0x5d,0x80,0xbe,0x9f}, {0xd0,0x93,0x7c,0x69}, {0xd5,0x2d,0xa9,0x6f}, {0x25,0x12,0xb3,0xcf}, +{0xac,0x99,0x3b,0xc8}, {0x18,0x7d,0xa7,0x10}, {0x9c,0x63,0x6e,0xe8}, {0x3b,0xbb,0x7b,0xdb}, +{0x26,0x78,0x09,0xcd}, {0x59,0x18,0xf4,0x6e}, {0x9a,0xb7,0x01,0xec}, {0x4f,0x9a,0xa8,0x83}, +{0x95,0x6e,0x65,0xe6}, {0xff,0xe6,0x7e,0xaa}, {0xbc,0xcf,0x08,0x21}, {0x15,0xe8,0xe6,0xef}, +{0xe7,0x9b,0xd9,0xba}, {0x6f,0x36,0xce,0x4a}, {0x9f,0x09,0xd4,0xea}, {0xb0,0x7c,0xd6,0x29}, +{0xa4,0xb2,0xaf,0x31}, {0x3f,0x23,0x31,0x2a}, {0xa5,0x94,0x30,0xc6}, {0xa2,0x66,0xc0,0x35}, +{0x4e,0xbc,0x37,0x74}, {0x82,0xca,0xa6,0xfc}, {0x90,0xd0,0xb0,0xe0}, {0xa7,0xd8,0x15,0x33}, +{0x04,0x98,0x4a,0xf1}, {0xec,0xda,0xf7,0x41}, {0xcd,0x50,0x0e,0x7f}, {0x91,0xf6,0x2f,0x17}, +{0x4d,0xd6,0x8d,0x76}, {0xef,0xb0,0x4d,0x43}, {0xaa,0x4d,0x54,0xcc}, {0x96,0x04,0xdf,0xe4}, +{0xd1,0xb5,0xe3,0x9e}, {0x6a,0x88,0x1b,0x4c}, {0x2c,0x1f,0xb8,0xc1}, {0x65,0x51,0x7f,0x46}, +{0x5e,0xea,0x04,0x9d}, {0x8c,0x35,0x5d,0x01}, {0x87,0x74,0x73,0xfa}, {0x0b,0x41,0x2e,0xfb}, +{0x67,0x1d,0x5a,0xb3}, {0xdb,0xd2,0x52,0x92}, {0x10,0x56,0x33,0xe9}, {0xd6,0x47,0x13,0x6d}, +{0xd7,0x61,0x8c,0x9a}, {0xa1,0x0c,0x7a,0x37}, {0xf8,0x14,0x8e,0x59}, {0x13,0x3c,0x89,0xeb}, +{0xa9,0x27,0xee,0xce}, {0x61,0xc9,0x35,0xb7}, {0x1c,0xe5,0xed,0xe1}, {0x47,0xb1,0x3c,0x7a}, +{0xd2,0xdf,0x59,0x9c}, {0xf2,0x73,0x3f,0x55}, {0x14,0xce,0x79,0x18}, {0xc7,0x37,0xbf,0x73}, +{0xf7,0xcd,0xea,0x53}, {0xfd,0xaa,0x5b,0x5f}, {0x3d,0x6f,0x14,0xdf}, {0x44,0xdb,0x86,0x78}, +{0xaf,0xf3,0x81,0xca}, {0x68,0xc4,0x3e,0xb9}, {0x24,0x34,0x2c,0x38}, {0xa3,0x40,0x5f,0xc2}, +{0x1d,0xc3,0x72,0x16}, {0xe2,0x25,0x0c,0xbc}, {0x3c,0x49,0x8b,0x28}, {0x0d,0x95,0x41,0xff}, +{0xa8,0x01,0x71,0x39}, {0x0c,0xb3,0xde,0x08}, {0xb4,0xe4,0x9c,0xd8}, {0x56,0xc1,0x90,0x64}, +{0xcb,0x84,0x61,0x7b}, {0x32,0xb6,0x70,0xd5}, {0x6c,0x5c,0x74,0x48}, {0xb8,0x57,0x42,0xd0} + } +}; +#define T8 xT8.xt8 + +static const word8 S5[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 +}; + +static const union xtab xU1 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0e,0x09,0x0d,0x0b}, {0x1c,0x12,0x1a,0x16}, {0x12,0x1b,0x17,0x1d}, +{0x38,0x24,0x34,0x2c}, {0x36,0x2d,0x39,0x27}, {0x24,0x36,0x2e,0x3a}, {0x2a,0x3f,0x23,0x31}, +{0x70,0x48,0x68,0x58}, {0x7e,0x41,0x65,0x53}, {0x6c,0x5a,0x72,0x4e}, {0x62,0x53,0x7f,0x45}, +{0x48,0x6c,0x5c,0x74}, {0x46,0x65,0x51,0x7f}, {0x54,0x7e,0x46,0x62}, {0x5a,0x77,0x4b,0x69}, +{0xe0,0x90,0xd0,0xb0}, {0xee,0x99,0xdd,0xbb}, {0xfc,0x82,0xca,0xa6}, {0xf2,0x8b,0xc7,0xad}, +{0xd8,0xb4,0xe4,0x9c}, {0xd6,0xbd,0xe9,0x97}, {0xc4,0xa6,0xfe,0x8a}, {0xca,0xaf,0xf3,0x81}, +{0x90,0xd8,0xb8,0xe8}, {0x9e,0xd1,0xb5,0xe3}, {0x8c,0xca,0xa2,0xfe}, {0x82,0xc3,0xaf,0xf5}, +{0xa8,0xfc,0x8c,0xc4}, {0xa6,0xf5,0x81,0xcf}, {0xb4,0xee,0x96,0xd2}, {0xba,0xe7,0x9b,0xd9}, +{0xdb,0x3b,0xbb,0x7b}, {0xd5,0x32,0xb6,0x70}, {0xc7,0x29,0xa1,0x6d}, {0xc9,0x20,0xac,0x66}, +{0xe3,0x1f,0x8f,0x57}, {0xed,0x16,0x82,0x5c}, {0xff,0x0d,0x95,0x41}, {0xf1,0x04,0x98,0x4a}, +{0xab,0x73,0xd3,0x23}, {0xa5,0x7a,0xde,0x28}, {0xb7,0x61,0xc9,0x35}, {0xb9,0x68,0xc4,0x3e}, +{0x93,0x57,0xe7,0x0f}, {0x9d,0x5e,0xea,0x04}, {0x8f,0x45,0xfd,0x19}, {0x81,0x4c,0xf0,0x12}, +{0x3b,0xab,0x6b,0xcb}, {0x35,0xa2,0x66,0xc0}, {0x27,0xb9,0x71,0xdd}, {0x29,0xb0,0x7c,0xd6}, +{0x03,0x8f,0x5f,0xe7}, {0x0d,0x86,0x52,0xec}, {0x1f,0x9d,0x45,0xf1}, {0x11,0x94,0x48,0xfa}, +{0x4b,0xe3,0x03,0x93}, {0x45,0xea,0x0e,0x98}, {0x57,0xf1,0x19,0x85}, {0x59,0xf8,0x14,0x8e}, +{0x73,0xc7,0x37,0xbf}, {0x7d,0xce,0x3a,0xb4}, {0x6f,0xd5,0x2d,0xa9}, {0x61,0xdc,0x20,0xa2}, +{0xad,0x76,0x6d,0xf6}, {0xa3,0x7f,0x60,0xfd}, {0xb1,0x64,0x77,0xe0}, {0xbf,0x6d,0x7a,0xeb}, +{0x95,0x52,0x59,0xda}, {0x9b,0x5b,0x54,0xd1}, {0x89,0x40,0x43,0xcc}, {0x87,0x49,0x4e,0xc7}, +{0xdd,0x3e,0x05,0xae}, {0xd3,0x37,0x08,0xa5}, {0xc1,0x2c,0x1f,0xb8}, {0xcf,0x25,0x12,0xb3}, +{0xe5,0x1a,0x31,0x82}, {0xeb,0x13,0x3c,0x89}, {0xf9,0x08,0x2b,0x94}, {0xf7,0x01,0x26,0x9f}, +{0x4d,0xe6,0xbd,0x46}, {0x43,0xef,0xb0,0x4d}, {0x51,0xf4,0xa7,0x50}, {0x5f,0xfd,0xaa,0x5b}, +{0x75,0xc2,0x89,0x6a}, {0x7b,0xcb,0x84,0x61}, {0x69,0xd0,0x93,0x7c}, {0x67,0xd9,0x9e,0x77}, +{0x3d,0xae,0xd5,0x1e}, {0x33,0xa7,0xd8,0x15}, {0x21,0xbc,0xcf,0x08}, {0x2f,0xb5,0xc2,0x03}, +{0x05,0x8a,0xe1,0x32}, {0x0b,0x83,0xec,0x39}, {0x19,0x98,0xfb,0x24}, {0x17,0x91,0xf6,0x2f}, +{0x76,0x4d,0xd6,0x8d}, {0x78,0x44,0xdb,0x86}, {0x6a,0x5f,0xcc,0x9b}, {0x64,0x56,0xc1,0x90}, +{0x4e,0x69,0xe2,0xa1}, {0x40,0x60,0xef,0xaa}, {0x52,0x7b,0xf8,0xb7}, {0x5c,0x72,0xf5,0xbc}, +{0x06,0x05,0xbe,0xd5}, {0x08,0x0c,0xb3,0xde}, {0x1a,0x17,0xa4,0xc3}, {0x14,0x1e,0xa9,0xc8}, +{0x3e,0x21,0x8a,0xf9}, {0x30,0x28,0x87,0xf2}, {0x22,0x33,0x90,0xef}, {0x2c,0x3a,0x9d,0xe4}, +{0x96,0xdd,0x06,0x3d}, {0x98,0xd4,0x0b,0x36}, {0x8a,0xcf,0x1c,0x2b}, {0x84,0xc6,0x11,0x20}, +{0xae,0xf9,0x32,0x11}, {0xa0,0xf0,0x3f,0x1a}, {0xb2,0xeb,0x28,0x07}, {0xbc,0xe2,0x25,0x0c}, +{0xe6,0x95,0x6e,0x65}, {0xe8,0x9c,0x63,0x6e}, {0xfa,0x87,0x74,0x73}, {0xf4,0x8e,0x79,0x78}, +{0xde,0xb1,0x5a,0x49}, {0xd0,0xb8,0x57,0x42}, {0xc2,0xa3,0x40,0x5f}, {0xcc,0xaa,0x4d,0x54}, +{0x41,0xec,0xda,0xf7}, {0x4f,0xe5,0xd7,0xfc}, {0x5d,0xfe,0xc0,0xe1}, {0x53,0xf7,0xcd,0xea}, +{0x79,0xc8,0xee,0xdb}, {0x77,0xc1,0xe3,0xd0}, {0x65,0xda,0xf4,0xcd}, {0x6b,0xd3,0xf9,0xc6}, +{0x31,0xa4,0xb2,0xaf}, {0x3f,0xad,0xbf,0xa4}, {0x2d,0xb6,0xa8,0xb9}, {0x23,0xbf,0xa5,0xb2}, +{0x09,0x80,0x86,0x83}, {0x07,0x89,0x8b,0x88}, {0x15,0x92,0x9c,0x95}, {0x1b,0x9b,0x91,0x9e}, +{0xa1,0x7c,0x0a,0x47}, {0xaf,0x75,0x07,0x4c}, {0xbd,0x6e,0x10,0x51}, {0xb3,0x67,0x1d,0x5a}, +{0x99,0x58,0x3e,0x6b}, {0x97,0x51,0x33,0x60}, {0x85,0x4a,0x24,0x7d}, {0x8b,0x43,0x29,0x76}, +{0xd1,0x34,0x62,0x1f}, {0xdf,0x3d,0x6f,0x14}, {0xcd,0x26,0x78,0x09}, {0xc3,0x2f,0x75,0x02}, +{0xe9,0x10,0x56,0x33}, {0xe7,0x19,0x5b,0x38}, {0xf5,0x02,0x4c,0x25}, {0xfb,0x0b,0x41,0x2e}, +{0x9a,0xd7,0x61,0x8c}, {0x94,0xde,0x6c,0x87}, {0x86,0xc5,0x7b,0x9a}, {0x88,0xcc,0x76,0x91}, +{0xa2,0xf3,0x55,0xa0}, {0xac,0xfa,0x58,0xab}, {0xbe,0xe1,0x4f,0xb6}, {0xb0,0xe8,0x42,0xbd}, +{0xea,0x9f,0x09,0xd4}, {0xe4,0x96,0x04,0xdf}, {0xf6,0x8d,0x13,0xc2}, {0xf8,0x84,0x1e,0xc9}, +{0xd2,0xbb,0x3d,0xf8}, {0xdc,0xb2,0x30,0xf3}, {0xce,0xa9,0x27,0xee}, {0xc0,0xa0,0x2a,0xe5}, +{0x7a,0x47,0xb1,0x3c}, {0x74,0x4e,0xbc,0x37}, {0x66,0x55,0xab,0x2a}, {0x68,0x5c,0xa6,0x21}, +{0x42,0x63,0x85,0x10}, {0x4c,0x6a,0x88,0x1b}, {0x5e,0x71,0x9f,0x06}, {0x50,0x78,0x92,0x0d}, +{0x0a,0x0f,0xd9,0x64}, {0x04,0x06,0xd4,0x6f}, {0x16,0x1d,0xc3,0x72}, {0x18,0x14,0xce,0x79}, +{0x32,0x2b,0xed,0x48}, {0x3c,0x22,0xe0,0x43}, {0x2e,0x39,0xf7,0x5e}, {0x20,0x30,0xfa,0x55}, +{0xec,0x9a,0xb7,0x01}, {0xe2,0x93,0xba,0x0a}, {0xf0,0x88,0xad,0x17}, {0xfe,0x81,0xa0,0x1c}, +{0xd4,0xbe,0x83,0x2d}, {0xda,0xb7,0x8e,0x26}, {0xc8,0xac,0x99,0x3b}, {0xc6,0xa5,0x94,0x30}, +{0x9c,0xd2,0xdf,0x59}, {0x92,0xdb,0xd2,0x52}, {0x80,0xc0,0xc5,0x4f}, {0x8e,0xc9,0xc8,0x44}, +{0xa4,0xf6,0xeb,0x75}, {0xaa,0xff,0xe6,0x7e}, {0xb8,0xe4,0xf1,0x63}, {0xb6,0xed,0xfc,0x68}, +{0x0c,0x0a,0x67,0xb1}, {0x02,0x03,0x6a,0xba}, {0x10,0x18,0x7d,0xa7}, {0x1e,0x11,0x70,0xac}, +{0x34,0x2e,0x53,0x9d}, {0x3a,0x27,0x5e,0x96}, {0x28,0x3c,0x49,0x8b}, {0x26,0x35,0x44,0x80}, +{0x7c,0x42,0x0f,0xe9}, {0x72,0x4b,0x02,0xe2}, {0x60,0x50,0x15,0xff}, {0x6e,0x59,0x18,0xf4}, +{0x44,0x66,0x3b,0xc5}, {0x4a,0x6f,0x36,0xce}, {0x58,0x74,0x21,0xd3}, {0x56,0x7d,0x2c,0xd8}, +{0x37,0xa1,0x0c,0x7a}, {0x39,0xa8,0x01,0x71}, {0x2b,0xb3,0x16,0x6c}, {0x25,0xba,0x1b,0x67}, +{0x0f,0x85,0x38,0x56}, {0x01,0x8c,0x35,0x5d}, {0x13,0x97,0x22,0x40}, {0x1d,0x9e,0x2f,0x4b}, +{0x47,0xe9,0x64,0x22}, {0x49,0xe0,0x69,0x29}, {0x5b,0xfb,0x7e,0x34}, {0x55,0xf2,0x73,0x3f}, +{0x7f,0xcd,0x50,0x0e}, {0x71,0xc4,0x5d,0x05}, {0x63,0xdf,0x4a,0x18}, {0x6d,0xd6,0x47,0x13}, +{0xd7,0x31,0xdc,0xca}, {0xd9,0x38,0xd1,0xc1}, {0xcb,0x23,0xc6,0xdc}, {0xc5,0x2a,0xcb,0xd7}, +{0xef,0x15,0xe8,0xe6}, {0xe1,0x1c,0xe5,0xed}, {0xf3,0x07,0xf2,0xf0}, {0xfd,0x0e,0xff,0xfb}, +{0xa7,0x79,0xb4,0x92}, {0xa9,0x70,0xb9,0x99}, {0xbb,0x6b,0xae,0x84}, {0xb5,0x62,0xa3,0x8f}, +{0x9f,0x5d,0x80,0xbe}, {0x91,0x54,0x8d,0xb5}, {0x83,0x4f,0x9a,0xa8}, {0x8d,0x46,0x97,0xa3} + } +}; +#define U1 xU1.xt8 + +static const union xtab xU2 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0b,0x0e,0x09,0x0d}, {0x16,0x1c,0x12,0x1a}, {0x1d,0x12,0x1b,0x17}, +{0x2c,0x38,0x24,0x34}, {0x27,0x36,0x2d,0x39}, {0x3a,0x24,0x36,0x2e}, {0x31,0x2a,0x3f,0x23}, +{0x58,0x70,0x48,0x68}, {0x53,0x7e,0x41,0x65}, {0x4e,0x6c,0x5a,0x72}, {0x45,0x62,0x53,0x7f}, +{0x74,0x48,0x6c,0x5c}, {0x7f,0x46,0x65,0x51}, {0x62,0x54,0x7e,0x46}, {0x69,0x5a,0x77,0x4b}, +{0xb0,0xe0,0x90,0xd0}, {0xbb,0xee,0x99,0xdd}, {0xa6,0xfc,0x82,0xca}, {0xad,0xf2,0x8b,0xc7}, +{0x9c,0xd8,0xb4,0xe4}, {0x97,0xd6,0xbd,0xe9}, {0x8a,0xc4,0xa6,0xfe}, {0x81,0xca,0xaf,0xf3}, +{0xe8,0x90,0xd8,0xb8}, {0xe3,0x9e,0xd1,0xb5}, {0xfe,0x8c,0xca,0xa2}, {0xf5,0x82,0xc3,0xaf}, +{0xc4,0xa8,0xfc,0x8c}, {0xcf,0xa6,0xf5,0x81}, {0xd2,0xb4,0xee,0x96}, {0xd9,0xba,0xe7,0x9b}, +{0x7b,0xdb,0x3b,0xbb}, {0x70,0xd5,0x32,0xb6}, {0x6d,0xc7,0x29,0xa1}, {0x66,0xc9,0x20,0xac}, +{0x57,0xe3,0x1f,0x8f}, {0x5c,0xed,0x16,0x82}, {0x41,0xff,0x0d,0x95}, {0x4a,0xf1,0x04,0x98}, +{0x23,0xab,0x73,0xd3}, {0x28,0xa5,0x7a,0xde}, {0x35,0xb7,0x61,0xc9}, {0x3e,0xb9,0x68,0xc4}, +{0x0f,0x93,0x57,0xe7}, {0x04,0x9d,0x5e,0xea}, {0x19,0x8f,0x45,0xfd}, {0x12,0x81,0x4c,0xf0}, +{0xcb,0x3b,0xab,0x6b}, {0xc0,0x35,0xa2,0x66}, {0xdd,0x27,0xb9,0x71}, {0xd6,0x29,0xb0,0x7c}, +{0xe7,0x03,0x8f,0x5f}, {0xec,0x0d,0x86,0x52}, {0xf1,0x1f,0x9d,0x45}, {0xfa,0x11,0x94,0x48}, +{0x93,0x4b,0xe3,0x03}, {0x98,0x45,0xea,0x0e}, {0x85,0x57,0xf1,0x19}, {0x8e,0x59,0xf8,0x14}, +{0xbf,0x73,0xc7,0x37}, {0xb4,0x7d,0xce,0x3a}, {0xa9,0x6f,0xd5,0x2d}, {0xa2,0x61,0xdc,0x20}, +{0xf6,0xad,0x76,0x6d}, {0xfd,0xa3,0x7f,0x60}, {0xe0,0xb1,0x64,0x77}, {0xeb,0xbf,0x6d,0x7a}, +{0xda,0x95,0x52,0x59}, {0xd1,0x9b,0x5b,0x54}, {0xcc,0x89,0x40,0x43}, {0xc7,0x87,0x49,0x4e}, +{0xae,0xdd,0x3e,0x05}, {0xa5,0xd3,0x37,0x08}, {0xb8,0xc1,0x2c,0x1f}, {0xb3,0xcf,0x25,0x12}, +{0x82,0xe5,0x1a,0x31}, {0x89,0xeb,0x13,0x3c}, {0x94,0xf9,0x08,0x2b}, {0x9f,0xf7,0x01,0x26}, +{0x46,0x4d,0xe6,0xbd}, {0x4d,0x43,0xef,0xb0}, {0x50,0x51,0xf4,0xa7}, {0x5b,0x5f,0xfd,0xaa}, +{0x6a,0x75,0xc2,0x89}, {0x61,0x7b,0xcb,0x84}, {0x7c,0x69,0xd0,0x93}, {0x77,0x67,0xd9,0x9e}, +{0x1e,0x3d,0xae,0xd5}, {0x15,0x33,0xa7,0xd8}, {0x08,0x21,0xbc,0xcf}, {0x03,0x2f,0xb5,0xc2}, +{0x32,0x05,0x8a,0xe1}, {0x39,0x0b,0x83,0xec}, {0x24,0x19,0x98,0xfb}, {0x2f,0x17,0x91,0xf6}, +{0x8d,0x76,0x4d,0xd6}, {0x86,0x78,0x44,0xdb}, {0x9b,0x6a,0x5f,0xcc}, {0x90,0x64,0x56,0xc1}, +{0xa1,0x4e,0x69,0xe2}, {0xaa,0x40,0x60,0xef}, {0xb7,0x52,0x7b,0xf8}, {0xbc,0x5c,0x72,0xf5}, +{0xd5,0x06,0x05,0xbe}, {0xde,0x08,0x0c,0xb3}, {0xc3,0x1a,0x17,0xa4}, {0xc8,0x14,0x1e,0xa9}, +{0xf9,0x3e,0x21,0x8a}, {0xf2,0x30,0x28,0x87}, {0xef,0x22,0x33,0x90}, {0xe4,0x2c,0x3a,0x9d}, +{0x3d,0x96,0xdd,0x06}, {0x36,0x98,0xd4,0x0b}, {0x2b,0x8a,0xcf,0x1c}, {0x20,0x84,0xc6,0x11}, +{0x11,0xae,0xf9,0x32}, {0x1a,0xa0,0xf0,0x3f}, {0x07,0xb2,0xeb,0x28}, {0x0c,0xbc,0xe2,0x25}, +{0x65,0xe6,0x95,0x6e}, {0x6e,0xe8,0x9c,0x63}, {0x73,0xfa,0x87,0x74}, {0x78,0xf4,0x8e,0x79}, +{0x49,0xde,0xb1,0x5a}, {0x42,0xd0,0xb8,0x57}, {0x5f,0xc2,0xa3,0x40}, {0x54,0xcc,0xaa,0x4d}, +{0xf7,0x41,0xec,0xda}, {0xfc,0x4f,0xe5,0xd7}, {0xe1,0x5d,0xfe,0xc0}, {0xea,0x53,0xf7,0xcd}, +{0xdb,0x79,0xc8,0xee}, {0xd0,0x77,0xc1,0xe3}, {0xcd,0x65,0xda,0xf4}, {0xc6,0x6b,0xd3,0xf9}, +{0xaf,0x31,0xa4,0xb2}, {0xa4,0x3f,0xad,0xbf}, {0xb9,0x2d,0xb6,0xa8}, {0xb2,0x23,0xbf,0xa5}, +{0x83,0x09,0x80,0x86}, {0x88,0x07,0x89,0x8b}, {0x95,0x15,0x92,0x9c}, {0x9e,0x1b,0x9b,0x91}, +{0x47,0xa1,0x7c,0x0a}, {0x4c,0xaf,0x75,0x07}, {0x51,0xbd,0x6e,0x10}, {0x5a,0xb3,0x67,0x1d}, +{0x6b,0x99,0x58,0x3e}, {0x60,0x97,0x51,0x33}, {0x7d,0x85,0x4a,0x24}, {0x76,0x8b,0x43,0x29}, +{0x1f,0xd1,0x34,0x62}, {0x14,0xdf,0x3d,0x6f}, {0x09,0xcd,0x26,0x78}, {0x02,0xc3,0x2f,0x75}, +{0x33,0xe9,0x10,0x56}, {0x38,0xe7,0x19,0x5b}, {0x25,0xf5,0x02,0x4c}, {0x2e,0xfb,0x0b,0x41}, +{0x8c,0x9a,0xd7,0x61}, {0x87,0x94,0xde,0x6c}, {0x9a,0x86,0xc5,0x7b}, {0x91,0x88,0xcc,0x76}, +{0xa0,0xa2,0xf3,0x55}, {0xab,0xac,0xfa,0x58}, {0xb6,0xbe,0xe1,0x4f}, {0xbd,0xb0,0xe8,0x42}, +{0xd4,0xea,0x9f,0x09}, {0xdf,0xe4,0x96,0x04}, {0xc2,0xf6,0x8d,0x13}, {0xc9,0xf8,0x84,0x1e}, +{0xf8,0xd2,0xbb,0x3d}, {0xf3,0xdc,0xb2,0x30}, {0xee,0xce,0xa9,0x27}, {0xe5,0xc0,0xa0,0x2a}, +{0x3c,0x7a,0x47,0xb1}, {0x37,0x74,0x4e,0xbc}, {0x2a,0x66,0x55,0xab}, {0x21,0x68,0x5c,0xa6}, +{0x10,0x42,0x63,0x85}, {0x1b,0x4c,0x6a,0x88}, {0x06,0x5e,0x71,0x9f}, {0x0d,0x50,0x78,0x92}, +{0x64,0x0a,0x0f,0xd9}, {0x6f,0x04,0x06,0xd4}, {0x72,0x16,0x1d,0xc3}, {0x79,0x18,0x14,0xce}, +{0x48,0x32,0x2b,0xed}, {0x43,0x3c,0x22,0xe0}, {0x5e,0x2e,0x39,0xf7}, {0x55,0x20,0x30,0xfa}, +{0x01,0xec,0x9a,0xb7}, {0x0a,0xe2,0x93,0xba}, {0x17,0xf0,0x88,0xad}, {0x1c,0xfe,0x81,0xa0}, +{0x2d,0xd4,0xbe,0x83}, {0x26,0xda,0xb7,0x8e}, {0x3b,0xc8,0xac,0x99}, {0x30,0xc6,0xa5,0x94}, +{0x59,0x9c,0xd2,0xdf}, {0x52,0x92,0xdb,0xd2}, {0x4f,0x80,0xc0,0xc5}, {0x44,0x8e,0xc9,0xc8}, +{0x75,0xa4,0xf6,0xeb}, {0x7e,0xaa,0xff,0xe6}, {0x63,0xb8,0xe4,0xf1}, {0x68,0xb6,0xed,0xfc}, +{0xb1,0x0c,0x0a,0x67}, {0xba,0x02,0x03,0x6a}, {0xa7,0x10,0x18,0x7d}, {0xac,0x1e,0x11,0x70}, +{0x9d,0x34,0x2e,0x53}, {0x96,0x3a,0x27,0x5e}, {0x8b,0x28,0x3c,0x49}, {0x80,0x26,0x35,0x44}, +{0xe9,0x7c,0x42,0x0f}, {0xe2,0x72,0x4b,0x02}, {0xff,0x60,0x50,0x15}, {0xf4,0x6e,0x59,0x18}, +{0xc5,0x44,0x66,0x3b}, {0xce,0x4a,0x6f,0x36}, {0xd3,0x58,0x74,0x21}, {0xd8,0x56,0x7d,0x2c}, +{0x7a,0x37,0xa1,0x0c}, {0x71,0x39,0xa8,0x01}, {0x6c,0x2b,0xb3,0x16}, {0x67,0x25,0xba,0x1b}, +{0x56,0x0f,0x85,0x38}, {0x5d,0x01,0x8c,0x35}, {0x40,0x13,0x97,0x22}, {0x4b,0x1d,0x9e,0x2f}, +{0x22,0x47,0xe9,0x64}, {0x29,0x49,0xe0,0x69}, {0x34,0x5b,0xfb,0x7e}, {0x3f,0x55,0xf2,0x73}, +{0x0e,0x7f,0xcd,0x50}, {0x05,0x71,0xc4,0x5d}, {0x18,0x63,0xdf,0x4a}, {0x13,0x6d,0xd6,0x47}, +{0xca,0xd7,0x31,0xdc}, {0xc1,0xd9,0x38,0xd1}, {0xdc,0xcb,0x23,0xc6}, {0xd7,0xc5,0x2a,0xcb}, +{0xe6,0xef,0x15,0xe8}, {0xed,0xe1,0x1c,0xe5}, {0xf0,0xf3,0x07,0xf2}, {0xfb,0xfd,0x0e,0xff}, +{0x92,0xa7,0x79,0xb4}, {0x99,0xa9,0x70,0xb9}, {0x84,0xbb,0x6b,0xae}, {0x8f,0xb5,0x62,0xa3}, +{0xbe,0x9f,0x5d,0x80}, {0xb5,0x91,0x54,0x8d}, {0xa8,0x83,0x4f,0x9a}, {0xa3,0x8d,0x46,0x97} + } +}; +#define U2 xU2.xt8 + +static const union xtab xU3 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x0d,0x0b,0x0e,0x09}, {0x1a,0x16,0x1c,0x12}, {0x17,0x1d,0x12,0x1b}, +{0x34,0x2c,0x38,0x24}, {0x39,0x27,0x36,0x2d}, {0x2e,0x3a,0x24,0x36}, {0x23,0x31,0x2a,0x3f}, +{0x68,0x58,0x70,0x48}, {0x65,0x53,0x7e,0x41}, {0x72,0x4e,0x6c,0x5a}, {0x7f,0x45,0x62,0x53}, +{0x5c,0x74,0x48,0x6c}, {0x51,0x7f,0x46,0x65}, {0x46,0x62,0x54,0x7e}, {0x4b,0x69,0x5a,0x77}, +{0xd0,0xb0,0xe0,0x90}, {0xdd,0xbb,0xee,0x99}, {0xca,0xa6,0xfc,0x82}, {0xc7,0xad,0xf2,0x8b}, +{0xe4,0x9c,0xd8,0xb4}, {0xe9,0x97,0xd6,0xbd}, {0xfe,0x8a,0xc4,0xa6}, {0xf3,0x81,0xca,0xaf}, +{0xb8,0xe8,0x90,0xd8}, {0xb5,0xe3,0x9e,0xd1}, {0xa2,0xfe,0x8c,0xca}, {0xaf,0xf5,0x82,0xc3}, +{0x8c,0xc4,0xa8,0xfc}, {0x81,0xcf,0xa6,0xf5}, {0x96,0xd2,0xb4,0xee}, {0x9b,0xd9,0xba,0xe7}, +{0xbb,0x7b,0xdb,0x3b}, {0xb6,0x70,0xd5,0x32}, {0xa1,0x6d,0xc7,0x29}, {0xac,0x66,0xc9,0x20}, +{0x8f,0x57,0xe3,0x1f}, {0x82,0x5c,0xed,0x16}, {0x95,0x41,0xff,0x0d}, {0x98,0x4a,0xf1,0x04}, +{0xd3,0x23,0xab,0x73}, {0xde,0x28,0xa5,0x7a}, {0xc9,0x35,0xb7,0x61}, {0xc4,0x3e,0xb9,0x68}, +{0xe7,0x0f,0x93,0x57}, {0xea,0x04,0x9d,0x5e}, {0xfd,0x19,0x8f,0x45}, {0xf0,0x12,0x81,0x4c}, +{0x6b,0xcb,0x3b,0xab}, {0x66,0xc0,0x35,0xa2}, {0x71,0xdd,0x27,0xb9}, {0x7c,0xd6,0x29,0xb0}, +{0x5f,0xe7,0x03,0x8f}, {0x52,0xec,0x0d,0x86}, {0x45,0xf1,0x1f,0x9d}, {0x48,0xfa,0x11,0x94}, +{0x03,0x93,0x4b,0xe3}, {0x0e,0x98,0x45,0xea}, {0x19,0x85,0x57,0xf1}, {0x14,0x8e,0x59,0xf8}, +{0x37,0xbf,0x73,0xc7}, {0x3a,0xb4,0x7d,0xce}, {0x2d,0xa9,0x6f,0xd5}, {0x20,0xa2,0x61,0xdc}, +{0x6d,0xf6,0xad,0x76}, {0x60,0xfd,0xa3,0x7f}, {0x77,0xe0,0xb1,0x64}, {0x7a,0xeb,0xbf,0x6d}, +{0x59,0xda,0x95,0x52}, {0x54,0xd1,0x9b,0x5b}, {0x43,0xcc,0x89,0x40}, {0x4e,0xc7,0x87,0x49}, +{0x05,0xae,0xdd,0x3e}, {0x08,0xa5,0xd3,0x37}, {0x1f,0xb8,0xc1,0x2c}, {0x12,0xb3,0xcf,0x25}, +{0x31,0x82,0xe5,0x1a}, {0x3c,0x89,0xeb,0x13}, {0x2b,0x94,0xf9,0x08}, {0x26,0x9f,0xf7,0x01}, +{0xbd,0x46,0x4d,0xe6}, {0xb0,0x4d,0x43,0xef}, {0xa7,0x50,0x51,0xf4}, {0xaa,0x5b,0x5f,0xfd}, +{0x89,0x6a,0x75,0xc2}, {0x84,0x61,0x7b,0xcb}, {0x93,0x7c,0x69,0xd0}, {0x9e,0x77,0x67,0xd9}, +{0xd5,0x1e,0x3d,0xae}, {0xd8,0x15,0x33,0xa7}, {0xcf,0x08,0x21,0xbc}, {0xc2,0x03,0x2f,0xb5}, +{0xe1,0x32,0x05,0x8a}, {0xec,0x39,0x0b,0x83}, {0xfb,0x24,0x19,0x98}, {0xf6,0x2f,0x17,0x91}, +{0xd6,0x8d,0x76,0x4d}, {0xdb,0x86,0x78,0x44}, {0xcc,0x9b,0x6a,0x5f}, {0xc1,0x90,0x64,0x56}, +{0xe2,0xa1,0x4e,0x69}, {0xef,0xaa,0x40,0x60}, {0xf8,0xb7,0x52,0x7b}, {0xf5,0xbc,0x5c,0x72}, +{0xbe,0xd5,0x06,0x05}, {0xb3,0xde,0x08,0x0c}, {0xa4,0xc3,0x1a,0x17}, {0xa9,0xc8,0x14,0x1e}, +{0x8a,0xf9,0x3e,0x21}, {0x87,0xf2,0x30,0x28}, {0x90,0xef,0x22,0x33}, {0x9d,0xe4,0x2c,0x3a}, +{0x06,0x3d,0x96,0xdd}, {0x0b,0x36,0x98,0xd4}, {0x1c,0x2b,0x8a,0xcf}, {0x11,0x20,0x84,0xc6}, +{0x32,0x11,0xae,0xf9}, {0x3f,0x1a,0xa0,0xf0}, {0x28,0x07,0xb2,0xeb}, {0x25,0x0c,0xbc,0xe2}, +{0x6e,0x65,0xe6,0x95}, {0x63,0x6e,0xe8,0x9c}, {0x74,0x73,0xfa,0x87}, {0x79,0x78,0xf4,0x8e}, +{0x5a,0x49,0xde,0xb1}, {0x57,0x42,0xd0,0xb8}, {0x40,0x5f,0xc2,0xa3}, {0x4d,0x54,0xcc,0xaa}, +{0xda,0xf7,0x41,0xec}, {0xd7,0xfc,0x4f,0xe5}, {0xc0,0xe1,0x5d,0xfe}, {0xcd,0xea,0x53,0xf7}, +{0xee,0xdb,0x79,0xc8}, {0xe3,0xd0,0x77,0xc1}, {0xf4,0xcd,0x65,0xda}, {0xf9,0xc6,0x6b,0xd3}, +{0xb2,0xaf,0x31,0xa4}, {0xbf,0xa4,0x3f,0xad}, {0xa8,0xb9,0x2d,0xb6}, {0xa5,0xb2,0x23,0xbf}, +{0x86,0x83,0x09,0x80}, {0x8b,0x88,0x07,0x89}, {0x9c,0x95,0x15,0x92}, {0x91,0x9e,0x1b,0x9b}, +{0x0a,0x47,0xa1,0x7c}, {0x07,0x4c,0xaf,0x75}, {0x10,0x51,0xbd,0x6e}, {0x1d,0x5a,0xb3,0x67}, +{0x3e,0x6b,0x99,0x58}, {0x33,0x60,0x97,0x51}, {0x24,0x7d,0x85,0x4a}, {0x29,0x76,0x8b,0x43}, +{0x62,0x1f,0xd1,0x34}, {0x6f,0x14,0xdf,0x3d}, {0x78,0x09,0xcd,0x26}, {0x75,0x02,0xc3,0x2f}, +{0x56,0x33,0xe9,0x10}, {0x5b,0x38,0xe7,0x19}, {0x4c,0x25,0xf5,0x02}, {0x41,0x2e,0xfb,0x0b}, +{0x61,0x8c,0x9a,0xd7}, {0x6c,0x87,0x94,0xde}, {0x7b,0x9a,0x86,0xc5}, {0x76,0x91,0x88,0xcc}, +{0x55,0xa0,0xa2,0xf3}, {0x58,0xab,0xac,0xfa}, {0x4f,0xb6,0xbe,0xe1}, {0x42,0xbd,0xb0,0xe8}, +{0x09,0xd4,0xea,0x9f}, {0x04,0xdf,0xe4,0x96}, {0x13,0xc2,0xf6,0x8d}, {0x1e,0xc9,0xf8,0x84}, +{0x3d,0xf8,0xd2,0xbb}, {0x30,0xf3,0xdc,0xb2}, {0x27,0xee,0xce,0xa9}, {0x2a,0xe5,0xc0,0xa0}, +{0xb1,0x3c,0x7a,0x47}, {0xbc,0x37,0x74,0x4e}, {0xab,0x2a,0x66,0x55}, {0xa6,0x21,0x68,0x5c}, +{0x85,0x10,0x42,0x63}, {0x88,0x1b,0x4c,0x6a}, {0x9f,0x06,0x5e,0x71}, {0x92,0x0d,0x50,0x78}, +{0xd9,0x64,0x0a,0x0f}, {0xd4,0x6f,0x04,0x06}, {0xc3,0x72,0x16,0x1d}, {0xce,0x79,0x18,0x14}, +{0xed,0x48,0x32,0x2b}, {0xe0,0x43,0x3c,0x22}, {0xf7,0x5e,0x2e,0x39}, {0xfa,0x55,0x20,0x30}, +{0xb7,0x01,0xec,0x9a}, {0xba,0x0a,0xe2,0x93}, {0xad,0x17,0xf0,0x88}, {0xa0,0x1c,0xfe,0x81}, +{0x83,0x2d,0xd4,0xbe}, {0x8e,0x26,0xda,0xb7}, {0x99,0x3b,0xc8,0xac}, {0x94,0x30,0xc6,0xa5}, +{0xdf,0x59,0x9c,0xd2}, {0xd2,0x52,0x92,0xdb}, {0xc5,0x4f,0x80,0xc0}, {0xc8,0x44,0x8e,0xc9}, +{0xeb,0x75,0xa4,0xf6}, {0xe6,0x7e,0xaa,0xff}, {0xf1,0x63,0xb8,0xe4}, {0xfc,0x68,0xb6,0xed}, +{0x67,0xb1,0x0c,0x0a}, {0x6a,0xba,0x02,0x03}, {0x7d,0xa7,0x10,0x18}, {0x70,0xac,0x1e,0x11}, +{0x53,0x9d,0x34,0x2e}, {0x5e,0x96,0x3a,0x27}, {0x49,0x8b,0x28,0x3c}, {0x44,0x80,0x26,0x35}, +{0x0f,0xe9,0x7c,0x42}, {0x02,0xe2,0x72,0x4b}, {0x15,0xff,0x60,0x50}, {0x18,0xf4,0x6e,0x59}, +{0x3b,0xc5,0x44,0x66}, {0x36,0xce,0x4a,0x6f}, {0x21,0xd3,0x58,0x74}, {0x2c,0xd8,0x56,0x7d}, +{0x0c,0x7a,0x37,0xa1}, {0x01,0x71,0x39,0xa8}, {0x16,0x6c,0x2b,0xb3}, {0x1b,0x67,0x25,0xba}, +{0x38,0x56,0x0f,0x85}, {0x35,0x5d,0x01,0x8c}, {0x22,0x40,0x13,0x97}, {0x2f,0x4b,0x1d,0x9e}, +{0x64,0x22,0x47,0xe9}, {0x69,0x29,0x49,0xe0}, {0x7e,0x34,0x5b,0xfb}, {0x73,0x3f,0x55,0xf2}, +{0x50,0x0e,0x7f,0xcd}, {0x5d,0x05,0x71,0xc4}, {0x4a,0x18,0x63,0xdf}, {0x47,0x13,0x6d,0xd6}, +{0xdc,0xca,0xd7,0x31}, {0xd1,0xc1,0xd9,0x38}, {0xc6,0xdc,0xcb,0x23}, {0xcb,0xd7,0xc5,0x2a}, +{0xe8,0xe6,0xef,0x15}, {0xe5,0xed,0xe1,0x1c}, {0xf2,0xf0,0xf3,0x07}, {0xff,0xfb,0xfd,0x0e}, +{0xb4,0x92,0xa7,0x79}, {0xb9,0x99,0xa9,0x70}, {0xae,0x84,0xbb,0x6b}, {0xa3,0x8f,0xb5,0x62}, +{0x80,0xbe,0x9f,0x5d}, {0x8d,0xb5,0x91,0x54}, {0x9a,0xa8,0x83,0x4f}, {0x97,0xa3,0x8d,0x46} + } +}; +#define U3 xU3.xt8 + +static const union xtab xU4 = { + .xt8 = { +{0x00,0x00,0x00,0x00}, {0x09,0x0d,0x0b,0x0e}, {0x12,0x1a,0x16,0x1c}, {0x1b,0x17,0x1d,0x12}, +{0x24,0x34,0x2c,0x38}, {0x2d,0x39,0x27,0x36}, {0x36,0x2e,0x3a,0x24}, {0x3f,0x23,0x31,0x2a}, +{0x48,0x68,0x58,0x70}, {0x41,0x65,0x53,0x7e}, {0x5a,0x72,0x4e,0x6c}, {0x53,0x7f,0x45,0x62}, +{0x6c,0x5c,0x74,0x48}, {0x65,0x51,0x7f,0x46}, {0x7e,0x46,0x62,0x54}, {0x77,0x4b,0x69,0x5a}, +{0x90,0xd0,0xb0,0xe0}, {0x99,0xdd,0xbb,0xee}, {0x82,0xca,0xa6,0xfc}, {0x8b,0xc7,0xad,0xf2}, +{0xb4,0xe4,0x9c,0xd8}, {0xbd,0xe9,0x97,0xd6}, {0xa6,0xfe,0x8a,0xc4}, {0xaf,0xf3,0x81,0xca}, +{0xd8,0xb8,0xe8,0x90}, {0xd1,0xb5,0xe3,0x9e}, {0xca,0xa2,0xfe,0x8c}, {0xc3,0xaf,0xf5,0x82}, +{0xfc,0x8c,0xc4,0xa8}, {0xf5,0x81,0xcf,0xa6}, {0xee,0x96,0xd2,0xb4}, {0xe7,0x9b,0xd9,0xba}, +{0x3b,0xbb,0x7b,0xdb}, {0x32,0xb6,0x70,0xd5}, {0x29,0xa1,0x6d,0xc7}, {0x20,0xac,0x66,0xc9}, +{0x1f,0x8f,0x57,0xe3}, {0x16,0x82,0x5c,0xed}, {0x0d,0x95,0x41,0xff}, {0x04,0x98,0x4a,0xf1}, +{0x73,0xd3,0x23,0xab}, {0x7a,0xde,0x28,0xa5}, {0x61,0xc9,0x35,0xb7}, {0x68,0xc4,0x3e,0xb9}, +{0x57,0xe7,0x0f,0x93}, {0x5e,0xea,0x04,0x9d}, {0x45,0xfd,0x19,0x8f}, {0x4c,0xf0,0x12,0x81}, +{0xab,0x6b,0xcb,0x3b}, {0xa2,0x66,0xc0,0x35}, {0xb9,0x71,0xdd,0x27}, {0xb0,0x7c,0xd6,0x29}, +{0x8f,0x5f,0xe7,0x03}, {0x86,0x52,0xec,0x0d}, {0x9d,0x45,0xf1,0x1f}, {0x94,0x48,0xfa,0x11}, +{0xe3,0x03,0x93,0x4b}, {0xea,0x0e,0x98,0x45}, {0xf1,0x19,0x85,0x57}, {0xf8,0x14,0x8e,0x59}, +{0xc7,0x37,0xbf,0x73}, {0xce,0x3a,0xb4,0x7d}, {0xd5,0x2d,0xa9,0x6f}, {0xdc,0x20,0xa2,0x61}, +{0x76,0x6d,0xf6,0xad}, {0x7f,0x60,0xfd,0xa3}, {0x64,0x77,0xe0,0xb1}, {0x6d,0x7a,0xeb,0xbf}, +{0x52,0x59,0xda,0x95}, {0x5b,0x54,0xd1,0x9b}, {0x40,0x43,0xcc,0x89}, {0x49,0x4e,0xc7,0x87}, +{0x3e,0x05,0xae,0xdd}, {0x37,0x08,0xa5,0xd3}, {0x2c,0x1f,0xb8,0xc1}, {0x25,0x12,0xb3,0xcf}, +{0x1a,0x31,0x82,0xe5}, {0x13,0x3c,0x89,0xeb}, {0x08,0x2b,0x94,0xf9}, {0x01,0x26,0x9f,0xf7}, +{0xe6,0xbd,0x46,0x4d}, {0xef,0xb0,0x4d,0x43}, {0xf4,0xa7,0x50,0x51}, {0xfd,0xaa,0x5b,0x5f}, +{0xc2,0x89,0x6a,0x75}, {0xcb,0x84,0x61,0x7b}, {0xd0,0x93,0x7c,0x69}, {0xd9,0x9e,0x77,0x67}, +{0xae,0xd5,0x1e,0x3d}, {0xa7,0xd8,0x15,0x33}, {0xbc,0xcf,0x08,0x21}, {0xb5,0xc2,0x03,0x2f}, +{0x8a,0xe1,0x32,0x05}, {0x83,0xec,0x39,0x0b}, {0x98,0xfb,0x24,0x19}, {0x91,0xf6,0x2f,0x17}, +{0x4d,0xd6,0x8d,0x76}, {0x44,0xdb,0x86,0x78}, {0x5f,0xcc,0x9b,0x6a}, {0x56,0xc1,0x90,0x64}, +{0x69,0xe2,0xa1,0x4e}, {0x60,0xef,0xaa,0x40}, {0x7b,0xf8,0xb7,0x52}, {0x72,0xf5,0xbc,0x5c}, +{0x05,0xbe,0xd5,0x06}, {0x0c,0xb3,0xde,0x08}, {0x17,0xa4,0xc3,0x1a}, {0x1e,0xa9,0xc8,0x14}, +{0x21,0x8a,0xf9,0x3e}, {0x28,0x87,0xf2,0x30}, {0x33,0x90,0xef,0x22}, {0x3a,0x9d,0xe4,0x2c}, +{0xdd,0x06,0x3d,0x96}, {0xd4,0x0b,0x36,0x98}, {0xcf,0x1c,0x2b,0x8a}, {0xc6,0x11,0x20,0x84}, +{0xf9,0x32,0x11,0xae}, {0xf0,0x3f,0x1a,0xa0}, {0xeb,0x28,0x07,0xb2}, {0xe2,0x25,0x0c,0xbc}, +{0x95,0x6e,0x65,0xe6}, {0x9c,0x63,0x6e,0xe8}, {0x87,0x74,0x73,0xfa}, {0x8e,0x79,0x78,0xf4}, +{0xb1,0x5a,0x49,0xde}, {0xb8,0x57,0x42,0xd0}, {0xa3,0x40,0x5f,0xc2}, {0xaa,0x4d,0x54,0xcc}, +{0xec,0xda,0xf7,0x41}, {0xe5,0xd7,0xfc,0x4f}, {0xfe,0xc0,0xe1,0x5d}, {0xf7,0xcd,0xea,0x53}, +{0xc8,0xee,0xdb,0x79}, {0xc1,0xe3,0xd0,0x77}, {0xda,0xf4,0xcd,0x65}, {0xd3,0xf9,0xc6,0x6b}, +{0xa4,0xb2,0xaf,0x31}, {0xad,0xbf,0xa4,0x3f}, {0xb6,0xa8,0xb9,0x2d}, {0xbf,0xa5,0xb2,0x23}, +{0x80,0x86,0x83,0x09}, {0x89,0x8b,0x88,0x07}, {0x92,0x9c,0x95,0x15}, {0x9b,0x91,0x9e,0x1b}, +{0x7c,0x0a,0x47,0xa1}, {0x75,0x07,0x4c,0xaf}, {0x6e,0x10,0x51,0xbd}, {0x67,0x1d,0x5a,0xb3}, +{0x58,0x3e,0x6b,0x99}, {0x51,0x33,0x60,0x97}, {0x4a,0x24,0x7d,0x85}, {0x43,0x29,0x76,0x8b}, +{0x34,0x62,0x1f,0xd1}, {0x3d,0x6f,0x14,0xdf}, {0x26,0x78,0x09,0xcd}, {0x2f,0x75,0x02,0xc3}, +{0x10,0x56,0x33,0xe9}, {0x19,0x5b,0x38,0xe7}, {0x02,0x4c,0x25,0xf5}, {0x0b,0x41,0x2e,0xfb}, +{0xd7,0x61,0x8c,0x9a}, {0xde,0x6c,0x87,0x94}, {0xc5,0x7b,0x9a,0x86}, {0xcc,0x76,0x91,0x88}, +{0xf3,0x55,0xa0,0xa2}, {0xfa,0x58,0xab,0xac}, {0xe1,0x4f,0xb6,0xbe}, {0xe8,0x42,0xbd,0xb0}, +{0x9f,0x09,0xd4,0xea}, {0x96,0x04,0xdf,0xe4}, {0x8d,0x13,0xc2,0xf6}, {0x84,0x1e,0xc9,0xf8}, +{0xbb,0x3d,0xf8,0xd2}, {0xb2,0x30,0xf3,0xdc}, {0xa9,0x27,0xee,0xce}, {0xa0,0x2a,0xe5,0xc0}, +{0x47,0xb1,0x3c,0x7a}, {0x4e,0xbc,0x37,0x74}, {0x55,0xab,0x2a,0x66}, {0x5c,0xa6,0x21,0x68}, +{0x63,0x85,0x10,0x42}, {0x6a,0x88,0x1b,0x4c}, {0x71,0x9f,0x06,0x5e}, {0x78,0x92,0x0d,0x50}, +{0x0f,0xd9,0x64,0x0a}, {0x06,0xd4,0x6f,0x04}, {0x1d,0xc3,0x72,0x16}, {0x14,0xce,0x79,0x18}, +{0x2b,0xed,0x48,0x32}, {0x22,0xe0,0x43,0x3c}, {0x39,0xf7,0x5e,0x2e}, {0x30,0xfa,0x55,0x20}, +{0x9a,0xb7,0x01,0xec}, {0x93,0xba,0x0a,0xe2}, {0x88,0xad,0x17,0xf0}, {0x81,0xa0,0x1c,0xfe}, +{0xbe,0x83,0x2d,0xd4}, {0xb7,0x8e,0x26,0xda}, {0xac,0x99,0x3b,0xc8}, {0xa5,0x94,0x30,0xc6}, +{0xd2,0xdf,0x59,0x9c}, {0xdb,0xd2,0x52,0x92}, {0xc0,0xc5,0x4f,0x80}, {0xc9,0xc8,0x44,0x8e}, +{0xf6,0xeb,0x75,0xa4}, {0xff,0xe6,0x7e,0xaa}, {0xe4,0xf1,0x63,0xb8}, {0xed,0xfc,0x68,0xb6}, +{0x0a,0x67,0xb1,0x0c}, {0x03,0x6a,0xba,0x02}, {0x18,0x7d,0xa7,0x10}, {0x11,0x70,0xac,0x1e}, +{0x2e,0x53,0x9d,0x34}, {0x27,0x5e,0x96,0x3a}, {0x3c,0x49,0x8b,0x28}, {0x35,0x44,0x80,0x26}, +{0x42,0x0f,0xe9,0x7c}, {0x4b,0x02,0xe2,0x72}, {0x50,0x15,0xff,0x60}, {0x59,0x18,0xf4,0x6e}, +{0x66,0x3b,0xc5,0x44}, {0x6f,0x36,0xce,0x4a}, {0x74,0x21,0xd3,0x58}, {0x7d,0x2c,0xd8,0x56}, +{0xa1,0x0c,0x7a,0x37}, {0xa8,0x01,0x71,0x39}, {0xb3,0x16,0x6c,0x2b}, {0xba,0x1b,0x67,0x25}, +{0x85,0x38,0x56,0x0f}, {0x8c,0x35,0x5d,0x01}, {0x97,0x22,0x40,0x13}, {0x9e,0x2f,0x4b,0x1d}, +{0xe9,0x64,0x22,0x47}, {0xe0,0x69,0x29,0x49}, {0xfb,0x7e,0x34,0x5b}, {0xf2,0x73,0x3f,0x55}, +{0xcd,0x50,0x0e,0x7f}, {0xc4,0x5d,0x05,0x71}, {0xdf,0x4a,0x18,0x63}, {0xd6,0x47,0x13,0x6d}, +{0x31,0xdc,0xca,0xd7}, {0x38,0xd1,0xc1,0xd9}, {0x23,0xc6,0xdc,0xcb}, {0x2a,0xcb,0xd7,0xc5}, +{0x15,0xe8,0xe6,0xef}, {0x1c,0xe5,0xed,0xe1}, {0x07,0xf2,0xf0,0xf3}, {0x0e,0xff,0xfb,0xfd}, +{0x79,0xb4,0x92,0xa7}, {0x70,0xb9,0x99,0xa9}, {0x6b,0xae,0x84,0xbb}, {0x62,0xa3,0x8f,0xb5}, +{0x5d,0x80,0xbe,0x9f}, {0x54,0x8d,0xb5,0x91}, {0x4f,0x9a,0xa8,0x83}, {0x46,0x97,0xa3,0x8d} + } +}; +#define U4 xU4.xt8 + +static const word32 rcon[30] = { + 0x01,0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 +}; diff --git a/racoon.tproj/cfparse.y b/racoon.tproj/cfparse.y new file mode 100644 index 0000000..a3d87f0 --- /dev/null +++ b/racoon.tproj/cfparse.y @@ -0,0 +1,1374 @@ +/* $KAME: cfparse.y,v 1.111 2001/12/31 20:13:40 thorpej Exp $ */ + +%{ +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO) +#include "addrinfo.h" +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "str2val.h" +#include "debug.h" + +/*#include "cfparse.h"*/ +#include "cftoken.h" +#include "algorithm.h" +#include "localconf.h" +#include "policy.h" +#include "sainfo.h" +#include "oakley.h" +#include "pfkey.h" +#include "remoteconf.h" +#include "grabmyaddr.h" +#include "isakmp_var.h" +#include "handler.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "strnames.h" +#include "gcmalloc.h" +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif +#include "vendorid.h" + +struct proposalspec { + time_t lifetime; /* for isakmp/ipsec */ + int lifebyte; /* for isakmp/ipsec */ + struct secprotospec *spspec; /* the head is always current spec. */ + struct proposalspec *next; /* the tail is the most prefered. */ + struct proposalspec *prev; +}; + +struct secprotospec { + int prop_no; + int trns_no; + int strength; /* for isakmp/ipsec */ + int encklen; /* for isakmp/ipsec */ + time_t lifetime; /* for isakmp */ + int lifebyte; /* for isakmp */ + int proto_id; /* for ipsec (isakmp?) */ + int ipsec_level; /* for ipsec */ + int encmode; /* for ipsec */ + int vendorid; /* for isakmp */ + char *gssid; + struct sockaddr *remote; + int algclass[MAXALGCLASS]; + + struct secprotospec *next; /* the tail is the most prefiered. */ + struct secprotospec *prev; + struct proposalspec *back; +}; + +static int num2dhgroup[] = { + 0, + OAKLEY_ATTR_GRP_DESC_MODP768, + OAKLEY_ATTR_GRP_DESC_MODP1024, + OAKLEY_ATTR_GRP_DESC_EC2N155, + OAKLEY_ATTR_GRP_DESC_EC2N185, + OAKLEY_ATTR_GRP_DESC_MODP1536, +}; + +static struct remoteconf *cur_rmconf; +static int tmpalgtype[MAXALGCLASS]; +static struct sainfo *cur_sainfo; +static int cur_algclass; + +static struct proposalspec *prhead; /* the head is always current. */ + +static struct proposalspec *newprspec __P((void)); +static void cleanprhead __P((void)); +static void insprspec __P((struct proposalspec *, struct proposalspec **)); +static struct secprotospec *newspspec __P((void)); +static void insspspec __P((struct secprotospec *, struct proposalspec **)); + +static int set_isakmp_proposal + __P((struct remoteconf *, struct proposalspec *)); +static void clean_tmpalgtype __P((void)); +static int expand_isakmpspec __P((int, int, int *, + int, int, time_t, int, int, int, char *, struct remoteconf *)); + +#if 0 +static int fix_lifebyte __P((u_long)); +#endif +%} + +%union { + unsigned long num; + vchar_t *val; + struct remoteconf *rmconf; + struct sockaddr *saddr; + struct sainfoalg *alg; +} + + /* path */ +%token PATH PATHTYPE + /* include */ +%token INCLUDE + /* self information */ +%token IDENTIFIER VENDORID + /* logging */ +%token LOGGING LOGLEV + /* padding */ +%token PADDING PAD_RANDOMIZE PAD_RANDOMIZELEN PAD_MAXLEN PAD_STRICT PAD_EXCLTAIL + /* listen */ +%token LISTEN X_ISAKMP X_ADMIN STRICT_ADDRESS + /* timer */ +%token RETRY RETRY_COUNTER RETRY_INTERVAL RETRY_PERSEND +%token RETRY_PHASE1 RETRY_PHASE2 + /* algorithm */ +%token ALGORITHM_CLASS ALGORITHMTYPE STRENGTHTYPE + /* sainfo */ +%token SAINFO + /* remote */ +%token REMOTE ANONYMOUS +%token EXCHANGE_MODE EXCHANGETYPE DOI DOITYPE SITUATION SITUATIONTYPE +%token CERTIFICATE_TYPE CERTTYPE PEERS_CERTFILE VERIFY_CERT SEND_CERT SEND_CR +%token IDENTIFIERTYPE MY_IDENTIFIER PEERS_IDENTIFIER VERIFY_IDENTIFIER +%token DNSSEC CERT_X509 +%token NONCE_SIZE DH_GROUP KEEPALIVE PASSIVE INITIAL_CONTACT +%token PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL +%token GENERATE_POLICY SUPPORT_MIP6 +%token PROPOSAL +%token EXEC_PATH EXEC_COMMAND EXEC_SUCCESS EXEC_FAILURE +%token GSSAPI_ID +%token COMPLEX_BUNDLE + +%token PREFIX PORT PORTANY UL_PROTO ANY +%token PFS_GROUP LIFETIME LIFETYPE_TIME LIFETYPE_BYTE STRENGTH + +%token NUMBER SWITCH BOOLEAN +%token HEXSTRING QUOTEDSTRING ADDRSTRING +%token UNITTYPE_BYTE UNITTYPE_KBYTES UNITTYPE_MBYTES UNITTYPE_TBYTES +%token UNITTYPE_SEC UNITTYPE_MIN UNITTYPE_HOUR +%token EOS BOC EOC COMMA + +%type NUMBER BOOLEAN SWITCH keylength +%type PATHTYPE IDENTIFIERTYPE LOGLEV +%type ALGORITHM_CLASS dh_group_num +%type ALGORITHMTYPE STRENGTHTYPE +%type PREFIX prefix PORT port ike_port +%type ul_proto UL_PROTO +%type EXCHANGETYPE DOITYPE SITUATIONTYPE +%type CERTTYPE CERT_X509 PROPOSAL_CHECK_LEVEL +%type unittype_time unittype_byte +%type QUOTEDSTRING HEXSTRING ADDRSTRING sainfo_id +%type identifierstring +%type remote_index ike_addrinfo_port +%type algorithm + +%% + +statements + : /* nothing */ + | statements statement + ; +statement + : path_statement + | include_statement + | identifier_statement + | logging_statement + | padding_statement + | listen_statement + | timer_statement + | sainfo_statement + | remote_statement + | special_statement + ; + + /* path */ +path_statement + : PATH PATHTYPE QUOTEDSTRING + { + if ($2 > LC_PATHTYPE_MAX) { + yyerror("invalid path type %d", $2); + return -1; + } + + /* free old pathinfo */ + if (lcconf->pathinfo[$2]) + racoon_free(lcconf->pathinfo[$2]); + + /* set new pathinfo */ + lcconf->pathinfo[$2] = strdup($3->v); + vfree($3); + } + EOS + ; + + /* special */ +special_statement + : COMPLEX_BUNDLE SWITCH { lcconf->complex_bundle = $2; } EOS + ; + + /* include */ +include_statement + : INCLUDE QUOTEDSTRING + { + char path[MAXPATHLEN]; + + getpathname(path, sizeof(path), + LC_PATHTYPE_INCLUDE, $2->v); + vfree($2); + if (yycf_switch_buffer(path) != 0) + return -1; + } + EOS + ; + + /* self infomation */ +identifier_statement + : IDENTIFIER identifier_stmt + ; +identifier_stmt + : VENDORID + { + /*XXX to be deleted */ + } + QUOTEDSTRING EOS + | IDENTIFIERTYPE QUOTEDSTRING + { + /*XXX to be deleted */ + $2->l--; /* nuke '\0' */ + lcconf->ident[$1] = $2; + if (lcconf->ident[$1] == NULL) { + yyerror("failed to set my ident: %s", + strerror(errno)); + return -1; + } + } + EOS + ; + + /* logging */ +logging_statement + : LOGGING log_level EOS + ; +log_level + : HEXSTRING + { + /* + * XXX ignore it because this specification + * will be obsoleted. + */ + yywarn("see racoon.conf(5), such a log specification will be obsoleted."); + vfree($1); + } + | LOGLEV + { + /* + * set the loglevel by configuration file only when + * the command line did not specify any loglevel. + */ + if (loglevel <= LLV_BASE) + loglevel += $1; + } + ; + + /* padding */ +padding_statement + : PADDING BOC padding_stmts EOC + ; +padding_stmts + : /* nothing */ + | padding_stmts padding_stmt + ; +padding_stmt + : PAD_RANDOMIZE SWITCH { lcconf->pad_random = $2; } EOS + | PAD_RANDOMIZELEN SWITCH { lcconf->pad_randomlen = $2; } EOS + | PAD_MAXLEN NUMBER { lcconf->pad_maxsize = $2; } EOS + | PAD_STRICT SWITCH { lcconf->pad_strict = $2; } EOS + | PAD_EXCLTAIL SWITCH { lcconf->pad_excltail = $2; } EOS + ; + + /* listen */ +listen_statement + : LISTEN BOC listen_stmts EOC + ; +listen_stmts + : /* nothing */ + | listen_stmts listen_stmt + ; +listen_stmt + : X_ISAKMP ike_addrinfo_port + { + struct myaddrs *p; + + p = newmyaddr(); + if (p == NULL) { + yyerror("failed to allocate myaddrs"); + return -1; + } + p->addr = $2; + if (p->addr == NULL) { + yyerror("failed to copy sockaddr "); + delmyaddr(p); + return -1; + } + + insmyaddr(p, &lcconf->myaddrs); + + lcconf->autograbaddr = 0; + } + EOS + | X_ADMIN + { + yyerror("admin directive is obsoleted."); + } + PORT EOS + | STRICT_ADDRESS { lcconf->strict_address = TRUE; } EOS + ; +ike_addrinfo_port + : ADDRSTRING ike_port + { + char portbuf[10]; + + snprintf(portbuf, sizeof(portbuf), "%ld", $2); + $$ = str2saddr($1->v, portbuf); + vfree($1); + if (!$$) + return -1; + } + ; +ike_port + : /* nothing */ { $$ = PORT_ISAKMP; } + | PORT { $$ = $1; } + ; + + /* timer */ +timer_statement + : RETRY BOC timer_stmts EOC + ; +timer_stmts + : /* nothing */ + | timer_stmts timer_stmt + ; +timer_stmt + : RETRY_COUNTER NUMBER + { + lcconf->retry_counter = $2; + } + EOS + | RETRY_INTERVAL NUMBER unittype_time + { + lcconf->retry_interval = $2 * $3; + } + EOS + | RETRY_PERSEND NUMBER + { + lcconf->count_persend = $2; + } + EOS + | RETRY_PHASE1 NUMBER unittype_time + { + lcconf->retry_checkph1 = $2 * $3; + } + EOS + | RETRY_PHASE2 NUMBER unittype_time + { + lcconf->wait_ph2complete = $2 * $3; + } + EOS + ; + + /* sainfo */ +sainfo_statement + : SAINFO + { + cur_sainfo = newsainfo(); + if (cur_sainfo == NULL) { + yyerror("failed to allocate sainfo"); + return -1; + } + } + sainfo_name BOC sainfo_specs + { + struct sainfo *check; + + /* default */ + if (cur_sainfo->algs[algclass_ipsec_enc] == 0) { + yyerror("no encryption algorithm at %s", + sainfo2str(cur_sainfo)); + return -1; + } + if (cur_sainfo->algs[algclass_ipsec_auth] == 0) { + yyerror("no authentication algorithm at %s", + sainfo2str(cur_sainfo)); + return -1; + } + if (cur_sainfo->algs[algclass_ipsec_comp] == 0) { + yyerror("no compression algorithm at %s", + sainfo2str(cur_sainfo)); + return -1; + } + + /* duplicate check */ + check = getsainfo(cur_sainfo->idsrc, cur_sainfo->iddst); + if (check && (!check->idsrc && !cur_sainfo->idsrc)) { + yyerror("duplicated sainfo: %s", + sainfo2str(cur_sainfo)); + return -1; + } + inssainfo(cur_sainfo); + } + EOC + ; +sainfo_name + : ANONYMOUS + { + cur_sainfo->idsrc = NULL; + cur_sainfo->iddst = NULL; + } + | sainfo_id sainfo_id + { + cur_sainfo->idsrc = $1; + cur_sainfo->iddst = $2; + } + ; +sainfo_id + : IDENTIFIERTYPE ADDRSTRING prefix port ul_proto + { + char portbuf[10]; + struct sockaddr *saddr; + + if (($5 == IPPROTO_ICMP || $5 == IPPROTO_ICMPV6) + && ($4 != IPSEC_PORT_ANY || $4 != IPSEC_PORT_ANY)) { + yyerror("port number must be \"any\"."); + return -1; + } + + snprintf(portbuf, sizeof(portbuf), "%lu", $4); + saddr = str2saddr($2->v, portbuf); + vfree($2); + if (saddr == NULL) + return -1; + + switch (saddr->sa_family) { + case AF_INET: + if ($5 == IPPROTO_ICMPV6) { + yyerror("upper layer protocol mismatched.\n"); + racoon_free(saddr); + return -1; + } + $$ = ipsecdoi_sockaddr2id(saddr, + $3 == ~0 ? (sizeof(struct in_addr) << 3): $3, + $5); + break; +#ifdef INET6 + case AF_INET6: + if ($5 == IPPROTO_ICMP) { + yyerror("upper layer protocol mismatched.\n"); + racoon_free(saddr); + return -1; + } + $$ = ipsecdoi_sockaddr2id(saddr, + $3 == ~0 ? (sizeof(struct in6_addr) << 3) : $3, + $5); + break; +#endif + default: + yyerror("invalid family: %d", saddr->sa_family); + break; + } + racoon_free(saddr); + if ($$ == NULL) + return -1; + } + | IDENTIFIERTYPE QUOTEDSTRING + { + struct ipsecdoi_id_b *id_b; + + if ($1 == IDTYPE_ASN1DN) { + yyerror("id type forbidden: %d", $1); + return -1; + } + + $2->l--; + + $$ = vmalloc(sizeof(*id_b) + $2->l); + if ($$ == NULL) { + yyerror("failed to allocate identifier"); + return -1; + } + + id_b = (struct ipsecdoi_id_b *)$$->v; + id_b->type = idtype2doi($1); + + id_b->proto_id = 0; + id_b->port = 0; + + memcpy($$->v + sizeof(*id_b), $2->v, $2->l); + } + ; +sainfo_specs + : /* nothing */ + | sainfo_specs sainfo_spec + ; +sainfo_spec + : PFS_GROUP dh_group_num + { + cur_sainfo->pfs_group = $2; + } + EOS + | LIFETIME LIFETYPE_TIME NUMBER unittype_time + { + cur_sainfo->lifetime = $3 * $4; + } + EOS + | LIFETIME LIFETYPE_BYTE NUMBER unittype_byte + { +#if 1 + yyerror("byte lifetime support is deprecated"); + return -1; +#else + cur_sainfo->lifebyte = fix_lifebyte($3 * $4); + if (cur_sainfo->lifebyte == 0) + return -1; +#endif + } + EOS + | ALGORITHM_CLASS { + cur_algclass = $1; + } + algorithms EOS + | IDENTIFIER IDENTIFIERTYPE + { + yyerror("it's deprecated to specify a identifier in phase 2"); + } + EOS + | MY_IDENTIFIER IDENTIFIERTYPE QUOTEDSTRING + { + yyerror("it's deprecated to specify a identifier in phase 2"); + } + EOS + ; + +algorithms + : algorithm + { + inssainfoalg(&cur_sainfo->algs[cur_algclass], $1); + } + | algorithm + { + inssainfoalg(&cur_sainfo->algs[cur_algclass], $1); + } + COMMA algorithms + ; +algorithm + : ALGORITHMTYPE keylength + { + int defklen; + + $$ = newsainfoalg(); + if ($$ == NULL) { + yyerror("failed to get algorithm alocation"); + return -1; + } + + $$->alg = algtype2doi(cur_algclass, $1); + if ($$->alg == -1) { + yyerror("algorithm mismatched"); + racoon_free($$); + return -1; + } + + defklen = default_keylen(cur_algclass, $1); + if (defklen == 0) { + if ($2) { + yyerror("keylen not allowed"); + racoon_free($$); + return -1; + } + } else { + if ($2 && check_keylen(cur_algclass, $1, $2) < 0) { + yyerror("invalid keylen %d", $2); + racoon_free($$); + return -1; + } + } + + if ($2) + $$->encklen = $2; + else + $$->encklen = defklen; + + /* check if it's supported algorithm by kernel */ + if (!(cur_algclass == algclass_ipsec_auth && $1 == algtype_non_auth) + && pk_checkalg(cur_algclass, $1, $$->encklen)) { + int a = algclass2doi(cur_algclass); + int b = algtype2doi(cur_algclass, $1); + if (a == IPSECDOI_ATTR_AUTH) + a = IPSECDOI_PROTO_IPSEC_AH; + yyerror("algorithm %s not supported", + s_ipsecdoi_trns(a, b)); + racoon_free($$); + return -1; + } + } + ; +prefix + : /* nothing */ { $$ = ~0; } + | PREFIX { $$ = $1; } + ; +port + : /* nothing */ { $$ = IPSEC_PORT_ANY; } + | PORT { $$ = $1; } + | PORTANY { $$ = IPSEC_PORT_ANY; } + ; +ul_proto + : NUMBER { $$ = $1; } + | UL_PROTO { $$ = $1; } + | ANY { $$ = IPSEC_ULPROTO_ANY; } + ; +keylength + : /* nothing */ { $$ = 0; } + | NUMBER { $$ = $1; } + ; + + /* remote */ +remote_statement + : REMOTE remote_index + { + struct remoteconf *new; + struct proposalspec *prspec; + + new = newrmconf(); + if (new == NULL) { + yyerror("failed to get new remoteconf."); + return -1; + } + + new->remote = $2; + cur_rmconf = new; + + prspec = newprspec(); + if (prspec == NULL) + return -1; + prspec->lifetime = oakley_get_defaultlifetime(); + insprspec(prspec, &prhead); + } + BOC remote_specs + { + /* check a exchange mode */ + if (cur_rmconf->etypes == NULL) { + yyerror("no exchange mode specified.\n"); + return -1; + } + + if (cur_rmconf->idvtype == IDTYPE_ASN1DN + && cur_rmconf->mycertfile == NULL) { + yyerror("id type mismatched due to " + "no CERT defined.\n"); + return -1; + } + + if (set_isakmp_proposal(cur_rmconf, prhead) != 0) + return -1; + + /* DH group settting if aggressive mode is there. */ + if (check_etypeok(cur_rmconf, ISAKMP_ETYPE_AGG) != NULL) { + struct isakmpsa *p; + int b = 0; + + /* DH group */ + for (p = cur_rmconf->proposal; p; p = p->next) { + if (b == 0 || (b && b == p->dh_group)) { + b = p->dh_group; + continue; + } + yyerror("DH group must be equal " + "to each proposals's " + "when aggressive mode is " + "used.\n"); + return -1; + } + cur_rmconf->dh_group = b; + + if (cur_rmconf->dh_group == 0) { + yyerror("DH group must be required.\n"); + return -1; + } + + /* DH group settting if PFS is required. */ + if (oakley_setdhgroup(cur_rmconf->dh_group, + &cur_rmconf->dhgrp) < 0) { + yyerror("failed to set DH value.\n"); + return -1; + } + } + + insrmconf(cur_rmconf); + + cleanprhead(); + } + EOC + ; +remote_index + : ANONYMOUS ike_port + { + $$ = newsaddr(sizeof(struct sockaddr *)); + $$->sa_family = AF_UNSPEC; + ((struct sockaddr_in *)$$)->sin_port = htons($2); + } + | ike_addrinfo_port + { + $$ = $1; + if ($$ == NULL) { + yyerror("failed to allocate sockaddr"); + return -1; + } + } + ; +remote_specs + : /* nothing */ + | remote_specs remote_spec + ; +remote_spec + : EXCHANGE_MODE exchange_types EOS + | DOI DOITYPE { cur_rmconf->doitype = $2; } EOS + | SITUATION SITUATIONTYPE { cur_rmconf->sittype = $2; } EOS + | CERTIFICATE_TYPE cert_spec + | PEERS_CERTFILE QUOTEDSTRING + { +#ifdef HAVE_SIGNING_C + cur_rmconf->getcert_method = ISAKMP_GETCERT_LOCALFILE; + cur_rmconf->peerscertfile = strdup($2->v); + vfree($2); +#else + yyerror("directive not supported"); + return -1; +#endif + } + EOS + | PEERS_CERTFILE DNSSEC + { +#ifdef HAVE_SIGNING_C + cur_rmconf->getcert_method = ISAKMP_GETCERT_DNS; + cur_rmconf->peerscertfile = NULL; +#else + yyerror("directive not supported"); + return -1; +#endif + } + EOS + | VERIFY_CERT SWITCH { cur_rmconf->verify_cert = $2; } EOS + | SEND_CERT SWITCH { cur_rmconf->send_cert = $2; } EOS + | SEND_CR SWITCH { cur_rmconf->send_cr = $2; } EOS + | IDENTIFIER IDENTIFIERTYPE + { + /*XXX to be deleted */ + cur_rmconf->idvtype = $2; + } + EOS + | MY_IDENTIFIER IDENTIFIERTYPE identifierstring + { + if (set_identifier(&cur_rmconf->idv, $2, $3) != 0) { + yyerror("failed to set identifer.\n"); + return -1; + } + cur_rmconf->idvtype = $2; + } + EOS + | PEERS_IDENTIFIER IDENTIFIERTYPE identifierstring + { + if (set_identifier(&cur_rmconf->idv_p, $2, $3) != 0) { + yyerror("failed to set identifer.\n"); + return -1; + } + cur_rmconf->idvtype_p = $2; + } + EOS + | VERIFY_IDENTIFIER SWITCH { cur_rmconf->verify_identifier = $2; } EOS + | NONCE_SIZE NUMBER { cur_rmconf->nonce_size = $2; } EOS + | DH_GROUP + { + yyerror("dh_group cannot be defined here."); + return -1; + } + dh_group_num EOS + | KEEPALIVE { cur_rmconf->keepalive = TRUE; } EOS + | PASSIVE SWITCH { cur_rmconf->passive = $2; } EOS + | GENERATE_POLICY SWITCH { cur_rmconf->gen_policy = $2; } EOS + | SUPPORT_MIP6 SWITCH { cur_rmconf->support_mip6 = $2; } EOS + | INITIAL_CONTACT SWITCH { cur_rmconf->ini_contact = $2; } EOS + | PROPOSAL_CHECK PROPOSAL_CHECK_LEVEL { cur_rmconf->pcheck_level = $2; } EOS + | LIFETIME LIFETYPE_TIME NUMBER unittype_time + { + prhead->lifetime = $3 * $4; + } + EOS + | LIFETIME LIFETYPE_BYTE NUMBER unittype_byte + { +#if 1 + yyerror("byte lifetime support is deprecated"); + return -1; +#else + yywarn("the lifetime of bytes in phase 1 " + "will be ignored at the moment."); + prhead->lifebyte = fix_lifebyte($3 * $4); + if (prhead->lifebyte == 0) + return -1; +#endif + } + EOS + | PROPOSAL + { + struct secprotospec *spspec; + + spspec = newspspec(); + if (spspec == NULL) + return -1; + insspspec(spspec, &prhead); + } + BOC isakmpproposal_specs EOC + ; +exchange_types + : /* nothing */ + | exchange_types EXCHANGETYPE + { + struct etypes *new; + new = racoon_malloc(sizeof(struct etypes)); + if (new == NULL) { + yyerror("filed to allocate etypes"); + return -1; + } + new->type = $2; + new->next = NULL; + if (cur_rmconf->etypes == NULL) + cur_rmconf->etypes = new; + else { + struct etypes *p; + for (p = cur_rmconf->etypes; + p->next != NULL; + p = p->next) + ; + p->next = new; + } + } + ; +cert_spec + : CERT_X509 QUOTEDSTRING QUOTEDSTRING + { +#ifdef HAVE_SIGNING_C + cur_rmconf->certtype = $1; + cur_rmconf->mycertfile = strdup($2->v); + vfree($2); + cur_rmconf->myprivfile = strdup($3->v); + vfree($3); +#else + yyerror("directive not supported"); + return -1; +#endif + } + EOS + ; +dh_group_num + : ALGORITHMTYPE + { + $$ = algtype2doi(algclass_isakmp_dh, $1); + if ($$ == -1) { + yyerror("must be DH group"); + return -1; + } + } + | NUMBER + { + if (ARRAYLEN(num2dhgroup) > $1 && num2dhgroup[$1] != 0) { + $$ = num2dhgroup[$1]; + } else { + yyerror("must be DH group"); + return -1; + } + } + ; +identifierstring + : /* nothing */ { $$ = NULL; } + | ADDRSTRING { $$ = $1; } + | QUOTEDSTRING { $$ = $1; } + ; +isakmpproposal_specs + : /* nothing */ + | isakmpproposal_specs isakmpproposal_spec + ; +isakmpproposal_spec + : STRENGTH + { + yyerror("strength directive is obsoleted."); + } STRENGTHTYPE EOS + | LIFETIME LIFETYPE_TIME NUMBER unittype_time + { + prhead->spspec->lifetime = $3 * $4; + } + EOS + | LIFETIME LIFETYPE_BYTE NUMBER unittype_byte + { +#if 1 + yyerror("byte lifetime support is deprecated"); + return -1; +#else + prhead->spspec->lifebyte = fix_lifebyte($3 * $4); + if (prhead->spspec->lifebyte == 0) + return -1; +#endif + } + EOS + | DH_GROUP dh_group_num + { + prhead->spspec->algclass[algclass_isakmp_dh] = $2; + } + EOS + | GSSAPI_ID QUOTEDSTRING + { + if (prhead->spspec->vendorid != VENDORID_GSSAPI) { + yyerror("wrong Vendor ID for gssapi_id"); + return -1; + } + prhead->spspec->gssid = strdup($2->v); + } + EOS + | ALGORITHM_CLASS ALGORITHMTYPE keylength + { + int doi; + int defklen; + + doi = algtype2doi($1, $2); + if (doi == -1) { + yyerror("algorithm mismatched 1"); + return -1; + } + + switch ($1) { + case algclass_isakmp_enc: + /* reject suppressed algorithms */ +#ifndef HAVE_OPENSSL_RC5_H + if ($2 == algtype_rc5) { + yyerror("algorithm %s not supported", + s_attr_isakmp_enc(doi)); + return -1; + } +#endif +#ifndef HAVE_OPENSSL_IDEA_H + if ($2 == algtype_idea) { + yyerror("algorithm %s not supported", + s_attr_isakmp_enc(doi)); + return -1; + } +#endif + + prhead->spspec->algclass[algclass_isakmp_enc] = doi; + defklen = default_keylen($1, $2); + if (defklen == 0) { + if ($3) { + yyerror("keylen not allowed"); + return -1; + } + } else { + if ($3 && check_keylen($1, $2, $3) < 0) { + yyerror("invalid keylen %d", $3); + return -1; + } + } + if ($3) + prhead->spspec->encklen = $3; + else + prhead->spspec->encklen = defklen; + break; + case algclass_isakmp_hash: + prhead->spspec->algclass[algclass_isakmp_hash] = doi; + break; + case algclass_isakmp_ameth: + prhead->spspec->algclass[algclass_isakmp_ameth] = doi; + /* + * We may have to set the Vendor ID for the + * authentication method we're using. + */ + switch ($2) { + case algtype_gssapikrb: + if (prhead->spspec->vendorid != + VENDORID_UNKNOWN) { + yyerror("Vendor ID mismatch " + "for auth method"); + return -1; + } + /* + * For interoperability with Win2k, + * we set the Vendor ID to "GSSAPI". + */ + prhead->spspec->vendorid = + VENDORID_GSSAPI; + break; + default: + break; + } + break; + default: + yyerror("algorithm mismatched 2"); + return -1; + } + } + EOS + ; + +unittype_time + : UNITTYPE_SEC { $$ = 1; } + | UNITTYPE_MIN { $$ = 60; } + | UNITTYPE_HOUR { $$ = (60 * 60); } + ; +unittype_byte + : UNITTYPE_BYTE { $$ = 1; } + | UNITTYPE_KBYTES { $$ = 1024; } + | UNITTYPE_MBYTES { $$ = (1024 * 1024); } + | UNITTYPE_TBYTES { $$ = (1024 * 1024 * 1024); } + ; +%% + +static struct proposalspec * +newprspec() +{ + struct proposalspec *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + yyerror("failed to allocate proposal"); + + return new; +} + +static void +cleanprhead() +{ + struct proposalspec *p, *next; + + if (prhead == NULL) + return; + + for (p = prhead; p != NULL; p = next) { + next = p->next; + racoon_free(p); + } + + prhead = NULL; +} + +/* + * insert into head of list. + */ +static void +insprspec(prspec, head) + struct proposalspec *prspec; + struct proposalspec **head; +{ + if (*head != NULL) + (*head)->prev = prspec; + prspec->next = *head; + *head = prspec; +} + +static struct secprotospec * +newspspec() +{ + struct secprotospec *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) { + yyerror("failed to allocate spproto"); + return NULL; + } + + new->encklen = 0; /*XXX*/ + + /* + * Default to "uknown" vendor -- we will override this + * as necessary. When we send a Vendor ID payload, an + * "unknown" will be translated to a KAME/racoon ID. + */ + new->vendorid = VENDORID_UNKNOWN; + + return new; +} + +/* + * insert into head of list. + */ +static void +insspspec(spspec, head) + struct secprotospec *spspec; + struct proposalspec **head; +{ + spspec->back = *head; + + if ((*head)->spspec != NULL) + (*head)->spspec->prev = spspec; + spspec->next = (*head)->spspec; + (*head)->spspec = spspec; +} + +/* set final acceptable proposal */ +static int +set_isakmp_proposal(rmconf, prspec) + struct remoteconf *rmconf; + struct proposalspec *prspec; +{ + struct proposalspec *p; + struct secprotospec *s; + int prop_no = 1; + int trns_no = 1; + u_int32_t types[MAXALGCLASS]; + + p = prspec; + if (p->next != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "multiple proposal definition.\n"); + return -1; + } + + /* mandatory check */ + if (p->spspec == NULL) { + yyerror("no remote specification found: %s.\n", + rm2str(rmconf)); + return -1; + } + for (s = p->spspec; s != NULL; s = s->next) { + /* XXX need more to check */ + if (s->algclass[algclass_isakmp_enc] == 0) { + yyerror("encryption algorithm required."); + return -1; + } + if (s->algclass[algclass_isakmp_hash] == 0) { + yyerror("hash algorithm required."); + return -1; + } + if (s->algclass[algclass_isakmp_dh] == 0) { + yyerror("DH group required."); + return -1; + } + if (s->algclass[algclass_isakmp_ameth] == 0) { + yyerror("authentication method required."); + return -1; + } + } + + /* skip to last part */ + for (s = p->spspec; s->next != NULL; s = s->next) + ; + + while (s != NULL) { + plog(LLV_DEBUG2, LOCATION, NULL, + "lifetime = %ld\n", (long) + (s->lifetime ? s->lifetime : p->lifetime)); + plog(LLV_DEBUG2, LOCATION, NULL, + "lifebyte = %d\n", + s->lifebyte ? s->lifebyte : p->lifebyte); + plog(LLV_DEBUG2, LOCATION, NULL, + "encklen=%d\n", s->encklen); + + memset(types, 0, ARRAYLEN(types)); + types[algclass_isakmp_enc] = s->algclass[algclass_isakmp_enc]; + types[algclass_isakmp_hash] = s->algclass[algclass_isakmp_hash]; + types[algclass_isakmp_dh] = s->algclass[algclass_isakmp_dh]; + types[algclass_isakmp_ameth] = + s->algclass[algclass_isakmp_ameth]; + + /* expanding spspec */ + clean_tmpalgtype(); + trns_no = expand_isakmpspec(prop_no, trns_no, types, + algclass_isakmp_enc, algclass_isakmp_ameth + 1, + s->lifetime ? s->lifetime : p->lifetime, + s->lifebyte ? s->lifebyte : p->lifebyte, + s->encklen, s->vendorid, s->gssid, + rmconf); + if (trns_no == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to expand isakmp proposal.\n"); + return -1; + } + + s = s->prev; + } + + if (rmconf->proposal == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no proposal found.\n"); + return -1; + } + + return 0; +} + +static void +clean_tmpalgtype() +{ + int i; + for (i = 0; i < MAXALGCLASS; i++) + tmpalgtype[i] = 0; /* means algorithm undefined. */ +} + +static int +expand_isakmpspec(prop_no, trns_no, types, + class, last, lifetime, lifebyte, encklen, vendorid, gssid, + rmconf) + int prop_no, trns_no; + int *types, class, last; + time_t lifetime; + int lifebyte; + int encklen; + int vendorid; + char *gssid; + struct remoteconf *rmconf; +{ + struct isakmpsa *new; + + /* debugging */ + { + int j; + char tb[10]; + plog(LLV_DEBUG2, LOCATION, NULL, + "p:%d t:%d\n", prop_no, trns_no); + for (j = class; j < MAXALGCLASS; j++) { + snprintf(tb, sizeof(tb), "%d", types[j]); + plog(LLV_DEBUG2, LOCATION, NULL, + "%s%s%s%s\n", + s_algtype(j, types[j]), + types[j] ? "(" : "", + tb[0] == '0' ? "" : tb, + types[j] ? ")" : ""); + } + plog(LLV_DEBUG2, LOCATION, NULL, "\n"); + } + +#define TMPALGTYPE2STR(n) \ + s_algtype(algclass_isakmp_##n, types[algclass_isakmp_##n]) + /* check mandatory values */ + if (types[algclass_isakmp_enc] == 0 + || types[algclass_isakmp_ameth] == 0 + || types[algclass_isakmp_hash] == 0 + || types[algclass_isakmp_dh] == 0) { + yyerror("few definition of algorithm " + "enc=%s ameth=%s hash=%s dhgroup=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(ameth), + TMPALGTYPE2STR(hash), + TMPALGTYPE2STR(dh)); + return -1; + } +#undef TMPALGTYPE2STR + + /* set new sa */ + new = newisakmpsa(); + if (new == NULL) { + yyerror("failed to allocate isakmp sa"); + return -1; + } + new->prop_no = prop_no; + new->trns_no = trns_no++; + new->lifetime = lifetime; + new->lifebyte = lifebyte; + new->enctype = types[algclass_isakmp_enc]; + new->encklen = encklen; + new->authmethod = types[algclass_isakmp_ameth]; + new->hashtype = types[algclass_isakmp_hash]; + new->dh_group = types[algclass_isakmp_dh]; + new->vendorid = vendorid; +#ifdef HAVE_GSSAPI + if (gssid != NULL) { + new->gssid = vmalloc(strlen(gssid) + 1); + memcpy(new->gssid->v, gssid, new->gssid->l); + racoon_free(gssid); + } else + new->gssid = NULL; +#endif + insisakmpsa(new, rmconf); + + return trns_no; +} + +#if 0 +/* + * fix lifebyte. + * Must be more than 1024B because its unit is kilobytes. + * That is defined RFC2407. + */ +static int +fix_lifebyte(t) + unsigned long t; +{ + if (t < 1024) { + yyerror("byte size should be more than 1024B."); + return 0; + } + + return(t / 1024); +} +#endif + +int +cfparse() +{ + int error; + + yycf_init_buffer(); + + if (yycf_set_buffer(lcconf->racoon_conf) != 0) + return -1; + + prhead = NULL; + + error = yyparse(); + if (error != 0) { + if (yyerrorcount) { + plog(LLV_ERROR, LOCATION, NULL, + "fatal parse failure (%d errors)\n", + yyerrorcount); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "fatal parse failure.\n"); + } + return -1; + } + + if (error == 0 && yyerrorcount) { + plog(LLV_ERROR, LOCATION, NULL, + "parse error is nothing, but yyerrorcount is %d.\n", + yyerrorcount); + exit(1); + } + + yycf_clean_buffer(); + + plog(LLV_DEBUG2, LOCATION, NULL, "parse successed.\n"); + + return 0; +} + +int +cfreparse() +{ + flushph2(); + flushph1(); + flushrmconf(); + cleanprhead(); + clean_tmpalgtype(); + yycf_init_buffer(); + + if (yycf_set_buffer(lcconf->racoon_conf) != 0) + return -1; + + return(cfparse()); +} + diff --git a/racoon.tproj/cftoken.h b/racoon.tproj/cftoken.h new file mode 100644 index 0000000..b70fce4 --- /dev/null +++ b/racoon.tproj/cftoken.h @@ -0,0 +1,41 @@ +/* $KAME: cftoken.h,v 1.3 2000/09/13 04:50:24 itojun 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. 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. + */ + +extern int yyerrorcount; + +extern int yylex __P((void)); +extern void yyerror __P((char *, ...)); +extern void yywarn __P((char *, ...)); + +extern int yycf_switch_buffer __P((char *)); +extern int yycf_set_buffer __P((char *)); +extern void yycf_init_buffer __P((void)); +extern void yycf_clean_buffer __P((void)); diff --git a/racoon.tproj/cftoken.l b/racoon.tproj/cftoken.l new file mode 100644 index 0000000..e05a0ae --- /dev/null +++ b/racoon.tproj/cftoken.l @@ -0,0 +1,533 @@ +/* $KAME: cftoken.l,v 1.66 2001/12/07 03:35:14 sakane Exp $ */ + +%{ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "algorithm.h" +#include "cfparse.h" +#include "cftoken.h" +#include "localconf.h" +#include "oakley.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "proposal.h" +#ifdef GC +#include "gcmalloc.h" +#endif + +/*#include "y.tab.h"*/ + +int yyerrorcount = 0; + +#if defined(YIPS_DEBUG) +# define YYDB plog(LLV_DEBUG2, LOCATION, NULL, \ + "begin <%d>%s\n", yy_start, yytext); +# define YYD { \ + plog(LLV_DEBUG2, LOCATION, NULL, "<%d>%s", \ + yy_start, loglevel >= LLV_DEBUG2 ? "\n" : ""); \ +} +#else +# define YYDB +# define YYD +#endif /* defined(YIPS_DEBUG) */ + +#define MAX_INCLUDE_DEPTH 10 + +static struct include_stack { + char *path; + FILE *fp; + YY_BUFFER_STATE state; + int lineno; +} incstack[MAX_INCLUDE_DEPTH]; +static int incstackp = 0; + +static int yy_first_time = 1; +%} + +/* common seciton */ +nl \n +ws [ \t]+ +digit [0-9] +letter [A-Za-z] +hexdigit [0-9A-Fa-f] +/*octet (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5]))) */ +special [()+\|\?\*] +comma \, +dot \. +slash \/ +bcl \{ +ecl \} +blcl \[ +elcl \] +percent \% +semi \; +comment \#.* +ccomment "/*" +bracketstring \<[^>]*\> +quotedstring \"[^"]*\" +addrstring [a-fA-F0-9:]([a-fA-F0-9:\.]*|[a-fA-F0-9:\.]*%[a-zA-Z0-9]*) +decstring {digit}+ +hexstring 0x{hexdigit}+ + +%s S_INI S_PTH S_INF S_LOG S_PAD S_LST S_RTRY +%s S_ALGST S_ALGCL +%s S_SAINF S_SAINFS +%s S_RMT S_RMTS S_RMTP +%s S_SA + +%% +%{ + if (yy_first_time) { + BEGIN S_INI; + yy_first_time = 0; + } +%} + + /* path */ +path { BEGIN S_PTH; YYDB; return(PATH); } +include { YYD; yylval.num = LC_PATHTYPE_INCLUDE; + return(PATHTYPE); } +pre_shared_key { YYD; yylval.num = LC_PATHTYPE_PSK; + return(PATHTYPE); } +certificate { YYD; yylval.num = LC_PATHTYPE_CERT; + return(PATHTYPE); } +backupsa { YYD; yylval.num = LC_PATHTYPE_BACKUPSA; + return(PATHTYPE); } +{semi} { BEGIN S_INI; YYDB; return(EOS); } + + /* include */ +include { YYDB; return(INCLUDE); } + + /* self information */ +identifier { BEGIN S_INF; YYDB; yywarn("it is obsoleted. use \"my_identifier\" in each remote directives."); return(IDENTIFIER); } +{semi} { BEGIN S_INI; return(EOS); } + + /* special */ +complex_bundle { YYDB; return(COMPLEX_BUNDLE); } + + /* logging */ +log { BEGIN S_LOG; YYDB; return(LOGGING); } +info { YYD; yywarn("it is obsoleted. use \"notify\""); yylval.num = 0; return(LOGLEV); } +notify { YYD; yylval.num = 0; return(LOGLEV); } +debug { YYD; yylval.num = 1; return(LOGLEV); } +debug2 { YYD; yylval.num = 2; return(LOGLEV); } +debug3 { YYD; yywarn("it is osboleted. use \"debug2\""); yylval.num = 2; return(LOGLEV); } +debug4 { YYD; yywarn("it is obsoleted. use \"debug2\""); yylval.num = 2; return(LOGLEV); } +{semi} { BEGIN S_INI; return(EOS); } + + /* padding */ +padding { BEGIN S_PAD; YYDB; return(PADDING); } +{bcl} { return(BOC); } +randomize { YYD; return(PAD_RANDOMIZE); } +randomize_length { YYD; return(PAD_RANDOMIZELEN); } +maximum_length { YYD; return(PAD_MAXLEN); } +strict_check { YYD; return(PAD_STRICT); } +exclusive_tail { YYD; return(PAD_EXCLTAIL); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* listen */ +listen { BEGIN S_LST; YYDB; return(LISTEN); } +{bcl} { return(BOC); } +isakmp { YYD; return(X_ISAKMP); } +admin { YYD; return(X_ADMIN); } +strict_address { YYD; return(STRICT_ADDRESS); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* timer */ +timer { BEGIN S_RTRY; YYDB; return(RETRY); } +{bcl} { return(BOC); } +counter { YYD; return(RETRY_COUNTER); } +interval { YYD; return(RETRY_INTERVAL); } +persend { YYD; return(RETRY_PERSEND); } +phase1 { YYD; return(RETRY_PHASE1); } +phase2 { YYD; return(RETRY_PHASE2); } +{ecl} { BEGIN S_INI; return(EOC); } + + /* sainfo */ +sainfo { BEGIN S_SAINF; YYDB; return(SAINFO); } +anonymous { YYD; return(ANONYMOUS); } +{blcl}any{elcl} { YYD; return(PORTANY); } +any { YYD; return(ANY); } + /* sainfo spec */ +{bcl} { BEGIN S_SAINFS; return(BOC); } +{semi} { BEGIN S_INI; return(EOS); } +{ecl} { BEGIN S_INI; return(EOC); } +pfs_group { YYD; return(PFS_GROUP); } +identifier { YYD; yywarn("it is obsoleted. use \"my_identifier\"."); return(IDENTIFIER); } +my_identifier { YYD; return(MY_IDENTIFIER); } +lifetime { YYD; return(LIFETIME); } +time { YYD; return(LIFETYPE_TIME); } +byte { YYD; return(LIFETYPE_BYTE); } +encryption_algorithm { YYD; yylval.num = algclass_ipsec_enc; return(ALGORITHM_CLASS); } +authentication_algorithm { YYD; yylval.num = algclass_ipsec_auth; return(ALGORITHM_CLASS); } +compression_algorithm { YYD; yylval.num = algclass_ipsec_comp; return(ALGORITHM_CLASS); } +{comma} { YYD; return(COMMA); } + + /* remote */ +remote { BEGIN S_RMT; YYDB; return(REMOTE); } +anonymous { YYD; return(ANONYMOUS); } + /* remote spec */ +{bcl} { BEGIN S_RMTS; return(BOC); } +{ecl} { BEGIN S_INI; return(EOC); } +exchange_mode { YYD; return(EXCHANGE_MODE); } +{comma} { YYD; /* XXX ignored, but to be handled. */ ; } +base { YYD; yylval.num = ISAKMP_ETYPE_BASE; return(EXCHANGETYPE); } +main { YYD; yylval.num = ISAKMP_ETYPE_IDENT; return(EXCHANGETYPE); } +aggressive { YYD; yylval.num = ISAKMP_ETYPE_AGG; return(EXCHANGETYPE); } +doi { YYD; return(DOI); } +ipsec_doi { YYD; yylval.num = IPSEC_DOI; return(DOITYPE); } +situation { YYD; return(SITUATION); } +identity_only { YYD; yylval.num = IPSECDOI_SIT_IDENTITY_ONLY; return(SITUATIONTYPE); } +secrecy { YYD; yylval.num = IPSECDOI_SIT_SECRECY; return(SITUATIONTYPE); } +integrity { YYD; yylval.num = IPSECDOI_SIT_INTEGRITY; return(SITUATIONTYPE); } +identifier { YYD; yywarn("it is obsoleted. use \"my_identifier\"."); return(IDENTIFIER); } +my_identifier { YYD; return(MY_IDENTIFIER); } +peers_identifier { YYD; return(PEERS_IDENTIFIER); } +verify_identifier { YYD; return(VERIFY_IDENTIFIER); } +certificate_type { YYD; return(CERTIFICATE_TYPE); } +x509 { YYD; yylval.num = ISAKMP_CERT_X509SIGN; return(CERT_X509); } +peers_certfile { YYD; return(PEERS_CERTFILE); } +dnssec { YYD; return(DNSSEC); } +verify_cert { YYD; return(VERIFY_CERT); } +send_cert { YYD; return(SEND_CERT); } +send_cr { YYD; return(SEND_CR); } +dh_group { YYD; return(DH_GROUP); } +nonce_size { YYD; return(NONCE_SIZE); } +generate_policy { YYD; return(GENERATE_POLICY); } +support_mip6 { YYD; return(SUPPORT_MIP6); } +initial_contact { YYD; return(INITIAL_CONTACT); } +proposal_check { YYD; return(PROPOSAL_CHECK); } +obey { YYD; yylval.num = PROP_CHECK_OBEY; return(PROPOSAL_CHECK_LEVEL); } +strict { YYD; yylval.num = PROP_CHECK_STRICT; return(PROPOSAL_CHECK_LEVEL); } +exact { YYD; yylval.num = PROP_CHECK_EXACT; return(PROPOSAL_CHECK_LEVEL); } +claim { YYD; yylval.num = PROP_CHECK_CLAIM; return(PROPOSAL_CHECK_LEVEL); } +keepalive { YYD; return(KEEPALIVE); } +passive { YYD; return(PASSIVE); } +lifetime { YYD; return(LIFETIME); } +time { YYD; return(LIFETYPE_TIME); } +byte { YYD; return(LIFETYPE_BYTE); } + /* remote proposal */ +proposal { BEGIN S_RMTP; YYDB; return(PROPOSAL); } +{bcl} { return(BOC); } +{ecl} { BEGIN S_RMTS; return(EOC); } +lifetime { YYD; return(LIFETIME); } +time { YYD; return(LIFETYPE_TIME); } +byte { YYD; return(LIFETYPE_BYTE); } +encryption_algorithm { YYD; yylval.num = algclass_isakmp_enc; return(ALGORITHM_CLASS); } +authentication_method { YYD; yylval.num = algclass_isakmp_ameth; return(ALGORITHM_CLASS); } +hash_algorithm { YYD; yylval.num = algclass_isakmp_hash; return(ALGORITHM_CLASS); } +dh_group { YYD; return(DH_GROUP); } +gssapi_id { YYD; return(GSSAPI_ID); } + + /* parameter */ +on { YYD; yylval.num = TRUE; return(SWITCH); } +off { YYD; yylval.num = FALSE; return(SWITCH); } + + /* prefix */ +{slash}{digit}{1,3} { + YYD; + yytext++; + yylval.num = atoi(yytext); + return(PREFIX); + } + + /* port number */ +{blcl}{decstring}{elcl} { + char *p = yytext; + YYD; + while (*++p != ']') ; + *p = NULL; + yytext++; + yylval.num = atoi(yytext); + return(PORT); + } + + /* upper protocol */ +esp { YYD; yylval.num = IPPROTO_ESP; return(UL_PROTO); } +ah { YYD; yylval.num = IPPROTO_AH; return(UL_PROTO); } +ipcomp { YYD; yylval.num = IPPROTO_IPCOMP; return(UL_PROTO); } +icmp { YYD; yylval.num = IPPROTO_ICMP; return(UL_PROTO); } +icmp6 { YYD; yylval.num = IPPROTO_ICMPV6; return(UL_PROTO); } +tcp { YYD; yylval.num = IPPROTO_TCP; return(UL_PROTO); } +udp { YYD; yylval.num = IPPROTO_UDP; return(UL_PROTO); } + + /* algorithm type */ +des_iv64 { YYD; yylval.num = algtype_des_iv64; return(ALGORITHMTYPE); } +des { YYD; yylval.num = algtype_des; return(ALGORITHMTYPE); } +3des { YYD; yylval.num = algtype_3des; return(ALGORITHMTYPE); } +rc5 { YYD; yylval.num = algtype_rc5; return(ALGORITHMTYPE); } +idea { YYD; yylval.num = algtype_idea; return(ALGORITHMTYPE); } +cast128 { YYD; yylval.num = algtype_cast128; return(ALGORITHMTYPE); } +blowfish { YYD; yylval.num = algtype_blowfish; return(ALGORITHMTYPE); } +3idea { YYD; yylval.num = algtype_3idea; return(ALGORITHMTYPE); } +des_iv32 { YYD; yylval.num = algtype_des_iv32; return(ALGORITHMTYPE); } +rc4 { YYD; yylval.num = algtype_rc4; return(ALGORITHMTYPE); } +null_enc { YYD; yylval.num = algtype_null_enc; return(ALGORITHMTYPE); } +rijndael { YYD; yylval.num = algtype_rijndael; return(ALGORITHMTYPE); } +aes { YYD; yylval.num = algtype_rijndael; return(ALGORITHMTYPE); } +twofish { YYD; yylval.num = algtype_twofish; return(ALGORITHMTYPE); } +non_auth { YYD; yylval.num = algtype_non_auth; return(ALGORITHMTYPE); } +hmac_md5 { YYD; yylval.num = algtype_hmac_md5; return(ALGORITHMTYPE); } +hmac_sha1 { YYD; yylval.num = algtype_hmac_sha1; return(ALGORITHMTYPE); } +hmac_sha2_256 { YYD; yylval.num = algtype_hmac_sha2_256; return(ALGORITHMTYPE); } +hmac_sha2_384 { YYD; yylval.num = algtype_hmac_sha2_384; return(ALGORITHMTYPE); } +hmac_sha2_512 { YYD; yylval.num = algtype_hmac_sha2_512; return(ALGORITHMTYPE); } +des_mac { YYD; yylval.num = algtype_des_mac; return(ALGORITHMTYPE); } +kpdk { YYD; yylval.num = algtype_kpdk; return(ALGORITHMTYPE); } +md5 { YYD; yylval.num = algtype_md5; return(ALGORITHMTYPE); } +sha1 { YYD; yylval.num = algtype_sha1; return(ALGORITHMTYPE); } +tiger { YYD; yylval.num = algtype_tiger; return(ALGORITHMTYPE); } +sha2_256 { YYD; yylval.num = algtype_sha2_256; return(ALGORITHMTYPE); } +sha2_384 { YYD; yylval.num = algtype_sha2_384; return(ALGORITHMTYPE); } +sha2_512 { YYD; yylval.num = algtype_sha2_512; return(ALGORITHMTYPE); } +oui { YYD; yylval.num = algtype_oui; return(ALGORITHMTYPE); } +deflate { YYD; yylval.num = algtype_deflate; return(ALGORITHMTYPE); } +lzs { YYD; yylval.num = algtype_lzs; return(ALGORITHMTYPE); } +modp768 { YYD; yylval.num = algtype_modp768; return(ALGORITHMTYPE); } +modp1024 { YYD; yylval.num = algtype_modp1024; return(ALGORITHMTYPE); } +modp1536 { YYD; yylval.num = algtype_modp1536; return(ALGORITHMTYPE); } +ec2n155 { YYD; yylval.num = algtype_ec2n155; return(ALGORITHMTYPE); } +ec2n185 { YYD; yylval.num = algtype_ec2n185; return(ALGORITHMTYPE); } +modp2048 { YYD; yylval.num = algtype_modp2048; return(ALGORITHMTYPE); } +modp3072 { YYD; yylval.num = algtype_modp3072; return(ALGORITHMTYPE); } +modp4096 { YYD; yylval.num = algtype_modp4096; return(ALGORITHMTYPE); } +modp6144 { YYD; yylval.num = algtype_modp6144; return(ALGORITHMTYPE); } +modp8192 { YYD; yylval.num = algtype_modp8192; return(ALGORITHMTYPE); } +pre_shared_key { YYD; yylval.num = algtype_psk; return(ALGORITHMTYPE); } +rsasig { YYD; yylval.num = algtype_rsasig; return(ALGORITHMTYPE); } +dsssig { YYD; yylval.num = algtype_dsssig; return(ALGORITHMTYPE); } +rsaenc { YYD; yylval.num = algtype_rsaenc; return(ALGORITHMTYPE); } +rsarev { YYD; yylval.num = algtype_rsarev; return(ALGORITHMTYPE); } +gssapi_krb { YYD; yylval.num = algtype_gssapikrb; return(ALGORITHMTYPE); } + + /* identifier type */ +vendor_id { YYD; yywarn("it is obsoleted."); return(VENDORID); } +user_fqdn { YYD; yylval.num = IDTYPE_USERFQDN; return(IDENTIFIERTYPE); } +fqdn { YYD; yylval.num = IDTYPE_FQDN; return(IDENTIFIERTYPE); } +keyid { YYD; yylval.num = IDTYPE_KEYID; return(IDENTIFIERTYPE); } +address { YYD; yylval.num = IDTYPE_ADDRESS; return(IDENTIFIERTYPE); } +asn1dn { YYD; yylval.num = IDTYPE_ASN1DN; return(IDENTIFIERTYPE); } +certname { YYD; yywarn("certname will be obsoleted in near future."); yylval.num = IDTYPE_ASN1DN; return(IDENTIFIERTYPE); } + + /* units */ +B|byte|bytes { YYD; return(UNITTYPE_BYTE); } +KB { YYD; return(UNITTYPE_KBYTES); } +MB { YYD; return(UNITTYPE_MBYTES); } +TB { YYD; return(UNITTYPE_TBYTES); } +sec|secs|second|seconds { YYD; return(UNITTYPE_SEC); } +min|mins|minute|minutes { YYD; return(UNITTYPE_MIN); } +hour|hours { YYD; return(UNITTYPE_HOUR); } + + /* boolean */ +yes { YYD; yylval.num = TRUE; return(BOOLEAN); } +no { YYD; yylval.num = FALSE; return(BOOLEAN); } + +{decstring} { + char *bp; + + YYD; + yylval.num = strtol(yytext, &bp, 10); + return(NUMBER); + } + +{hexstring} { + char *p; + + YYD; + yylval.val = vmalloc(yyleng + (yyleng & 1) + 1); + if (yylval.val == NULL) { + yyerror("vmalloc failed"); + return -1; + } + + p = yylval.val->v; + *p++ = '0'; + *p++ = 'x'; + + /* fixed string if length is odd. */ + if (yyleng & 1) + *p++ = '0'; + memcpy(p, &yytext[2], yyleng - 1); + + return(HEXSTRING); + } + +{quotedstring} { + u_char *p = yytext; + + YYD; + while (*++p != '"') ; + *p = '\0'; + + yylval.val = vmalloc(yyleng - 1); + if (yylval.val == NULL) { + yyerror("vmalloc failed"); + return -1; + } + memcpy(yylval.val->v, &yytext[1], yylval.val->l); + + return(QUOTEDSTRING); + } + +{addrstring} { + YYD; + + yylval.val = vmalloc(yyleng + 1); + if (yylval.val == NULL) { + yyerror("vmalloc failed"); + return -1; + } + memcpy(yylval.val->v, yytext, yylval.val->l); + + return(ADDRSTRING); + } + +<> { + if ( --incstackp < 0 ) { + yyterminate(); + } else { + yy_delete_buffer(YY_CURRENT_BUFFER); + yy_switch_to_buffer(incstack[incstackp].state); + } + } + + /* ... */ +{ws} { ; } +{nl} { incstack[incstackp].lineno++; } +{comment} { YYD; } +{semi} { return(EOS); } +. { yymore(); } + +%% + +void +yyerror(char *s, ...) +{ + char fmt[512]; + + va_list ap; +#ifdef HAVE_STDARG_H + va_start(ap, s); +#else + va_start(ap); +#endif + snprintf(fmt, sizeof(fmt), "%s:%d: \"%s\" %s\n", + incstack[incstackp].path, incstack[incstackp].lineno, + yytext, s); + plogv(LLV_ERROR, LOCATION, NULL, fmt, ap); + va_end(ap); + + yyerrorcount++; +} + +void +yywarn(char *s, ...) +{ + char fmt[512]; + + va_list ap; +#ifdef HAVE_STDARG_H + va_start(ap, s); +#else + va_start(ap); +#endif + snprintf(fmt, sizeof(fmt), "%s:%d: \"%s\" %s\n", + incstack[incstackp].path, incstack[incstackp].lineno, + yytext, s); + plogv(LLV_WARNING, LOCATION, NULL, fmt, ap); + va_end(ap); +} + +int +yycf_switch_buffer(path) + char *path; +{ + /* got the include file name */ + if (incstackp >= MAX_INCLUDE_DEPTH) { + plog(LLV_ERROR, LOCATION, NULL, + "Includes nested too deeply"); + return -1; + } + + incstack[incstackp++].state = YY_CURRENT_BUFFER; + + if (yycf_set_buffer(path) != 0) + return -1; + + yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + + BEGIN(S_INI); + + return 0; +} + +int +yycf_set_buffer(path) + char *path; +{ + yyin = fopen(path, "r"); + if (yyin == NULL) { + fprintf(stderr, "failed to open file %s (%s)\n", + path, strerror(errno)); + plog(LLV_ERROR, LOCATION, NULL, + "failed to open file %s (%s)\n", + path, strerror(errno)); + return -1; + } + + /* initialize */ + incstack[incstackp].fp = yyin; + incstack[incstackp].path = strdup(path); + incstack[incstackp].lineno = 1; + + return 0; +} + +void +yycf_init_buffer() +{ + int i; + + for (i = 0; i < MAX_INCLUDE_DEPTH; i++) + memset(&incstack[i], 0, sizeof(incstack[i])); + incstackp = 0; +} + +void +yycf_clean_buffer() +{ + int i; + + for (i = 0; i < MAX_INCLUDE_DEPTH; i++) { + if (incstack[i].path != NULL) { + fclose(incstack[i].fp); + racoon_free(incstack[i].path); + incstack[i].path = NULL; + } + } +} + diff --git a/racoon.tproj/crypto_openssl.c b/racoon.tproj/crypto_openssl.c new file mode 100644 index 0000000..c042c33 --- /dev/null +++ b/racoon.tproj/crypto_openssl.c @@ -0,0 +1,2295 @@ +/* $KAME: crypto_openssl.c,v 1.69 2001/09/11 13:25:00 sakane 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. 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. + */ + +#include +#include + +#include +#include +#include +#include + +/* get openssl/ssleay version number */ +#ifdef HAVE_OPENSSL_OPENSSLV_H +# include +#else +# error no opensslv.h found. +#endif + +#ifndef OPENSSL_VERSION_NUMBER +#error OPENSSL_VERSION_NUMBER is not defined. OpenSSL0.9.4 or later required. +#endif + +#ifdef HAVE_OPENSSL_PEM_H +#include +#endif +#ifdef HAVE_OPENSSL_EVP_H +#include +#endif +#ifdef HAVE_OPENSSL_X509_H +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_OPENSSL_IDEA_H +#include +#endif +#include +#ifdef HAVE_OPENSSL_RC5_H +#include +#endif +#include +#include +#ifdef HAVE_OPENSSL_RIJNDAEL_H +#include +#else +#include "rijndael-api-fst.h" +#endif +#ifdef HAVE_OPENSSL_SHA2_H +#include +#else +#include "sha2.h" +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "crypto_openssl.h" +#include "debug.h" +#include "gcmalloc.h" + +/* + * I hate to cast every parameter to des_xx into void *, but it is + * necessary for SSLeay/OpenSSL portability. It sucks. + */ + +#ifdef HAVE_SIGNING_C +static int cb_check_cert __P((int, X509_STORE_CTX *)); +static void eay_setgentype __P((char *, int *)); +static X509 *mem2x509 __P((vchar_t *)); +#endif + +static caddr_t eay_hmac_init __P((vchar_t *, const EVP_MD *)); + +#ifdef HAVE_SIGNING_C +/* X509 Certificate */ +/* + * convert the string of the subject name into DER + * e.g. str = "C=JP, ST=Kanagawa"; + */ +vchar_t * +eay_str2asn1dn(str, len) + char *str; + int len; +{ + X509_NAME *name; + char *buf; + char *field, *value; + int i, j; + vchar_t *ret; + caddr_t p; + + buf = racoon_malloc(len + 1); + if (!buf) { + printf("failed to allocate buffer\n"); + return NULL; + } + memcpy(buf, str, len); + + name = X509_NAME_new(); + + field = &buf[0]; + value = NULL; + for (i = 0; i < len; i++) { + if (!value && buf[i] == '=') { + buf[i] = '\0'; + value = &buf[i + 1]; + continue; + } else if (buf[i] == ',' || buf[i] == '/') { + buf[i] = '\0'; +#if 0 + printf("[%s][%s]\n", field, value); +#endif + if (!X509_NAME_add_entry_by_txt(name, field, + MBSTRING_ASC, value, -1, -1, 0)) + goto err; + for (j = i + 1; j < len; j++) { + if (buf[j] != ' ') + break; + } + field = &buf[j]; + value = NULL; + continue; + } + } + buf[len] = '\0'; +#if 0 + printf("[%s][%s]\n", field, value); +#endif + if (!X509_NAME_add_entry_by_txt(name, field, + MBSTRING_ASC, value, -1, -1, 0)) + goto err; + + i = i2d_X509_NAME(name, NULL); + if (!i) + goto err; + ret = vmalloc(i); + if (!ret) + goto err; + p = ret->v; + i = i2d_X509_NAME(name, (unsigned char **)&p); + if (!i) + goto err; + + return ret; + + err: + if (buf) + racoon_free(buf); + if (name) + X509_NAME_free(name); + return NULL; +} + +/* + * compare two subjectNames. + * OUT: 0: equal + * positive: + * -1: other error. + */ +int +eay_cmp_asn1dn(n1, n2) + vchar_t *n1, *n2; +{ + X509_NAME *a = NULL, *b = NULL; + caddr_t p; + int i = -1; + + p = n1->v; + if (!d2i_X509_NAME(&a, (unsigned char **)&p, n1->l)) + goto end; + p = n2->v; + if (!d2i_X509_NAME(&b, (unsigned char **)&p, n2->l)) + goto end; + + i = X509_NAME_cmp(a, b); + + end: + if (a) + X509_NAME_free(a); + if (b) + X509_NAME_free(b); + return i; +} + +/* + * this functions is derived from apps/verify.c in OpenSSL0.9.5 + */ +int +eay_check_x509cert(cert, CApath) + vchar_t *cert; + char *CApath; +{ + X509_STORE *cert_ctx = NULL; + X509_LOOKUP *lookup = NULL; + X509 *x509 = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + X509_STORE_CTX *csc; +#else + X509_STORE_CTX csc; +#endif + int error = -1; + + /* XXX define only functions required. */ +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + OpenSSL_add_all_algorithms(); +#else + SSLeay_add_all_algorithms(); +#endif + + cert_ctx = X509_STORE_new(); + if (cert_ctx == NULL) + goto end; + X509_STORE_set_verify_cb_func(cert_ctx, cb_check_cert); + + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file()); + if (lookup == NULL) + goto end; + X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); /* XXX */ + + lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir()); + if (lookup == NULL) + goto end; + error = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM); + if(!error) { + error = -1; + goto end; + } + error = -1; /* initialized */ + + /* read the certificate to be verified */ + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + csc = X509_STORE_CTX_new(); + if (csc == NULL) + goto end; + X509_STORE_CTX_init(csc, cert_ctx, x509, NULL); + error = X509_verify_cert(csc); + X509_STORE_CTX_cleanup(csc); +#else + X509_STORE_CTX_init(&csc, cert_ctx, x509, NULL); + error = X509_verify_cert(&csc); + X509_STORE_CTX_cleanup(&csc); +#endif + + /* + * if x509_verify_cert() is successful then the value of error is + * set non-zero. + */ + error = error ? 0 : -1; + +end: + if (error) + printf("%s\n", eay_strerror()); + if (cert_ctx != NULL) + X509_STORE_free(cert_ctx); + if (x509 != NULL) + X509_free(x509); + + return(error); +} + +/* + * callback function for verifing certificate. + * this function is derived from cb() in openssl/apps/s_server.c + */ +static int +cb_check_cert(ok, ctx) + int ok; + X509_STORE_CTX *ctx; +{ + char buf[256]; + int log_tag; + + if (!ok) { + X509_NAME_oneline( + X509_get_subject_name(ctx->current_cert), + buf, + 256); + /* + * since we are just checking the certificates, it is + * ok if they are self signed. But we should still warn + * the user. + */ + switch (ctx->error) { + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: +#if OPENSSL_VERSION_NUMBER >= 0x00905100L + case X509_V_ERR_INVALID_CA: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_PURPOSE: +#endif + ok = 1; + log_tag = LLV_WARNING; + break; + default: + log_tag = LLV_ERROR; + } +#ifndef EAYDEBUG + plog(log_tag, LOCATION, NULL, + "%s(%d) at depth:%d SubjectName:%s\n", + X509_verify_cert_error_string(ctx->error), + ctx->error, + ctx->error_depth, + buf); +#else + printf("%d: %s(%d) at depth:%d SubjectName:%s\n", + log_tag, + X509_verify_cert_error_string(ctx->error), + ctx->error, + ctx->error_depth, + buf); +#endif + } + ERR_clear_error(); + + return ok; +} + +/* + * get a subjectAltName from X509 certificate. + */ +vchar_t * +eay_get_x509asn1subjectname(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + u_char *bp; + vchar_t *name = NULL; + int len; + int error = -1; + + bp = cert->v; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + /* get the length of the name */ + len = i2d_X509_NAME(x509->cert_info->subject, NULL); + name = vmalloc(len); + if (!name) + goto end; + /* get the name */ + bp = name->v; + len = i2d_X509_NAME(x509->cert_info->subject, &bp); + + error = 0; + + end: + if (error) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#else + printf("%s\n", eay_strerror()); +#endif + if (name) { + vfree(name); + name = NULL; + } + } + if (x509) + X509_free(x509); + + return name; +} + +/* + * get the subjectAltName from X509 certificate. + * the name is terminated by '\0'. + */ +#include +int +eay_get_x509subjectaltname(cert, altname, type, pos) + vchar_t *cert; + char **altname; + int *type; + int pos; +{ + X509 *x509 = NULL; + X509_EXTENSION *ext; + X509V3_EXT_METHOD *method = NULL; + STACK_OF(GENERAL_NAME) *name; + CONF_VALUE *cval = NULL; + STACK_OF(CONF_VALUE) *nval = NULL; + u_char *bp; + int i, len; + int error = -1; + + *altname = NULL; + *type = GENT_OTHERNAME; + + bp = cert->v; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + i = X509_get_ext_by_NID(x509, NID_subject_alt_name, -1); + if (i < 0) + goto end; + ext = X509_get_ext(x509, i); + method = X509V3_EXT_get(ext); + if(!method) + goto end; + + bp = ext->value->data; + name = method->d2i(NULL, &bp, ext->value->length); + if(!name) + goto end; + + nval = method->i2v(method, name, NULL); + method->ext_free(name); + name = NULL; + if(!nval) + goto end; + + for (i = 0; i < sk_CONF_VALUE_num(nval); i++) { + /* skip the name */ + if (i + 1 != pos) + continue; + cval = sk_CONF_VALUE_value(nval, i); + len = strlen(cval->value) + 1; /* '\0' included */ + *altname = racoon_malloc(len); + if (!*altname) { + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); + goto end; + } + strcpy(*altname, cval->value); + + /* set type of the name */ + eay_setgentype(cval->name, type); + } + + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); + + error = 0; + + end: + if (error) { + if (*altname) { + racoon_free(*altname); + *altname = NULL; + } +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#else + printf("%s\n", eay_strerror()); +#endif + } + if (x509) + X509_free(x509); + + return error; +} + +static void +eay_setgentype(name, type) + char *name; + int *type; +{ + /* XXX It's needed effective code */ + if(!memcmp(name, "email", strlen("email"))) { + *type = GENT_EMAIL; + } else if(!memcmp(name, "URI", strlen("URI"))) { + *type = GENT_URI; + } else if(!memcmp(name, "DNS", strlen("DNS"))) { + *type = GENT_DNS; + } else if(!memcmp(name, "RID", strlen("RID"))) { + *type = GENT_RID; + } else if(!memcmp(name, "IP", strlen("IP"))) { + *type = GENT_IPADD; + } else { + *type = GENT_OTHERNAME; + } +} + +/* + * decode a X509 certificate and make a readable text terminated '\n'. + * return the buffer allocated, so must free it later. + */ +char * +eay_get_x509text(cert) + vchar_t *cert; +{ + X509 *x509 = NULL; + BIO *bio = NULL; + char *text = NULL; + u_char *bp = NULL; + int len = 0; + int error = -1; + + x509 = mem2x509(cert); + if (x509 == NULL) + goto end; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + goto end; + + error = X509_print(bio, x509); + if (error != 1) { + error = -1; + goto end; + } + + len = BIO_get_mem_data(bio, &bp); + text = racoon_malloc(len + 1); + if (text == NULL) + goto end; + memcpy(text, bp, len); + text[len] = '\0'; + + error = 0; + + end: + if (error) { + if (text) { + racoon_free(text); + text = NULL; + } +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#else + printf("%s\n", eay_strerror()); +#endif + } + if (bio) + BIO_free(bio); + if (x509) + X509_free(x509); + + return text; +} + +/* get X509 structure from buffer. */ +static X509 * +mem2x509(cert) + vchar_t *cert; +{ + X509 *x509; + +#ifndef EAYDEBUG + { + u_char *bp; + + bp = cert->v; + + x509 = d2i_X509(NULL, &bp, cert->l); + } +#else + { + BIO *bio; + int len; + + bio = BIO_new(BIO_s_mem()); + if (bio == NULL) + return NULL; + len = BIO_write(bio, cert->v, cert->l); + if (len == -1) + return NULL; + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + } +#endif + return x509; +} + +/* + * get a X509 certificate from local file. + * a certificate must be PEM format. + * Input: + * path to a certificate. + * Output: + * NULL if error occured + * other is the cert. + */ +vchar_t * +eay_get_x509cert(path) + char *path; +{ + FILE *fp; + X509 *x509; + vchar_t *cert; + u_char *bp; + int len; + int error; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + x509 = PEM_read_X509(fp, NULL, NULL, NULL); +#else + x509 = PEM_read_X509(fp, NULL, NULL); +#endif + fclose (fp); + + if (x509 == NULL) + return NULL; + + len = i2d_X509(x509, NULL); + cert = vmalloc(len); + if (cert == NULL) { + X509_free(x509); + return NULL; + } + bp = cert->v; + error = i2d_X509(x509, &bp); + X509_free(x509); + + if (error == 0) + return NULL; + + return cert; +} + +/* + * sign a souce by X509 signature. + * XXX: to be get hash type from my cert ? + * to be handled EVP_dss(). + */ +vchar_t * +eay_get_x509sign(source, privkey, cert) + vchar_t *source; + vchar_t *privkey; + vchar_t *cert; +{ + vchar_t *sig = NULL; + + sig = eay_rsa_sign(source, privkey); + + return sig; +} + +/* + * check a X509 signature + * XXX: to be get hash type from my cert ? + * to be handled EVP_dss(). + * OUT: return -1 when error. + * 0 + */ +int +eay_check_x509sign(source, sig, cert) + vchar_t *source; + vchar_t *sig; + vchar_t *cert; +{ + X509 *x509; + u_char *bp; + vchar_t pubkey; + + bp = cert->v; + + x509 = d2i_X509(NULL, &bp, cert->l); + if (x509 == NULL) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#endif + return -1; + } + + pubkey.v = x509->cert_info->key->public_key->data; + pubkey.l = x509->cert_info->key->public_key->length; + + return eay_rsa_verify(source, sig, &pubkey); +} + +/* + * check a signature by signed with PKCS7 certificate. + * XXX: to be get hash type from my cert ? + * to be handled EVP_dss(). + * OUT: return -1 when error. + * 0 + */ +int +eay_check_pkcs7sign(source, sig, cert) + vchar_t *source; + vchar_t *sig; + vchar_t *cert; +{ + X509 *x509; + EVP_MD_CTX md_ctx; + EVP_PKEY *evp; + int error; + BIO *bio = BIO_new(BIO_s_mem()); + char *bp; + + if (bio == NULL) + return -1; + error = BIO_write(bio, cert->v, cert->l); + if (error != cert->l) + return -1; + + bp = cert->v; + x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); + BIO_free(bio); + if (x509 == NULL) + return -1; + + evp = X509_get_pubkey(x509); + X509_free(x509); + if (evp == NULL) + return -1; + + /* Verify the signature */ + /* XXX: to be handled EVP_dss() */ + EVP_VerifyInit(&md_ctx, EVP_sha1()); + EVP_VerifyUpdate(&md_ctx, source->v, source->l); + error = EVP_VerifyFinal(&md_ctx, sig->v, sig->l, evp); + + EVP_PKEY_free(evp); + + if (error != 1) + return -1; + + return 0; +} + +/* + * get PKCS#1 Private Key of PEM format from local file. + */ +vchar_t * +eay_get_pkcs1privkey(path) + char *path; +{ + FILE *fp; + EVP_PKEY *evp = NULL; + vchar_t *pkey = NULL; + u_char *bp; + int pkeylen; + int error = -1; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + evp = PEM_read_PrivateKey(fp, NULL, NULL, NULL); +#else + evp = PEM_read_PrivateKey(fp, NULL, NULL); +#endif + fclose (fp); + + if (evp == NULL) + return NULL; + + pkeylen = i2d_PrivateKey(evp, NULL); + if (pkeylen == 0) + goto end; + pkey = vmalloc(pkeylen); + if (pkey == NULL) + goto end; + bp = pkey->v; + pkeylen = i2d_PrivateKey(evp, &bp); + if (pkeylen == 0) + goto end; + + error = 0; + +end: + if (evp != NULL) + EVP_PKEY_free(evp); + if (error != 0 && pkey != NULL) { + vfree(pkey); + pkey = NULL; + } + + return pkey; +} + +/* + * get PKCS#1 Public Key of PEM format from local file. + */ +vchar_t * +eay_get_pkcs1pubkey(path) + char *path; +{ + FILE *fp; + EVP_PKEY *evp = NULL; + vchar_t *pkey = NULL; + X509 *x509 = NULL; + u_char *bp; + int pkeylen; + int error = -1; + + /* Read private key */ + fp = fopen(path, "r"); + if (fp == NULL) + return NULL; + +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + x509 = PEM_read_X509(fp, NULL, NULL, NULL); +#else + x509 = PEM_read_X509(fp, NULL, NULL); +#endif + fclose (fp); + + if (x509 == NULL) + return NULL; + + /* Get public key - eay */ + evp = X509_get_pubkey(x509); + if (evp == NULL) + return NULL; + + pkeylen = i2d_PublicKey(evp, NULL); + if (pkeylen == 0) + goto end; + pkey = vmalloc(pkeylen); + if (pkey == NULL) + goto end; + bp = pkey->v; + pkeylen = i2d_PublicKey(evp, &bp); + if (pkeylen == 0) + goto end; + + error = 0; +end: + if (evp != NULL) + EVP_PKEY_free(evp); + if (error != 0 && pkey != NULL) { + vfree(pkey); + pkey = NULL; + } + + return pkey; +} +#endif + +vchar_t * +eay_rsa_sign(src, privkey) + vchar_t *src, *privkey; +{ + EVP_PKEY *evp; + u_char *bp = privkey->v; + vchar_t *sig = NULL; + int len; + int pad = RSA_PKCS1_PADDING; + + /* XXX to be handled EVP_PKEY_DSA */ + evp = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &bp, privkey->l); + if (evp == NULL) + return NULL; + + /* XXX: to be handled EVP_dss() */ + /* XXX: Where can I get such parameters ? From my cert ? */ + + len = RSA_size(evp->pkey.rsa); + + sig = vmalloc(len); + if (sig == NULL) + return NULL; + + len = RSA_private_encrypt(src->l, src->v, sig->v, evp->pkey.rsa, pad); + EVP_PKEY_free(evp); + if (len == 0 || len != sig->l) { + vfree(sig); + sig = NULL; + } + + return sig; +} + +int +eay_rsa_verify(src, sig, pubkey) + vchar_t *src, *sig, *pubkey; +{ + EVP_PKEY *evp; + u_char *bp = pubkey->v; + vchar_t *xbuf = NULL; + int pad = RSA_PKCS1_PADDING; + int len = 0; + int error; + + evp = d2i_PUBKEY(NULL, &bp, pubkey->l); + if (evp == NULL) +#ifndef EAYDEBUG + return NULL; +#endif + + len = RSA_size(evp->pkey.rsa); + + xbuf = vmalloc(len); + if (xbuf == NULL) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#endif + EVP_PKEY_free(evp); + return -1; + } + + len = RSA_public_decrypt(sig->l, sig->v, xbuf->v, evp->pkey.rsa, pad); +#ifndef EAYDEBUG + if (len == 0 || len != src->l) + plog(LLV_ERROR, LOCATION, NULL, "%s\n", eay_strerror()); +#endif + EVP_PKEY_free(evp); + if (len == 0 || len != src->l) { + vfree(xbuf); + return -1; + } + + error = memcmp(src->v, xbuf->v, src->l); + vfree(xbuf); + if (error != 0) + return -1; + + return 0; +} + +/* + * get error string + * MUST load ERR_load_crypto_strings() first. + */ +char * +eay_strerror() +{ + static char ebuf[512]; + int len = 0, n; + unsigned long l; + char buf[200]; +#if OPENSSL_VERSION_NUMBER >= 0x00904100L + const char *file, *data; +#else + char *file, *data; +#endif + int line, flags; + unsigned long es; + + es = CRYPTO_thread_id(); + + while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0){ + n = snprintf(ebuf + len, sizeof(ebuf) - len, + "%lu:%s:%s:%d:%s ", + es, ERR_error_string(l, buf), file, line, + (flags & ERR_TXT_STRING) ? data : ""); + if (n < 0 || n >= sizeof(ebuf) - len) + break; + len += n; + if (sizeof(ebuf) < len) + break; + } + + return ebuf; +} + +void +eay_init_error() +{ + ERR_load_crypto_strings(); +} + +/* + * DES-CBC + */ +vchar_t * +eay_des_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks; + + if (des_key_sched((void *)key->v, ks) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks, (void *)iv->v, DES_ENCRYPT); + + return res; +} + +vchar_t * +eay_des_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks; + + if (des_key_sched((void *)key->v, ks) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks, (void *)iv->v, DES_DECRYPT); + + return res; +} + +int +eay_des_weakkey(key) + vchar_t *key; +{ + return des_is_weak_key((void *)key->v); +} + +int +eay_des_keylen(len) + int len; +{ + if (len != 0 && len != 64) + return -1; + return 64; +} + +#ifdef HAVE_OPENSSL_IDEA_H +/* + * IDEA-CBC + */ +vchar_t * +eay_idea_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + IDEA_KEY_SCHEDULE ks; + + idea_set_encrypt_key(key->v, &ks); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + idea_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, IDEA_ENCRYPT); + + return res; +} + +vchar_t * +eay_idea_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + IDEA_KEY_SCHEDULE ks, dks; + + idea_set_encrypt_key(key->v, &ks); + idea_set_decrypt_key(&ks, &dks); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + idea_cbc_encrypt(data->v, res->v, data->l, + &dks, iv->v, IDEA_DECRYPT); + + return res; +} + +int +eay_idea_weakkey(key) + vchar_t *key; +{ + return 0; /* XXX */ +} + +int +eay_idea_keylen(len) + int len; +{ + if (len != 0 && len != 128) + return -1; + return 128; +} +#endif + +/* + * BLOWFISH-CBC + */ +vchar_t * +eay_bf_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + BF_KEY ks; + + BF_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + BF_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, BF_ENCRYPT); + + return res; +} + +vchar_t * +eay_bf_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + BF_KEY ks; + + BF_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + BF_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, BF_DECRYPT); + + return res; +} + +int +eay_bf_weakkey(key) + vchar_t *key; +{ + return 0; /* XXX to be done. refer to RFC 2451 */ +} + +int +eay_bf_keylen(len) + int len; +{ + if (len == 0) + return 448; + if (len < 40 || len > 448) + return -1; + return len + 7 / 8; +} + +#ifdef HAVE_OPENSSL_RC5_H +/* + * RC5-CBC + */ +vchar_t * +eay_rc5_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + RC5_32_KEY ks; + + /* in RFC 2451, there is information about the number of round. */ + RC5_32_set_key(&ks, key->l, key->v, 16); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + RC5_32_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, RC5_ENCRYPT); + + return res; +} + +vchar_t * +eay_rc5_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + RC5_32_KEY ks; + + /* in RFC 2451, there is information about the number of round. */ + RC5_32_set_key(&ks, key->l, key->v, 16); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + RC5_32_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, RC5_DECRYPT); + + return res; +} + +int +eay_rc5_weakkey(key) + vchar_t *key; +{ + return 0; /* No known weak keys when used with 16 rounds. */ + +} + +int +eay_rc5_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len < 40 || len > 2040) + return -1; + return len + 7 / 8; +} +#endif + +/* + * 3DES-CBC + */ +vchar_t * +eay_3des_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks1, ks2, ks3; + + if (key->l < 24) + return NULL; + + if (des_key_sched((void *)key->v, ks1) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 8), ks2) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 16), ks3) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_ede3_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks1, ks2, ks3, (void *)iv->v, DES_ENCRYPT); + + return res; +} + +vchar_t * +eay_3des_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + des_key_schedule ks1, ks2, ks3; + + if (key->l < 24) + return NULL; + + if (des_key_sched((void *)key->v, ks1) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 8), ks2) != 0) + return NULL; + if (des_key_sched((void *)(key->v + 16), ks3) != 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + des_ede3_cbc_encrypt((void *)data->v, (void *)res->v, data->l, + ks1, ks2, ks3, (void *)iv->v, DES_DECRYPT); + + return res; +} + +int +eay_3des_weakkey(key) + vchar_t *key; +{ + if (key->l < 24) + return NULL; + + return (des_is_weak_key((void *)key->v) + || des_is_weak_key((void *)(key->v + 8)) + || des_is_weak_key((void *)(key->v + 16))); +} + +int +eay_3des_keylen(len) + int len; +{ + if (len != 0 && len != 192) + return -1; + return 192; +} + +/* + * CAST-CBC + */ +vchar_t * +eay_cast_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + CAST_KEY ks; + + CAST_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + CAST_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, DES_ENCRYPT); + + return res; +} + +vchar_t * +eay_cast_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + CAST_KEY ks; + + CAST_set_key(&ks, key->l, key->v); + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + CAST_cbc_encrypt(data->v, res->v, data->l, + &ks, iv->v, DES_DECRYPT); + + return res; +} + +int +eay_cast_weakkey(key) + vchar_t *key; +{ + return 0; /* No known weak keys. */ +} + +int +eay_cast_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len < 40 || len > 128) + return -1; + return len + 7 / 8; +} + +/* + * AES(RIJNDAEL)-CBC + */ +vchar_t * +eay_aes_encrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + keyInstance k; + cipherInstance c; + + memset(&k, 0, sizeof(k)); + if (rijndael_makeKey(&k, DIR_ENCRYPT, key->l << 3, key->v) < 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* encryption data */ + memset(&c, 0, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0) + return NULL; + if (rijndael_blockEncrypt(&c, &k, data->v, data->l << 3, res->v) < 0) + return NULL; + + return res; +} + +vchar_t * +eay_aes_decrypt(data, key, iv) + vchar_t *data, *key, *iv; +{ + vchar_t *res; + keyInstance k; + cipherInstance c; + + memset(&k, 0, sizeof(k)); + if (rijndael_makeKey(&k, DIR_DECRYPT, key->l << 3, key->v) < 0) + return NULL; + + /* allocate buffer for result */ + if ((res = vmalloc(data->l)) == NULL) + return NULL; + + /* decryption data */ + memset(&c, 0, sizeof(c)); + if (rijndael_cipherInit(&c, MODE_CBC, iv->v) < 0) + return NULL; + if (rijndael_blockDecrypt(&c, &k, data->v, data->l << 3, res->v) < 0) + return NULL; + + return res; +} + +int +eay_aes_weakkey(key) + vchar_t *key; +{ + return 0; +} + +int +eay_aes_keylen(len) + int len; +{ + if (len == 0) + return 128; + if (len != 128 && len != 192 && len != 256) + return -1; + return len; +} + +/* for ipsec part */ +int +eay_null_hashlen() +{ + return 0; +} + +int +eay_kpdk_hashlen() +{ + return 0; +} + +int +eay_twofish_keylen(len) + int len; +{ + if (len < 0 || len > 256) + return -1; + return len; +} + +/* + * HMAC functions + */ +static caddr_t +eay_hmac_init(key, md) + vchar_t *key; + const EVP_MD *md; +{ + HMAC_CTX *c = racoon_malloc(sizeof(*c)); + + HMAC_Init(c, key->v, key->l, md); + + return (caddr_t)c; +} + +/* + * HMAC SHA2-512 + */ +vchar_t * +eay_hmacsha2_512_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_512_init(key); + eay_hmacsha2_512_update(ctx, data); + res = eay_hmacsha2_512_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_512_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha2_512()); +} + +void +eay_hmacsha2_512_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha2_512_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA512_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_512 length mismatch %d.\n", res->l); +#else + printf("hmac sha2_512 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC SHA2-384 + */ +vchar_t * +eay_hmacsha2_384_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_384_init(key); + eay_hmacsha2_384_update(ctx, data); + res = eay_hmacsha2_384_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_384_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha2_384()); +} + +void +eay_hmacsha2_384_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha2_384_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA384_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_384 length mismatch %d.\n", res->l); +#else + printf("hmac sha2_384 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC SHA2-256 + */ +vchar_t * +eay_hmacsha2_256_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha2_256_init(key); + eay_hmacsha2_256_update(ctx, data); + res = eay_hmacsha2_256_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha2_256_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha2_256()); +} + +void +eay_hmacsha2_256_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha2_256_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA256_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha2_256 length mismatch %d.\n", res->l); +#else + printf("hmac sha2_256 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC SHA1 + */ +vchar_t * +eay_hmacsha1_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacsha1_init(key); + eay_hmacsha1_update(ctx, data); + res = eay_hmacsha1_final(ctx); + + return(res); +} + +caddr_t +eay_hmacsha1_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_sha1()); +} + +void +eay_hmacsha1_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacsha1_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (SHA_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac sha1 length mismatch %d.\n", res->l); +#else + printf("hmac sha1 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * HMAC MD5 + */ +vchar_t * +eay_hmacmd5_one(key, data) + vchar_t *key, *data; +{ + vchar_t *res; + caddr_t ctx; + + ctx = eay_hmacmd5_init(key); + eay_hmacmd5_update(ctx, data); + res = eay_hmacmd5_final(ctx); + + return(res); +} + +caddr_t +eay_hmacmd5_init(key) + vchar_t *key; +{ + return eay_hmac_init(key, EVP_md5()); +} + +void +eay_hmacmd5_update(c, data) + caddr_t c; + vchar_t *data; +{ + HMAC_Update((HMAC_CTX *)c, data->v, data->l); +} + +vchar_t * +eay_hmacmd5_final(c) + caddr_t c; +{ + vchar_t *res; + unsigned int l; + + if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0) + return NULL; + + HMAC_Final((HMAC_CTX *)c, res->v, &l); + res->l = l; + (void)racoon_free(c); + + if (MD5_DIGEST_LENGTH != res->l) { +#ifndef EAYDEBUG + plog(LLV_ERROR, LOCATION, NULL, + "hmac md5 length mismatch %d.\n", res->l); +#else + printf("hmac md5 length mismatch %d.\n", res->l); +#endif + vfree(res); + return NULL; + } + + return(res); +} + +/* + * SHA2-512 functions + */ +caddr_t +eay_sha2_512_init() +{ + SHA512_CTX *c = racoon_malloc(sizeof(*c)); + + SHA512_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_512_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA512_Update((SHA512_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_512_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA512_DIGEST_LENGTH)) == 0) + return(0); + + SHA512_Final(res->v, (SHA512_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_512_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_512_init(); + eay_sha2_512_update(ctx, data); + res = eay_sha2_512_final(ctx); + + return(res); +} + +int +eay_sha2_512_hashlen() +{ + return SHA512_DIGEST_LENGTH << 3; +} + +/* + * SHA2-384 functions + */ +caddr_t +eay_sha2_384_init() +{ + SHA384_CTX *c = racoon_malloc(sizeof(*c)); + + SHA384_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_384_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA384_Update((SHA384_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_384_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA384_DIGEST_LENGTH)) == 0) + return(0); + + SHA384_Final(res->v, (SHA384_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_384_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_384_init(); + eay_sha2_384_update(ctx, data); + res = eay_sha2_384_final(ctx); + + return(res); +} + +int +eay_sha2_384_hashlen() +{ + return SHA384_DIGEST_LENGTH << 3; +} + +/* + * SHA2-256 functions + */ +caddr_t +eay_sha2_256_init() +{ + SHA256_CTX *c = racoon_malloc(sizeof(*c)); + + SHA256_Init(c); + + return((caddr_t)c); +} + +void +eay_sha2_256_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA256_Update((SHA256_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha2_256_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA256_DIGEST_LENGTH)) == 0) + return(0); + + SHA256_Final(res->v, (SHA256_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha2_256_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha2_256_init(); + eay_sha2_256_update(ctx, data); + res = eay_sha2_256_final(ctx); + + return(res); +} + +int +eay_sha2_256_hashlen() +{ + return SHA256_DIGEST_LENGTH << 3; +} + +/* + * SHA functions + */ +caddr_t +eay_sha1_init() +{ + SHA_CTX *c = racoon_malloc(sizeof(*c)); + + SHA1_Init(c); + + return((caddr_t)c); +} + +void +eay_sha1_update(c, data) + caddr_t c; + vchar_t *data; +{ + SHA1_Update((SHA_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_sha1_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(SHA_DIGEST_LENGTH)) == 0) + return(0); + + SHA1_Final(res->v, (SHA_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_sha1_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_sha1_init(); + eay_sha1_update(ctx, data); + res = eay_sha1_final(ctx); + + return(res); +} + +int +eay_sha1_hashlen() +{ + return SHA_DIGEST_LENGTH << 3; +} + +/* + * MD5 functions + */ +caddr_t +eay_md5_init() +{ + MD5_CTX *c = racoon_malloc(sizeof(*c)); + + MD5_Init(c); + + return((caddr_t)c); +} + +void +eay_md5_update(c, data) + caddr_t c; + vchar_t *data; +{ + MD5_Update((MD5_CTX *)c, data->v, data->l); + + return; +} + +vchar_t * +eay_md5_final(c) + caddr_t c; +{ + vchar_t *res; + + if ((res = vmalloc(MD5_DIGEST_LENGTH)) == 0) + return(0); + + MD5_Final(res->v, (MD5_CTX *)c); + (void)racoon_free(c); + + return(res); +} + +vchar_t * +eay_md5_one(data) + vchar_t *data; +{ + caddr_t ctx; + vchar_t *res; + + ctx = eay_md5_init(); + eay_md5_update(ctx, data); + res = eay_md5_final(ctx); + + return(res); +} + +int +eay_md5_hashlen() +{ + return MD5_DIGEST_LENGTH << 3; +} + +/* + * eay_set_random + * size: number of bytes. + */ +vchar_t * +eay_set_random(size) + u_int32_t size; +{ + BIGNUM *r = NULL; + vchar_t *res = 0; + + if ((r = BN_new()) == NULL) + goto end; + BN_rand(r, size * 8, 0, 0); + eay_bn2v(&res, r); + +end: + if (r) + BN_free(r); + return(res); +} + +/* DH */ +int +eay_dh_generate(prime, g, publen, pub, priv) + vchar_t *prime, **pub, **priv; + u_int publen; + u_int32_t g; +{ + BIGNUM *p = NULL; + DH *dh = NULL; + int error = -1; + + /* initialize */ + /* pre-process to generate number */ + if (eay_v2bn(&p, prime) < 0) + goto end; + + if ((dh = DH_new()) == NULL) + goto end; + dh->p = p; + p = NULL; /* p is now part of dh structure */ + dh->g = NULL; + if ((dh->g = BN_new()) == NULL) + goto end; + if (!BN_set_word(dh->g, g)) + goto end; + + if (publen != 0) + dh->length = publen; + + /* generate public and private number */ + if (!DH_generate_key(dh)) + goto end; + + /* copy results to buffers */ + if (eay_bn2v(pub, dh->pub_key) < 0) + goto end; + if (eay_bn2v(priv, dh->priv_key) < 0) { + vfree(*pub); + goto end; + } + + error = 0; + +end: + if (dh != NULL) + DH_free(dh); + if (p != 0) + BN_free(p); + return(error); +} + +int +eay_dh_compute(prime, g, pub, priv, pub2, key) + vchar_t *prime, *pub, *priv, *pub2, **key; + u_int32_t g; +{ + BIGNUM *dh_pub = NULL; + DH *dh = NULL; + int l; + caddr_t v = NULL; + int error = -1; + + /* make public number to compute */ + if (eay_v2bn(&dh_pub, pub2) < 0) + goto end; + + /* make DH structure */ + if ((dh = DH_new()) == NULL) + goto end; + if (eay_v2bn(&dh->p, prime) < 0) + goto end; + if (eay_v2bn(&dh->pub_key, pub) < 0) + goto end; + if (eay_v2bn(&dh->priv_key, priv) < 0) + goto end; + dh->length = pub2->l * 8; + + dh->g = NULL; + if ((dh->g = BN_new()) == NULL) + goto end; + if (!BN_set_word(dh->g, g)) + goto end; + + if ((v = (caddr_t)racoon_calloc(prime->l, sizeof(u_char))) == NULL) + goto end; + if ((l = DH_compute_key(v, dh_pub, dh)) == -1) + goto end; + memcpy((*key)->v + (prime->l - l), v, l); + + error = 0; + +end: + if (dh_pub != NULL) + BN_free(dh_pub); + if (dh != NULL) + DH_free(dh); + if (v != NULL) + racoon_free(v); + return(error); +} + +#if 1 +int +eay_v2bn(bn, var) + BIGNUM **bn; + vchar_t *var; +{ + if ((*bn = BN_bin2bn(var->v, var->l, NULL)) == NULL) + return -1; + + return 0; +} +#else +/* + * convert vchar_t <-> BIGNUM. + * + * vchar_t: unit is u_char, network endian, most significant byte first. + * BIGNUM: unit is BN_ULONG, each of BN_ULONG is in host endian, + * least significant BN_ULONG must come first. + * + * hex value of "0x3ffe050104" is represented as follows: + * vchar_t: 3f fe 05 01 04 + * BIGNUM (BN_ULONG = u_int8_t): 04 01 05 fe 3f + * BIGNUM (BN_ULONG = u_int16_t): 0x0104 0xfe05 0x003f + * BIGNUM (BN_ULONG = u_int32_t_t): 0xfe050104 0x0000003f + */ +int +eay_v2bn(bn, var) + BIGNUM **bn; + vchar_t *var; +{ + u_char *p; + u_char *q; + BN_ULONG *r; + int l; + BN_ULONG num; + + *bn = BN_new(); + if (*bn == NULL) + goto err; + l = (var->l * 8 + BN_BITS2 - 1) / BN_BITS2; + if (bn_expand(*bn, l * BN_BITS2) == NULL) + goto err; + (*bn)->top = l; + + /* scan from least significant byte */ + p = (u_char *)var->v; + q = (u_char *)(var->v + var->l); + r = (*bn)->d; + num = 0; + l = 0; + do { + q--; + num = num | ((BN_ULONG)*q << (l++ * 8)); + if (l == BN_BYTES) { + *r++ = num; + num = 0; + l = 0; + } + } while (p < q); + if (l) + *r = num; + return 0; + +err: + if (*bn) + BN_free(*bn); + return -1; +} +#endif + +int +eay_bn2v(var, bn) + vchar_t **var; + BIGNUM *bn; +{ + *var = vmalloc(bn->top * BN_BYTES); + if (*var == NULL) + return(-1); + + (*var)->l = BN_bn2bin(bn, (*var)->v); + + return 0; +} + +const char * +eay_version() +{ + return SSLeay_version(SSLEAY_VERSION); +} diff --git a/racoon.tproj/crypto_openssl.h b/racoon.tproj/crypto_openssl.h new file mode 100644 index 0000000..51c920f --- /dev/null +++ b/racoon.tproj/crypto_openssl.h @@ -0,0 +1,189 @@ +/* $KAME: crypto_openssl.h,v 1.23 2001/08/14 12:26:06 sakane 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. 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. + */ + +#ifdef HAVE_SIGNING_C +/* X509 Certificate */ +#define GENT_OTHERNAME 0 +#define GENT_EMAIL 1 +#define GENT_DNS 2 +#define GENT_X400 3 +#define GENT_DIRNAME 4 +#define GENT_EDIPARTY 5 +#define GENT_URI 6 +#define GENT_IPADD 7 +#define GENT_RID 8 + +extern vchar_t *eay_str2asn1dn __P((char *, int)); +extern int eay_cmp_asn1dn __P((vchar_t *, vchar_t *)); +extern int eay_check_x509cert __P((vchar_t *, char *)); +extern vchar_t *eay_get_x509asn1subjectname __P((vchar_t *)); +extern int eay_get_x509subjectaltname __P((vchar_t *, char **, int *, int)); +extern char *eay_get_x509text __P((vchar_t *)); +extern vchar_t *eay_get_x509cert __P((char *)); +extern vchar_t *eay_get_x509sign __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_check_x509sign __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_check_pkcs7sign __P((vchar_t *, vchar_t *, vchar_t *)); + +/* RSA */ +extern vchar_t *eay_rsa_sign __P((vchar_t *, vchar_t *)); +extern int eay_rsa_verify __P((vchar_t *, vchar_t *, vchar_t *)); + +/* ASN.1 */ +extern vchar_t *eay_get_pkcs1privkey __P((char *)); +extern vchar_t *eay_get_pkcs1pubkey __P((char *)); +#endif + +/* string error */ +extern char *eay_strerror __P((void)); +extern void eay_init_error __P((void)); + +/* DES */ +extern vchar_t *eay_des_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_des_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_des_weakkey __P((vchar_t *)); +extern int eay_des_keylen __P((int)); + +/* IDEA */ +extern vchar_t *eay_idea_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_idea_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_idea_weakkey __P((vchar_t *)); +extern int eay_idea_keylen __P((int)); + +/* blowfish */ +extern vchar_t *eay_bf_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_bf_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_bf_weakkey __P((vchar_t *)); +extern int eay_bf_keylen __P((int)); + +/* RC5 */ +extern vchar_t *eay_rc5_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_rc5_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_rc5_weakkey __P((vchar_t *)); +extern int eay_rc5_keylen __P((int)); + +/* 3DES */ +extern vchar_t *eay_3des_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_3des_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_3des_weakkey __P((vchar_t *)); +extern int eay_3des_keylen __P((int)); + +/* CAST */ +extern vchar_t *eay_cast_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_cast_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_cast_weakkey __P((vchar_t *)); +extern int eay_cast_keylen __P((int)); + +/* AES(RIJNDAEL) */ +extern vchar_t *eay_aes_encrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *eay_aes_decrypt __P((vchar_t *, vchar_t *, vchar_t *)); +extern int eay_aes_weakkey __P((vchar_t *)); +extern int eay_aes_keylen __P((int)); + +/* misc */ +extern int eay_null_hashlen __P((void)); +extern int eay_kpdk_hashlen __P((void)); +extern int eay_twofish_keylen __P((int)); + +/* hash */ +/* HMAC SHA2 */ +extern vchar_t *eay_hmacsha2_512_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha2_512_init __P((vchar_t *)); +extern void eay_hmacsha2_512_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha2_512_final __P((caddr_t)); +extern vchar_t *eay_hmacsha2_384_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha2_384_init __P((vchar_t *)); +extern void eay_hmacsha2_384_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha2_384_final __P((caddr_t)); +extern vchar_t *eay_hmacsha2_256_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha2_256_init __P((vchar_t *)); +extern void eay_hmacsha2_256_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha2_256_final __P((caddr_t)); +/* HMAC SHA1 */ +extern vchar_t *eay_hmacsha1_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacsha1_init __P((vchar_t *)); +extern void eay_hmacsha1_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacsha1_final __P((caddr_t)); +/* HMAC MD5 */ +extern vchar_t *eay_hmacmd5_one __P((vchar_t *, vchar_t *)); +extern caddr_t eay_hmacmd5_init __P((vchar_t *)); +extern void eay_hmacmd5_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_hmacmd5_final __P((caddr_t)); + +/* SHA2 functions */ +extern caddr_t eay_sha2_512_init __P((void)); +extern void eay_sha2_512_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha2_512_final __P((caddr_t)); +extern vchar_t *eay_sha2_512_one __P((vchar_t *)); +extern int eay_sha2_512_hashlen __P((void)); + +extern caddr_t eay_sha2_384_init __P((void)); +extern void eay_sha2_384_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha2_384_final __P((caddr_t)); +extern vchar_t *eay_sha2_384_one __P((vchar_t *)); +extern int eay_sha2_384_hashlen __P((void)); + +extern caddr_t eay_sha2_256_init __P((void)); +extern void eay_sha2_256_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha2_256_final __P((caddr_t)); +extern vchar_t *eay_sha2_256_one __P((vchar_t *)); +extern int eay_sha2_256_hashlen __P((void)); + +/* SHA functions */ +extern caddr_t eay_sha1_init __P((void)); +extern void eay_sha1_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_sha1_final __P((caddr_t)); +extern vchar_t *eay_sha1_one __P((vchar_t *)); +extern int eay_sha1_hashlen __P((void)); + +/* MD5 functions */ +extern caddr_t eay_md5_init __P((void)); +extern void eay_md5_update __P((caddr_t, vchar_t *)); +extern vchar_t *eay_md5_final __P((caddr_t)); +extern vchar_t *eay_md5_one __P((vchar_t *)); +extern int eay_md5_hashlen __P((void)); + +/* eay_set_random */ +extern vchar_t *eay_set_random __P((u_int32_t)); + +/* DH */ +extern int eay_dh_generate __P((vchar_t *, u_int32_t, u_int, vchar_t **, vchar_t **)); +extern int eay_dh_compute __P((vchar_t *, u_int32_t, vchar_t *, vchar_t *, vchar_t *, vchar_t **)); + +/* misc */ +extern int eay_revbnl __P((vchar_t *)); +#include +extern int eay_v2bn __P((BIGNUM **, vchar_t *)); +extern int eay_bn2v __P((vchar_t **, BIGNUM *)); + +extern const char *eay_version __P((void)); + +#define CBC_BLOCKLEN 8 +#define IPSEC_ENCRYPTKEYLEN 8 diff --git a/racoon.tproj/debug.h b/racoon.tproj/debug.h new file mode 100644 index 0000000..d6926b4 --- /dev/null +++ b/racoon.tproj/debug.h @@ -0,0 +1,34 @@ +/* $KAME: debug.h,v 1.16 2000/12/15 13:43:54 sakane 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. 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. + */ + +/* define by main.c */ +extern int f_local; +extern int vflag; diff --git a/racoon.tproj/dhgroup.h b/racoon.tproj/dhgroup.h new file mode 100644 index 0000000..7b403ff --- /dev/null +++ b/racoon.tproj/dhgroup.h @@ -0,0 +1,198 @@ +/* $KAME: dhgroup.h,v 1.1 2001/08/14 15:00:47 sakane 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. 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. + */ + +#define OAKLEY_PRIME_MODP768 \ + "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 OAKLEY_PRIME_MODP1024 \ + "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 OAKLEY_PRIME_MODP1536 \ + "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 OAKLEY_PRIME_MODP2048 \ + "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 OAKLEY_PRIME_MODP3072 \ + "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 OAKLEY_PRIME_MODP4096 \ + "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" + +#define OAKLEY_PRIME_MODP6144 \ + "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" + +#define OAKLEY_PRIME_MODP8192 \ + "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" + +extern struct dhgroup dh_modp768; +extern struct dhgroup dh_modp1024; +extern struct dhgroup dh_modp1536; +extern struct dhgroup dh_modp2048; +extern struct dhgroup dh_modp3072; +extern struct dhgroup dh_modp4096; +extern struct dhgroup dh_modp6144; +extern struct dhgroup dh_modp8192; diff --git a/racoon.tproj/dnssec.c b/racoon.tproj/dnssec.c new file mode 100644 index 0000000..7cb297b --- /dev/null +++ b/racoon.tproj/dnssec.c @@ -0,0 +1,147 @@ +/* $KAME: dnssec.c,v 1.1 2001/04/11 06:11:55 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include "var.h" +#include "vmbuf.h" +#include "misc.h" +#include "plog.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "netdb_dnssec.h" +#include "strnames.h" +#include "dnssec.h" +#include "gcmalloc.h" + +extern int h_errno; + +cert_t * +dnssec_getcert(id) + vchar_t *id; +{ + cert_t *cert = NULL; + struct certinfo *res = NULL; + struct ipsecdoi_id_b *id_b; + int type; + char *name = NULL; + int namelen; + int error; + + id_b = (struct ipsecdoi_id_b *)id->v; + + namelen = id->l - sizeof(*id_b); + name = racoon_malloc(namelen + 1); + if (!name) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + return NULL; + } + memcpy(name, id_b + 1, namelen); + name[namelen] = '\0'; + + switch (id_b->type) { + case IPSECDOI_ID_FQDN: + error = getcertsbyname(name, &res); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getcertsbyname(\"%s\") failed.\n", name); + goto err; + } + break; + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV6_ADDR: + /* XXX should be processed to query PTR ? */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "inpropper ID type passed %s " + "though getcert method is dnssec.\n", + s_ipsecdoi_ident(id_b->type)); + return NULL; + } + + /* check response */ + if (res->ci_next == NULL) { + plog(LLV_WARNING, LOCATION, NULL, + "not supported multiple CERT RR.\n"); + } + switch (res->ci_type) { + case DNSSEC_TYPE_PKIX: + /* XXX is it enough condition to set this type ? */ + type = ISAKMP_CERT_X509SIGN; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "not supported CERT RR type %d.\n", res->ci_type); + goto err; + } + + /* create cert holder */ + cert = oakley_newcert(); + if (cert == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer.\n"); + goto err; + } + cert->pl = vmalloc(res->ci_certlen + 1); + if (cert->pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer.\n"); + goto err; + } + memcpy(cert->pl->v + 1, res->ci_cert, res->ci_certlen); + cert->pl->v[0] = type; + cert->cert.v = cert->pl->v + 1; + cert->cert.l = cert->pl->l - 1; + + plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n"); + plogdump(LLV_DEBUG, cert->pl->v, cert->pl->l); + +end: + if (res) + freecertinfo(res); + + return cert; + +err: + if (name) + racoon_free(name); + if (cert) + oakley_delcert(cert); + goto end; +} diff --git a/racoon.tproj/dnssec.h b/racoon.tproj/dnssec.h new file mode 100644 index 0000000..1c0a78b --- /dev/null +++ b/racoon.tproj/dnssec.h @@ -0,0 +1,32 @@ +/* $KAME$ */ + +/* + * 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. 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. + */ + +extern cert_t *dnssec_getcert __P((vchar_t *)); diff --git a/racoon.tproj/gcmalloc.h b/racoon.tproj/gcmalloc.h new file mode 100644 index 0000000..53a882a --- /dev/null +++ b/racoon.tproj/gcmalloc.h @@ -0,0 +1,114 @@ +/* $KAME: gcmalloc.h,v 1.3 2001/04/04 22:23:05 thorpej Exp $ */ + +/* + * Copyright (C) 2000, 2001 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. 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. + */ + +/* + * Debugging malloc glue for Racoon. + */ + +#ifndef _GCMALLOC_H_DEFINED +#define _GCMALLOC_H_DEFINED + +/* ElectricFence needs no special handling. */ + +/* + * Boehm-GC provides GC_malloc(), GC_realloc(), GC_free() functions, + * but not the traditional entry points. So what we do is provide + * malloc(), calloc(), realloc(), and free() entry points in the main + * program and letting the linker do the rest. + */ +#ifdef GC +#define GC_DEBUG +#include + +#ifdef RACOON_MAIN_PROGRAM +void * +malloc(size_t size) +{ + + return (GC_MALLOC(size)); +} + +void * +calloc(size_t number, size_t size) +{ + + /* GC_malloc() clears the storage. */ + return (GC_MALLOC(number * size)); +} + +void * +realloc(void *ptr, size_t size) +{ + + return (GC_REALLOC(ptr, size)); +} + +void +free(void *ptr) +{ + + GC_FREE(ptr); +} +#endif /* RACOON_MAIN_PROGRAM */ + +#define racoon_malloc(sz) GC_debug_malloc(sz, GC_EXTRAS) +#define racoon_calloc(cnt, sz) GC_debug_malloc(cnt * sz, GC_EXTRAS) +#define racoon_realloc(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS) +#define racoon_free(p) GC_debug_free(p) + +#endif /* GC */ + +/* + * Dmalloc only requires that you pull in a header file and link + * against libdmalloc. + */ +#ifdef DMALLOC +#include +#endif /* DMALLOC */ + +#ifdef DEBUG_RECORD_MALLOCATION +#include +#else +#ifndef racoon_malloc +#define racoon_malloc(sz) malloc((sz)) +#endif +#ifndef racoon_calloc +#define racoon_calloc(cnt, sz) calloc((cnt), (sz)) +#endif +#ifndef racoon_realloc +#define racoon_realloc(old, sz) realloc((old), (sz)) +#endif +#ifndef racoon_free +#define racoon_free(p) free((p)) +#endif +#endif /* DEBUG_RECORD_MALLOCATION */ + +#endif /* _GCMALLOC_H_DEFINED */ diff --git a/racoon.tproj/getcertsbyname.c b/racoon.tproj/getcertsbyname.c new file mode 100644 index 0000000..e797fc4 --- /dev/null +++ b/racoon.tproj/getcertsbyname.c @@ -0,0 +1,410 @@ +/* $KAME: getcertsbyname.c,v 1.6 2001/08/07 09:17:49 itojun 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. 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. + */ + +#include +#include +#include + +#include +#include +#include +#ifdef HAVE_LWRES_GETRRSETBYNAME +#include +#include +#else +#include +#endif +#include +#include +#include + +#ifdef DNSSEC_DEBUG +#include +#include +#endif + +#include "netdb_dnssec.h" + +/* XXX should it use ci_errno to hold errno instead of h_errno ? */ +extern int h_errno; + +static struct certinfo *getnewci __P((int, int, int, int, int, char *)); + +static struct certinfo * +getnewci(qtype, keytag, algorithm, flags, certlen, cert) + int qtype, keytag, algorithm, flags, certlen; + char *cert; +{ + struct certinfo *res; + + res = malloc(sizeof(*res)); + if (!res) + return NULL; + + memset(res, 0, sizeof(*res)); + res->ci_type = qtype; + res->ci_keytag = keytag; + res->ci_algorithm = algorithm; + res->ci_flags = flags; + res->ci_certlen = certlen; + res->ci_cert = malloc(certlen); + if (!res->ci_cert) { + free(res); + return NULL; + } + memcpy(res->ci_cert, cert, certlen); + + return res; +} + +void +freecertinfo(ci) + struct certinfo *ci; +{ + struct certinfo *next; + + do { + next = ci->ci_next; + if (ci->ci_cert) + free(ci->ci_cert); + free(ci); + ci = next; + } while (ci); +} + +/* + * get CERT RR by FQDN and create certinfo structure chain. + */ +#ifdef HAVE_LWRES_GETRRSETBYNAME +#define getrrsetbyname lwres_getrrsetbyname +#define freerrset lwres_freerrset +#define hstrerror lwres_hstrerror +#endif +#if defined(HAVE_LWRES_GETRRSETBYNAME) || defined(AHVE_GETRRSETBYNAME) +int +getcertsbyname(name, res) + char *name; + struct certinfo **res; +{ + int rdlength; + char *cp; + int type, keytag, algorithm; + struct certinfo head, *cur; + struct rrsetinfo *rr = NULL; + int i; + int error = -1; + + /* initialize res */ + *res = NULL; + + memset(&head, 0, sizeof(head)); + cur = &head; + + error = getrrsetbyname(name, C_IN, T_CERT, 0, &rr); + if (error) { +#ifdef DNSSEC_DEBUG + printf("getrrsetbyname: %s\n", hstrerror(error)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + + if (rr->rri_rdclass != C_IN + || rr->rri_rdtype != T_CERT + || rr->rri_nrdatas == 0) { +#ifdef DNSSEC_DEBUG + printf("getrrsetbyname: %s", hstrerror(error)); +#endif + h_errno = NO_RECOVERY; + goto end; + } +#ifdef DNSSEC_DEBUG + if (!(rr->rri_flags & LWRDATA_VALIDATED)) + printf("rr is not valid"); +#endif + + for (i = 0; i < rr->rri_nrdatas; i++) { + rdlength = rr->rri_rdatas[i].rdi_length; + cp = rr->rri_rdatas[i].rdi_data; + + GETSHORT(type, cp); /* type */ + rdlength -= INT16SZ; + GETSHORT(keytag, cp); /* key tag */ + rdlength -= INT16SZ; + algorithm = *cp++; /* algorithm */ + rdlength -= 1; + +#ifdef DNSSEC_DEBUG + printf("type=%d keytag=%d alg=%d len=%d\n", + type, keytag, algorithm, rdlength); +#endif + + /* create new certinfo */ + cur->ci_next = getnewci(type, keytag, algorithm, + rr->rri_flags, rdlength, cp); + if (!cur->ci_next) { +#ifdef DNSSEC_DEBUG + printf("getnewci: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cur = cur->ci_next; + } + + *res = head.ci_next; + error = 0; + +end: + if (rr) + freerrset(rr); + if (error && head.ci_next) + freecertinfo(head.ci_next); + + return error; +} +#else /*!HAVE_LWRES_GETRRSETBYNAME*/ +int +getcertsbyname(name, res) + char *name; + struct certinfo **res; +{ + caddr_t answer = NULL, p; + int buflen, anslen, len; + HEADER *hp; + int qdcount, ancount, rdlength; + char *cp, *eom; + char hostbuf[1024]; /* XXX */ + int qtype, qclass, keytag, algorithm; + struct certinfo head, *cur; + int error = -1; + + /* initialize res */ + *res = NULL; + + memset(&head, 0, sizeof(head)); + cur = &head; + + /* get CERT RR */ + buflen = 512; + do { + + buflen *= 2; + p = realloc(answer, buflen); + if (!p) { +#ifdef DNSSEC_DEBUG + printf("realloc: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + answer = p; + + anslen = res_query(name, C_IN, T_CERT, answer, buflen); + if (anslen == -1) + goto end; + + } while (buflen < anslen); + +#ifdef DNSSEC_DEBUG + printf("get a DNS packet len=%d\n", anslen); +#endif + + /* parse CERT RR */ + eom = answer + anslen; + + hp = (HEADER *)answer; + qdcount = ntohs(hp->qdcount); + ancount = ntohs(hp->ancount); + + /* question section */ + if (qdcount != 1) { +#ifdef DNSSEC_DEBUG + printf("query count is not 1.\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cp = (char *)(hp + 1); + len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf)); + if (len < 0) { +#ifdef DNSSEC_DEBUG + printf("dn_expand failed.\n"); +#endif + goto end; + } + cp += len; + GETSHORT(qtype, cp); /* QTYPE */ + GETSHORT(qclass, cp); /* QCLASS */ + + /* answer section */ + while (ancount-- && cp < eom) { + len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf)); + if (len < 0) { +#ifdef DNSSEC_DEBUG + printf("dn_expand failed.\n"); +#endif + goto end; + } + cp += len; + GETSHORT(qtype, cp); /* TYPE */ + GETSHORT(qclass, cp); /* CLASS */ + cp += INT32SZ; /* TTL */ + GETSHORT(rdlength, cp); /* RDLENGTH */ + + /* CERT RR */ + if (qtype != T_CERT) { +#ifdef DNSSEC_DEBUG + printf("not T_CERT\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } + GETSHORT(qtype, cp); /* type */ + rdlength -= INT16SZ; + GETSHORT(keytag, cp); /* key tag */ + rdlength -= INT16SZ; + algorithm = *cp++; /* algorithm */ + rdlength -= 1; + if (cp + rdlength > eom) { +#ifdef DNSSEC_DEBUG + printf("rdlength is too long.\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } +#ifdef DNSSEC_DEBUG + printf("type=%d keytag=%d alg=%d len=%d\n", + qtype, keytag, algorithm, rdlength); +#endif + + /* create new certinfo */ + cur->ci_next = getnewci(qtype, keytag, algorithm, + 0, rdlength, cp); + if (!cur->ci_next) { +#ifdef DNSSEC_DEBUG + printf("getnewci: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cur = cur->ci_next; + + cp += rdlength; + } + + *res = head.ci_next; + error = 0; + +end: + if (answer) + free(answer); + if (error && head.ci_next) + freecertinfo(head.ci_next); + + return error; +} +#endif + +#ifdef DNSSEC_DEBUG +int +b64encode(p, len) + char *p; + int len; +{ + static const char b64t[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/="; + + while (len > 2) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)]); + printf("%c", b64t[((p[1] << 2) & 0x3c) | ((p[2] >> 6) & 0x03)]); + printf("%c", b64t[p[2] & 0x3f]); + len -= 3; + p += 3; + } + + if (len == 2) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30)| ((p[1] >> 4) & 0x0f)]); + printf("%c", b64t[((p[1] << 2) & 0x3c)]); + printf("%c", '='); + } else if (len == 1) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30)]); + printf("%c", '='); + printf("%c", '='); + } + + return 0; +} + +int +main(ac, av) + int ac; + char **av; +{ + struct certinfo *res, *p; + int i; + + if (ac < 2) { + printf("Usage: a.out (FQDN)\n"); + exit(1); + } + + i = getcertsbyname(*(av + 1), &res); + if (i != 0) { + herror("getcertsbyname"); + exit(1); + } + printf("getcertsbyname succeeded.\n"); + + i = 0; + for (p = res; p; p = p->ci_next) { + printf("certinfo[%d]:\n", i); + printf("\tci_type=%d\n", p->ci_type); + printf("\tci_keytag=%d\n", p->ci_keytag); + printf("\tci_algorithm=%d\n", p->ci_algorithm); + printf("\tci_flags=%d\n", p->ci_flags); + printf("\tci_certlen=%d\n", p->ci_certlen); + printf("\tci_cert: "); + b64encode(p->ci_cert, p->ci_certlen); + printf("\n"); + i++; + } + + freecertinfo(res); + + exit(0); +} +#endif diff --git a/racoon.tproj/grabmyaddr.c b/racoon.tproj/grabmyaddr.c new file mode 100644 index 0000000..d3a364f --- /dev/null +++ b/racoon.tproj/grabmyaddr.c @@ -0,0 +1,624 @@ +/* $KAME: grabmyaddr.c,v 1.28 2001/12/12 15:29:12 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_GETIFADDRS +#include +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "localconf.h" +#include "grabmyaddr.h" +#include "sockmisc.h" +#include "isakmp_var.h" +#include "gcmalloc.h" + +#ifndef HAVE_GETIFADDRS +static unsigned int if_maxindex __P((void)); +#endif +static struct myaddrs *find_myaddr __P((struct myaddrs *, struct myaddrs *)); +static int suitable_ifaddr __P((const char *, const struct sockaddr *)); +#ifdef INET6 +static int suitable_ifaddr6 __P((const char *, const struct sockaddr *)); +#endif + +#ifndef HAVE_GETIFADDRS +static unsigned int +if_maxindex() +{ + struct if_nameindex *p, *p0; + unsigned int max = 0; + + p0 = if_nameindex(); + for (p = p0; p && p->if_index && p->if_name; p++) { + if (max < p->if_index) + max = p->if_index; + } + if_freenameindex(p0); + return max; +} +#endif + +void +clear_myaddr(db) + struct myaddrs **db; +{ + struct myaddrs *p; + + while (*db) { + p = (*db)->next; + delmyaddr(*db); + *db = p; + } +} + +static struct myaddrs * +find_myaddr(db, p) + struct myaddrs *db; + struct myaddrs *p; +{ + struct myaddrs *q; + char h1[NI_MAXHOST], h2[NI_MAXHOST]; + + if (getnameinfo(p->addr, p->addr->sa_len, h1, sizeof(h1), NULL, 0, + NI_NUMERICHOST | niflags) != 0) + return NULL; + + for (q = db; q; q = q->next) { + if (p->addr->sa_len != q->addr->sa_len) + continue; + if (getnameinfo(q->addr, q->addr->sa_len, h2, sizeof(h2), + NULL, 0, NI_NUMERICHOST | niflags) != 0) + return NULL; + if (strcmp(h1, h2) == 0) + return q; + } + + return NULL; +} + +void +grab_myaddrs() +{ +#ifdef HAVE_GETIFADDRS + struct myaddrs *p, *q, *old; + struct ifaddrs *ifa0, *ifap; +#ifdef INET6 +#ifdef __KAME__ + struct sockaddr_in6 *sin6; +#endif +#endif + +#if defined(YIPS_DEBUG) + char _addr1_[NI_MAXHOST]; +#endif + + if (getifaddrs(&ifa0)) { + plog(LLV_ERROR, LOCATION, NULL, + "getifaddrs failed: %s\n", strerror(errno)); + exit(1); + /*NOTREACHED*/ + } + + old = lcconf->myaddrs; + + for (ifap = ifa0; ifap; ifap = ifap->ifa_next) { + + if (ifap->ifa_addr->sa_family != AF_INET +#ifdef INET6 + && ifap->ifa_addr->sa_family != AF_INET6 +#endif + ) + continue; + + if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) { + plog(LLV_ERROR, LOCATION, NULL, + "unsuitable ifaddr: %s\n", + saddr2str(ifap->ifa_addr)); + continue; + } + + p = newmyaddr(); + if (p == NULL) { + exit(1); + /*NOTREACHED*/ + } + p->addr = dupsaddr(ifap->ifa_addr); + if (p->addr == NULL) { + exit(1); + /*NOTREACHED*/ + } +#ifdef INET6 +#ifdef __KAME__ + if (ifap->ifa_addr->sa_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *)p->addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) + || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + } + } +#endif +#endif + if (getnameinfo(p->addr, p->addr->sa_len, + _addr1_, sizeof(_addr1_), + NULL, 0, + NI_NUMERICHOST | niflags)) + strcpy(_addr1_, "(invalid)"); + plog(LLV_DEBUG, LOCATION, NULL, + "my interface: %s (%s)\n", + _addr1_, ifap->ifa_name); + q = find_myaddr(old, p); + if (q) + p->sock = q->sock; + else + p->sock = -1; + p->next = lcconf->myaddrs; + lcconf->myaddrs = p; + } + + freeifaddrs(ifa0); + + clear_myaddr(&old); + +#else /*!HAVE_GETIFADDRS*/ + int s; + unsigned int maxif; + int len; + struct ifreq *iflist; + struct ifconf ifconf; + struct ifreq *ifr, *ifr_end; + struct myaddrs *p, *q, *old; +#ifdef INET6 +#ifdef __KAME__ + struct sockaddr_in6 *sin6; +#endif +#endif + +#if defined(YIPS_DEBUG) + char _addr1_[NI_MAXHOST]; +#endif + + maxif = if_maxindex() + 1; + len = maxif * sizeof(struct sockaddr_storage) * 4; /* guess guess */ + + iflist = (struct ifreq *)racoon_malloc(len); + if (!iflist) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer\n"); + exit(1); + /*NOTREACHED*/ + } + + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket(SOCK_DGRAM) failed: %s\n", + strerror(errno)); + exit(1); + /*NOTREACHED*/ + } + memset(&ifconf, 0, sizeof(ifconf)); + ifconf.ifc_req = iflist; + ifconf.ifc_len = len; + if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ioctl(SIOCGIFCONF) failed: %s\n", + strerror(errno)); + exit(1); + /*NOTREACHED*/ + } + close(s); + + old = lcconf->myaddrs; + + /* Look for this interface in the list */ + ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len); + +#define _IFREQ_LEN(p) \ + (sizeof((p)->ifr_name) + (p)->ifr_addr.sa_len > sizeof(struct ifreq) \ + ? sizeof((p)->ifr_name) + (p)->ifr_addr.sa_len : sizeof(struct ifreq)) + + for (ifr = ifconf.ifc_req; + ifr < ifr_end; + ifr = (struct ifreq *)((caddr_t)ifr + _IFREQ_LEN(ifr))) { + + switch (ifr->ifr_addr.sa_family) { + case AF_INET: +#ifdef INET6 + case AF_INET6: +#endif + if (!suitable_ifaddr(ifr->ifr_name, &ifr->ifr_addr)) { + plog(LLV_DEBUG, LOCATION, NULL, + "unsuitable ifaddr %s\n"); + continue; + } + + p = newmyaddr(); + if (p == NULL) { + exit(1); + /*NOTREACHED*/ + } + p->addr = dupsaddr(&ifr->ifr_addr); + if (p->addr == NULL) { + exit(1); + /*NOTREACHED*/ + } +#ifdef INET6 +#ifdef __KAME__ + sin6 = (struct sockaddr_in6 *)p->addr; + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) + || IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) { + sin6->sin6_scope_id = + ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + } +#endif +#endif + if (getnameinfo(p->addr, p->addr->sa_len, + _addr1_, sizeof(_addr1_), + NULL, 0, + NI_NUMERICHOST | niflags)) + strcpy(_addr1_, "(invalid)"); + plog(LLV_DEBUG, LOCATION, NULL, + "my interface: %s (%s)\n", + _addr1_, ifr->ifr_name); + q = find_myaddr(old, p); + if (q) + p->sock = q->sock; + else + p->sock = -1; + p->next = lcconf->myaddrs; + lcconf->myaddrs = p; + break; + default: + break; + } + } + + clear_myaddr(&old); + + racoon_free(iflist); +#endif /*HAVE_GETIFADDRS*/ +} + +/* + * check the interface is suitable or not + */ +static int +suitable_ifaddr(ifname, ifaddr) + const char *ifname; + const struct sockaddr *ifaddr; +{ + switch(ifaddr->sa_family) { + case AF_INET: + return 1; +#ifdef INET6 + case AF_INET6: + return suitable_ifaddr6(ifname, ifaddr); +#endif + default: + return 0; + } + /*NOTREACHED*/ +} + +#ifdef INET6 +static int +suitable_ifaddr6(ifname, ifaddr) + const char *ifname; + const struct sockaddr *ifaddr; +{ + struct in6_ifreq ifr6; + int s; + + if (ifaddr->sa_family != AF_INET6) + return 0; + + s = socket(PF_INET6, SOCK_DGRAM, 0); + if (s == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "socket(SOCK_DGRAM) failed:%s\n", strerror(errno)); + return 0; + } + + memset(&ifr6, 0, sizeof(ifr6)); + strncpy(ifr6.ifr_name, ifname, strlen(ifname)); + + ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr; + + if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno)); + close(s); + return 0; + } + + close(s); + + if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED + || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED) + return 0; + + /* suitable */ + return 1; +} +#endif + +int +update_myaddrs() +{ + char msg[BUFSIZ]; + int len; + struct rt_msghdr *rtm; + + len = read(lcconf->rtsock, msg, sizeof(msg)); + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "read(PF_ROUTE) failed: %s\n", + strerror(errno)); + return 0; + } + rtm = (struct rt_msghdr *)msg; + if (len < rtm->rtm_msglen) { + plog(LLV_ERROR, LOCATION, NULL, + "read(PF_ROUTE) short read\n"); + return 0; + } + if (rtm->rtm_version != RTM_VERSION) { + plog(LLV_ERROR, LOCATION, NULL, + "routing socket version mismatch\n"); + close(lcconf->rtsock); + lcconf->rtsock = 0; + return 0; + } + switch (rtm->rtm_type) { + case RTM_NEWADDR: + case RTM_DELADDR: + case RTM_DELETE: + case RTM_IFINFO: + break; + case RTM_MISS: + /* ignore this message silently */ + return 0; + default: + plog(LLV_DEBUG, LOCATION, NULL, + "msg %d not interesting\n", rtm->rtm_type); + return 0; + } + /* XXX more filters here? */ + + plog(LLV_DEBUG, LOCATION, NULL, + "caught rtm:%d, need update interface address list\n", + rtm->rtm_type); + return 1; +} + +/* + * initialize default port for ISAKMP to send, if no "listen" + * directive is specified in config file. + * + * DO NOT listen to wildcard addresses. if you receive packets to + * wildcard address, you'll be in trouble (DoS attack possible by + * broadcast storm). + */ +int +autoconf_myaddrsport() +{ + struct myaddrs *p; + struct sockaddr_in *sin4; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + int n; + + plog(LLV_DEBUG, LOCATION, NULL, + "configuring default isakmp port.\n"); + n = 0; + for (p = lcconf->myaddrs; p; p = p->next) { + switch (p->addr->sa_family) { + case AF_INET: + sin4 = (struct sockaddr_in *)p->addr; + sin4->sin_port = htons(lcconf->port_isakmp); + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)p->addr; + sin6->sin6_port = htons(lcconf->port_isakmp); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported AF %d\n", p->addr->sa_family); + goto err; + } + n++; + } + plog(LLV_DEBUG, LOCATION, NULL, + "%d addrs are configured successfully\n", n); + + return 0; +err: + plog(LLV_ERROR, LOCATION, NULL, "address autoconfiguration failed\n"); + return -1; +} + +/* + * get a port number to which racoon binded. + * NOTE: network byte order returned. + */ +u_short +getmyaddrsport(local) + struct sockaddr *local; +{ + struct myaddrs *p; + + /* get a relative port */ + for (p = lcconf->myaddrs; p; p = p->next) { + if (!p->addr) + continue; + if (!cmpsaddrwop(local, p->addr)) { + switch (p->addr->sa_family) { + case AF_INET: + return ((struct sockaddr_in *)p->addr)->sin_port; +#ifdef INET6 + case AF_INET6: + return ((struct sockaddr_in6 *)p->addr)->sin6_port; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", + p->addr->sa_family); + return -1; + } + } + continue; + } + + return htons(PORT_ISAKMP); +} + +struct myaddrs * +newmyaddr() +{ + struct myaddrs *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer for myaddrs.\n"); + return NULL; + } + + new->next = NULL; + new->addr = NULL; + + return new; +} + +void +insmyaddr(new, head) + struct myaddrs *new; + struct myaddrs **head; +{ + new->next = *head; + *head = new; +} + +void +delmyaddr(myaddr) + struct myaddrs *myaddr; +{ + if (myaddr->addr) + racoon_free(myaddr->addr); + racoon_free(myaddr); +} + +int +initmyaddr() +{ + /* initialize routing socket */ + lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC); + if (lcconf->rtsock < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket(PF_ROUTE) failed: %s", + strerror(errno)); + return -1; + } + + if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) { + grab_myaddrs(); + + if (autoconf_myaddrsport() < 0) + return -1; + } + + return 0; +} + +/* select the socket to be sent */ +/* should implement other method. */ +int +getsockmyaddr(my) + struct sockaddr *my; +{ + struct myaddrs *p, *lastresort = NULL; + + for (p = lcconf->myaddrs; p; p = p->next) { + if (p->addr == NULL) + continue; + if (my->sa_family == p->addr->sa_family) + lastresort = p; + if (my->sa_len == p->addr->sa_len + && memcmp(my, p->addr, my->sa_len) == 0) { + break; + } + } + if (!p) + p = lastresort; + if (!p) { + plog(LLV_ERROR, LOCATION, NULL, + "no socket matches address family %d\n", + my->sa_family); + return -1; + } + + return p->sock; +} diff --git a/racoon.tproj/grabmyaddr.h b/racoon.tproj/grabmyaddr.h new file mode 100644 index 0000000..5417e38 --- /dev/null +++ b/racoon.tproj/grabmyaddr.h @@ -0,0 +1,47 @@ +/* $KAME: grabmyaddr.h,v 1.5 2000/10/04 17:40:59 itojun 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. 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. + */ + +struct myaddrs { + struct myaddrs *next; + struct sockaddr *addr; + int sock; +}; + +extern void clear_myaddr __P((struct myaddrs **)); +extern void grab_myaddrs __P((void)); +extern int update_myaddrs __P((void)); +extern int autoconf_myaddrsport __P((void)); +extern u_short getmyaddrsport __P((struct sockaddr *)); +extern struct myaddrs *newmyaddr __P((void)); +extern void insmyaddr __P((struct myaddrs *, struct myaddrs **)); +extern void delmyaddr __P((struct myaddrs *)); +extern int initmyaddr __P((void)); +extern int getsockmyaddr __P((struct sockaddr *)); diff --git a/racoon.tproj/gssapi.c b/racoon.tproj/gssapi.c new file mode 100644 index 0000000..07a50ca --- /dev/null +++ b/racoon.tproj/gssapi.c @@ -0,0 +1,709 @@ +/* $KAME: gssapi.c,v 1.18 2001/03/05 23:36:31 thorpej Exp $ */ + +/* + * Copyright 2000 Wasabi Systems, Inc. + * All rights reserved. + * + * This software was written by Frank van der Linden of Wasabi Systems + * for Zembu Labs, Inc. http://www.zembu.com/ + * + * 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 Wasabi Systems for + * Zembu Labs, Inc. http://www.zembu.com/ + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#ifdef HAVE_GSSAPI +#include +#include +#include +#include + +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "localconf.h" +#include "remoteconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "pfkey.h" +#include "isakmp_ident.h" +#include "isakmp_inf.h" +#include "vendorid.h" +#include "gcmalloc.h" + +#include "gssapi.h" + +static void +gssapi_error(OM_uint32 status_code, const char *where, + const char *fmt, ...) +{ + OM_uint32 message_context, maj_stat, min_stat; + gss_buffer_desc status_string; + va_list ap; + + va_start(ap, fmt); + plogv(LLV_ERROR, where, NULL, fmt, ap); + va_end(ap); + + message_context = 0; + + do { + maj_stat = gss_display_status(&min_stat, status_code, + GSS_C_MECH_CODE, GSS_C_NO_OID, &message_context, + &status_string); + if (GSS_ERROR(maj_stat)) + plog(LLV_ERROR, LOCATION, NULL, + "UNABLE TO GET GSSAPI ERROR CODE\n"); + else { + plog(LLV_ERROR, where, NULL, + "%s\n", status_string.value); + gss_release_buffer(&min_stat, &status_string); + } + } while (message_context != 0); +} + +/* + * vmbufs and gss_buffer_descs are really just the same on NetBSD, but + * this is to be portable. + */ +static int +gssapi_vm2gssbuf(vchar_t *vmbuf, gss_buffer_t gsstoken) +{ + + gsstoken->value = racoon_malloc(vmbuf->l); + if (gsstoken->value == NULL) + return -1; + memcpy(gsstoken->value, vmbuf->v, vmbuf->l); + gsstoken->length = vmbuf->l; + + return 0; +} + +static int +gssapi_gss2vmbuf(gss_buffer_t gsstoken, vchar_t **vmbuf) +{ + + *vmbuf = vmalloc(gsstoken->length); + if (*vmbuf == NULL) + return -1; + memcpy((*vmbuf)->v, gsstoken->value, gsstoken->length); + (*vmbuf)->l = gsstoken->length; + + return 0; +} + +static int +gssapi_get_default_name(struct ph1handle *iph1, int remote, gss_name_t *service) +{ + char name[NI_MAXHOST]; + struct sockaddr *sa; + gss_buffer_desc name_token; + OM_uint32 min_stat, maj_stat; + + sa = remote ? iph1->remote : iph1->local; + + if (getnameinfo(sa, sa->sa_len, name, NI_MAXHOST, NULL, 0, 0) != 0) + return -1; + + name_token.length = asprintf((char **)&name_token.value, + "%s@%s", GSSAPI_DEF_NAME, name); + maj_stat = gss_import_name(&min_stat, &name_token, + GSS_C_NT_HOSTBASED_SERVICE, service); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "import name\n"); + maj_stat = gss_release_buffer(&min_stat, &name_token); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release name_token"); + return -1; + } + maj_stat = gss_release_buffer(&min_stat, &name_token); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release name_token"); + + return 0; +} + +static int +gssapi_init(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + gss_buffer_desc id_token, cred_token; + gss_buffer_t cred = &cred_token; + gss_name_t princ, canon_princ; + OM_uint32 maj_stat, min_stat; + + gps = racoon_calloc(1, sizeof (struct gssapi_ph1_state)); + if (gps == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "racoon_calloc failed\n"); + return -1; + } + gps->gss_context = GSS_C_NO_CONTEXT; + gps->gss_cred = GSS_C_NO_CREDENTIAL; + + gssapi_set_state(iph1, gps); + + if (iph1->rmconf->proposal->gssid != NULL) { + id_token.length = iph1->rmconf->proposal->gssid->l; + id_token.value = iph1->rmconf->proposal->gssid->v; + maj_stat = gss_import_name(&min_stat, &id_token, GSS_C_NO_OID, + &princ); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "import name\n"); + gssapi_free_state(iph1); + return -1; + } + } else + gssapi_get_default_name(iph1, 0, &princ); + + maj_stat = gss_canonicalize_name(&min_stat, princ, GSS_C_NO_OID, + &canon_princ); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "canonicalize name\n"); + maj_stat = gss_release_name(&min_stat, &princ); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release princ\n"); + gssapi_free_state(iph1); + return -1; + } + maj_stat = gss_release_name(&min_stat, &princ); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release princ\n"); + + maj_stat = gss_export_name(&min_stat, canon_princ, cred); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "export name\n"); + maj_stat = gss_release_name(&min_stat, &canon_princ); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release canon_princ\n"); + gssapi_free_state(iph1); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%*s' creds\n", + cred->length, cred->value); + maj_stat = gss_release_buffer(&min_stat, cred); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release cred buffer\n"); + + maj_stat = gss_acquire_cred(&min_stat, canon_princ, GSS_C_INDEFINITE, + GSS_C_NO_OID_SET, GSS_C_BOTH, &gps->gss_cred, NULL, NULL); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "acquire cred\n"); + maj_stat = gss_release_name(&min_stat, &canon_princ); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release canon_princ\n"); + gssapi_free_state(iph1); + return -1; + } + maj_stat = gss_release_name(&min_stat, &canon_princ); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release canon_princ\n"); + + return 0; +} + +int +gssapi_get_itoken(struct ph1handle *iph1, int *lenp) +{ + struct gssapi_ph1_state *gps; + gss_buffer_desc empty, name_token; + gss_buffer_t itoken, rtoken, dummy; + OM_uint32 maj_stat, min_stat; + gss_name_t partner; + + if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0) + return -1; + + gps = gssapi_get_state(iph1); + + empty.length = 0; + empty.value = NULL; + dummy = ∅ + + if (iph1->approval != NULL && iph1->approval->gssid != NULL) { + plog(LLV_DEBUG, LOCATION, NULL, "using provided service '%s'\n", + iph1->approval->gssid->v); + name_token.length = iph1->approval->gssid->l; + name_token.value = iph1->approval->gssid->v; + maj_stat = gss_import_name(&min_stat, &name_token, + GSS_C_NO_OID, &partner); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "import of %s\n", + name_token.value); + return -1; + } + } else + if (gssapi_get_default_name(iph1, 1, &partner) < 0) + return -1; + + rtoken = gps->gsscnt_p == 0 ? dummy : &gps->gss_p[gps->gsscnt_p - 1]; + itoken = &gps->gss[gps->gsscnt]; + + gps->gss_status = gss_init_sec_context(&min_stat, gps->gss_cred, + &gps->gss_context, partner, GSS_C_NO_OID, + GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG | + GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG, + 0, GSS_C_NO_CHANNEL_BINDINGS, rtoken, NULL, + itoken, NULL, NULL); + + if (GSS_ERROR(gps->gss_status)) { + gssapi_error(min_stat, LOCATION, "init_sec_context\n"); + maj_stat = gss_release_name(&min_stat, &partner); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release name\n"); + return -1; + } + maj_stat = gss_release_name(&min_stat, &partner); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release name\n"); + + plog(LLV_DEBUG, LOCATION, NULL, "gss_init_sec_context status %x\n", + gps->gss_status); + + if (lenp) + *lenp = itoken->length; + + if (itoken->length != 0) + gps->gsscnt++; + + return 0; +} + +/* + * Call gss_accept_context, with token just read from the wire. + */ +int +gssapi_get_rtoken(struct ph1handle *iph1, int *lenp) +{ + struct gssapi_ph1_state *gps; + gss_buffer_desc name_token; + gss_buffer_t itoken, rtoken; + OM_uint32 min_stat, maj_stat; + gss_name_t client_name; + + if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0) + return -1; + + gps = gssapi_get_state(iph1); + + rtoken = &gps->gss_p[gps->gsscnt_p - 1]; + itoken = &gps->gss[gps->gsscnt]; + + gps->gss_status = gss_accept_sec_context(&min_stat, &gps->gss_context, + gps->gss_cred, rtoken, GSS_C_NO_CHANNEL_BINDINGS, &client_name, + NULL, itoken, NULL, NULL, NULL); + + if (GSS_ERROR(gps->gss_status)) { + gssapi_error(min_stat, LOCATION, "accept_sec_context\n"); + return -1; + } + + maj_stat = gss_display_name(&min_stat, client_name, &name_token, NULL); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "gss_display_name\n"); + maj_stat = gss_release_name(&min_stat, &client_name); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release client_name\n"); + return -1; + } + maj_stat = gss_release_name(&min_stat, &client_name); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release client_name\n"); + + plog(LLV_DEBUG, LOCATION, NULL, + "gss_accept_sec_context: other side is %s\n", + name_token.value); + maj_stat = gss_release_buffer(&min_stat, &name_token); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release name buffer\n"); + + if (itoken->length != 0) + gps->gsscnt++; + + if (lenp) + *lenp = itoken->length; + + return 0; +} + +int +gssapi_save_received_token(struct ph1handle *iph1, vchar_t *token) +{ + struct gssapi_ph1_state *gps; + gss_buffer_t gsstoken; + int ret; + + if (gssapi_get_state(iph1) == NULL && gssapi_init(iph1) < 0) + return -1; + + gps = gssapi_get_state(iph1); + + gsstoken = &gps->gss_p[gps->gsscnt_p]; + + ret = gssapi_vm2gssbuf(token, gsstoken); + if (ret < 0) + return ret; + gps->gsscnt_p++; + + return 0; +} + +int +gssapi_get_token_to_send(struct ph1handle *iph1, vchar_t **token) +{ + struct gssapi_ph1_state *gps; + gss_buffer_t gsstoken; + int ret; + + gps = gssapi_get_state(iph1); + if (gps == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "gssapi not yet initialized?\n"); + return -1; + } + gsstoken = &gps->gss[gps->gsscnt - 1]; + ret = gssapi_gss2vmbuf(gsstoken, token); + if (ret < 0) + return ret; + + return 0; +} + +int +gssapi_get_itokens(struct ph1handle *iph1, vchar_t **tokens) +{ + struct gssapi_ph1_state *gps; + int len, i; + vchar_t *toks; + char *p; + + gps = gssapi_get_state(iph1); + if (gps == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "gssapi not yet initialized?\n"); + return -1; + } + + for (i = len = 0; i < gps->gsscnt; i++) + len += gps->gss[i].length; + + toks = vmalloc(len); + if (toks == 0) + return -1; + p = (char *)toks->v; + for (i = 0; i < gps->gsscnt; i++) { + memcpy(p, gps->gss[i].value, gps->gss[i].length); + p += gps->gss[i].length; + } + + *tokens = toks; + + plog(LLV_DEBUG, LOCATION, NULL, + "%d itokens of length %d\n", gps->gsscnt, (*tokens)->l); + + return 0; +} + +int +gssapi_get_rtokens(struct ph1handle *iph1, vchar_t **tokens) +{ + struct gssapi_ph1_state *gps; + int len, i; + vchar_t *toks; + char *p; + + gps = gssapi_get_state(iph1); + if (gps == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "gssapi not yet initialized?\n"); + return -1; + } + + if (gssapi_more_tokens(iph1)) { + plog(LLV_ERROR, LOCATION, NULL, + "gssapi roundtrips not complete\n"); + return -1; + } + + for (i = len = 0; i < gps->gsscnt_p; i++) + len += gps->gss_p[i].length; + + toks = vmalloc(len); + if (toks == 0) + return -1; + p = (char *)toks->v; + for (i = 0; i < gps->gsscnt_p; i++) { + memcpy(p, gps->gss_p[i].value, gps->gss_p[i].length); + p += gps->gss_p[i].length; + } + + *tokens = toks; + + return 0; +} + +vchar_t * +gssapi_wraphash(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + OM_uint32 maj_stat, min_stat; + gss_buffer_desc hash_in_buf, hash_out_buf; + gss_buffer_t hash_in = &hash_in_buf, hash_out = &hash_out_buf; + vchar_t *outbuf; + + gps = gssapi_get_state(iph1); + if (gps == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "gssapi not yet initialized?\n"); + return NULL; + } + + if (gssapi_more_tokens(iph1)) { + plog(LLV_ERROR, LOCATION, NULL, + "gssapi roundtrips not complete\n"); + return NULL; + } + + if (gssapi_vm2gssbuf(iph1->hash, hash_in) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "vm2gssbuf failed\n"); + return NULL; + } + + maj_stat = gss_wrap(&min_stat, gps->gss_context, 1, GSS_C_QOP_DEFAULT, + hash_in, NULL, hash_out); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "wrapping hash value\n"); + maj_stat = gss_release_buffer(&min_stat, hash_in); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release hash_in buffer\n"); + return NULL; + } + + plog(LLV_DEBUG, LOCATION, NULL, "wrapped HASH, ilen %d olen %d\n", + hash_in->length, hash_out->length); + + maj_stat = gss_release_buffer(&min_stat, hash_in); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release hash_in buffer\n"); + + if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n"); + maj_stat = gss_release_buffer(&min_stat, hash_out); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release hash_out buffer\n"); + return NULL; + } + maj_stat = gss_release_buffer(&min_stat, hash_out); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release hash_out buffer\n"); + + return outbuf; +} + +vchar_t * +gssapi_unwraphash(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + OM_uint32 maj_stat, min_stat; + gss_buffer_desc hashbuf, hash_outbuf; + gss_buffer_t hash_in = &hashbuf, hash_out = &hash_outbuf; + vchar_t *outbuf; + + gps = gssapi_get_state(iph1); + if (gps == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "gssapi not yet initialized?\n"); + return NULL; + } + + + hashbuf.length = ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash); + hashbuf.value = (char *)(iph1->pl_hash + 1); + + plog(LLV_DEBUG, LOCATION, NULL, "unwrapping HASH of len %d\n", + hashbuf.length); + + maj_stat = gss_unwrap(&min_stat, gps->gss_context, hash_in, hash_out, + NULL, NULL); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "unwrapping hash value\n"); + return NULL; + } + + if (gssapi_gss2vmbuf(hash_out, &outbuf) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n"); + maj_stat = gss_release_buffer(&min_stat, hash_out); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release hash_out buffer\n"); + return NULL; + } + maj_stat = gss_release_buffer(&min_stat, hash_out); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release hash_out buffer\n"); + + return outbuf; +} + +void +gssapi_set_id_sent(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + + gps = gssapi_get_state(iph1); + + gps->gss_flags |= GSSFLAG_ID_SENT; +} + +int +gssapi_id_sent(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + + gps = gssapi_get_state(iph1); + + return (gps->gss_flags & GSSFLAG_ID_SENT) != 0; +} + +void +gssapi_set_id_rcvd(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + + gps = gssapi_get_state(iph1); + + gps->gss_flags |= GSSFLAG_ID_RCVD; +} + +int +gssapi_id_rcvd(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + + gps = gssapi_get_state(iph1); + + return (gps->gss_flags & GSSFLAG_ID_RCVD) != 0; +} + +void +gssapi_free_state(struct ph1handle *iph1) +{ + struct gssapi_ph1_state *gps; + OM_uint32 maj_stat, min_stat; + + gps = gssapi_get_state(iph1); + + if (gps == NULL) + return; + + gssapi_set_state(iph1, NULL); + + if (gps->gss_cred != GSS_C_NO_CREDENTIAL) { + maj_stat = gss_release_cred(&min_stat, &gps->gss_cred); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "releasing credentials\n"); + } + racoon_free(gps); +} + +vchar_t * +gssapi_get_default_id(struct ph1handle *iph1) +{ + gss_buffer_desc id_buffer; + gss_buffer_t id = &id_buffer; + gss_name_t defname, canon_name; + OM_uint32 min_stat, maj_stat; + vchar_t *vmbuf; + + if (gssapi_get_default_name(iph1, 0, &defname) < 0) + return NULL; + + maj_stat = gss_canonicalize_name(&min_stat, defname, GSS_C_NO_OID, + &canon_name); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "canonicalize name\n"); + maj_stat = gss_release_name(&min_stat, &defname); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release default name\n"); + return NULL; + } + maj_stat = gss_release_name(&min_stat, &defname); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release default name\n"); + + maj_stat = gss_export_name(&min_stat, canon_name, id); + if (GSS_ERROR(maj_stat)) { + gssapi_error(min_stat, LOCATION, "export name\n"); + maj_stat = gss_release_name(&min_stat, &canon_name); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, + "release canonical name\n"); + return NULL; + } + maj_stat = gss_release_name(&min_stat, &canon_name); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release canonical name\n"); + + plog(LLV_DEBUG, LOCATION, NULL, "will try to acquire '%*s' creds\n", + id->length, id->value); + + if (gssapi_gss2vmbuf(id, &vmbuf) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "gss2vmbuf failed\n"); + maj_stat = gss_release_buffer(&min_stat, id); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release id buffer\n"); + return NULL; + } + maj_stat = gss_release_buffer(&min_stat, id); + if (GSS_ERROR(maj_stat)) + gssapi_error(min_stat, LOCATION, "release id buffer\n"); + + return vmbuf; +} +#else +int __gssapi_dUmMy; +#endif diff --git a/racoon.tproj/gssapi.h b/racoon.tproj/gssapi.h new file mode 100644 index 0000000..bbdb186 --- /dev/null +++ b/racoon.tproj/gssapi.h @@ -0,0 +1,88 @@ +/* $KAME: gssapi.h,v 1.3 2001/01/29 17:37:52 thorpej Exp $ */ + +/* + * Copyright 2000 Wasabi Systems, Inc. + * All rights reserved. + * + * This software was written by Frank van der Linden of Wasabi Systems + * for Zembu Labs, Inc. http://www.zembu.com/ + * + * 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 Wasabi Systems for + * Zembu Labs, Inc. http://www.zembu.com/ + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC + * 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. + */ + +#include + +#define GSSAPI_DEF_NAME "ike" + +struct ph1handle; +struct isakmpsa; + +struct gssapi_ph1_state { + int gsscnt; /* # of token we're working on */ + int gsscnt_p; /* # of token we're working on */ + + gss_buffer_desc gss[3]; /* gss-api tokens. */ + /* NOTE: XXX this restricts the max # */ + /* to 3. More should never happen */ + + gss_buffer_desc gss_p[3]; + + gss_ctx_id_t gss_context; /* context for gss_init_sec_context */ + + OM_uint32 gss_status; /* retval from gss_init_sec_context */ + gss_cred_id_t gss_cred; /* acquired credentials */ + + int gss_flags; +#define GSSFLAG_ID_SENT 0x0001 +#define GSSFLAG_ID_RCVD 0x0001 +}; + +#define gssapi_get_state(ph) \ + ((struct gssapi_ph1_state *)((ph)->gssapi_state)) + +#define gssapi_set_state(ph, st) \ + (ph)->gssapi_state = (st) + +#define gssapi_more_tokens(ph) \ + ((gssapi_get_state(ph)->gss_status & GSS_S_CONTINUE_NEEDED) != 0) + +int gssapi_get_itoken __P((struct ph1handle *, int *)); +int gssapi_get_rtoken __P((struct ph1handle *, int *)); +int gssapi_save_received_token __P((struct ph1handle *, vchar_t *)); +int gssapi_get_token_to_send __P((struct ph1handle *, vchar_t **)); +int gssapi_get_itokens __P((struct ph1handle *, vchar_t **)); +int gssapi_get_rtokens __P((struct ph1handle *, vchar_t **)); +vchar_t *gssapi_wraphash __P((struct ph1handle *)); +vchar_t *gssapi_unwraphash __P((struct ph1handle *)); +void gssapi_set_id_sent __P((struct ph1handle *)); +int gssapi_id_sent __P((struct ph1handle *)); +void gssapi_set_id_rcvd __P((struct ph1handle *)); +int gssapi_id_rcvd __P((struct ph1handle *)); +void gssapi_free_state __P((struct ph1handle *)); +vchar_t *gssapi_get_default_id __P((struct ph1handle *)); diff --git a/racoon.tproj/handler.c b/racoon.tproj/handler.c new file mode 100644 index 0000000..1ca5b5c --- /dev/null +++ b/racoon.tproj/handler.c @@ -0,0 +1,869 @@ +/* $KAME: handler.c,v 1.56 2002/01/02 09:05:25 jinmei 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. 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. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "grabmyaddr.h" +#include "algorithm.h" +#include "crypto_openssl.h" +#include "policy.h" +#include "proposal.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_inf.h" +#include "oakley.h" +#include "remoteconf.h" +#include "localconf.h" +#include "handler.h" +#include "gcmalloc.h" + +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif + +static LIST_HEAD(_ph1tree_, ph1handle) ph1tree; +static LIST_HEAD(_ph2tree_, ph2handle) ph2tree; +static LIST_HEAD(_ctdtree_, contacted) ctdtree; +static LIST_HEAD(_rcptree_, recvdpkt) rcptree; + +static void del_recvdpkt __P((struct recvdpkt *)); +static void rem_recvdpkt __P((struct recvdpkt *)); +static void sweep_recvdpkt __P((void *)); + +/* + * functions about management of the isakmp status table + */ +/* %%% management phase 1 handler */ +/* + * search for isakmpsa handler with isakmp index. + */ + +extern caddr_t val2str(const char *, size_t); + +struct ph1handle * +getph1byindex(index) + isakmp_index *index; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (memcmp(&p->index, index, sizeof(*index)) == 0) + return p; + } + + return NULL; +} + +/* + * search for isakmp handler by i_ck in index. + */ +struct ph1handle * +getph1byindex0(index) + isakmp_index *index; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (memcmp(&p->index, index, sizeof(cookie_t)) == 0) + return p; + } + + return NULL; +} + +/* + * search for isakmpsa handler by remote address. + * don't use port number to search because this function search + * with phase 2's destinaion. + */ +struct ph1handle * +getph1byaddr(local, remote) + struct sockaddr *local, *remote; +{ + struct ph1handle *p; + + LIST_FOREACH(p, &ph1tree, chain) { + if (p->status == PHASE1ST_EXPIRED) + continue; + if (cmpsaddrwop(local, p->local) == 0 + && cmpsaddrwop(remote, p->remote) == 0) + return p; + } + + return NULL; +} + +/* + * dump isakmp-sa + */ +vchar_t * +dumpph1() +{ + struct ph1handle *iph1; + struct ph1dump *pd; + int cnt = 0; + vchar_t *buf; + + /* get length of buffer */ + LIST_FOREACH(iph1, &ph1tree, chain) + cnt++; + + buf = vmalloc(cnt * sizeof(struct ph1dump)); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer\n"); + return NULL; + } + pd = (struct ph1dump *)buf->v; + + LIST_FOREACH(iph1, &ph1tree, chain) { + memcpy(&pd->index, &iph1->index, sizeof(iph1->index)); + pd->status = iph1->status; + pd->side = iph1->side; + memcpy(&pd->remote, iph1->remote, iph1->remote->sa_len); + memcpy(&pd->local, iph1->local, iph1->local->sa_len); + pd->version = iph1->version; + pd->etype = iph1->etype; + pd->created = iph1->created; + pd->ph2cnt = iph1->ph2cnt; + pd++; + } + + return buf; +} + +/* + * create new isakmp Phase 1 status record to handle isakmp in Phase1 + */ +struct ph1handle * +newph1() +{ + struct ph1handle *iph1; + + /* create new iph1 */ + iph1 = racoon_calloc(1, sizeof(*iph1)); + if (iph1 == NULL) + return NULL; + + iph1->status = PHASE1ST_SPAWN; + + return iph1; +} + +/* + * delete new isakmp Phase 1 status record to handle isakmp in Phase1 + */ +void +delph1(iph1) + struct ph1handle *iph1; +{ + if (iph1->remote) { + racoon_free(iph1->remote); + iph1->remote = NULL; + } + if (iph1->local) { + racoon_free(iph1->local); + iph1->local = NULL; + } + + VPTRINIT(iph1->authstr); + + sched_scrub_param(iph1); + iph1->sce = NULL; + iph1->scr = NULL; + + VPTRINIT(iph1->sendbuf); + + VPTRINIT(iph1->dhpriv); + VPTRINIT(iph1->dhpub); + VPTRINIT(iph1->dhpub_p); + VPTRINIT(iph1->dhgxy); + VPTRINIT(iph1->nonce); + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->skeyid); + VPTRINIT(iph1->skeyid_d); + VPTRINIT(iph1->skeyid_a); + VPTRINIT(iph1->skeyid_e); + VPTRINIT(iph1->key); + VPTRINIT(iph1->hash); + VPTRINIT(iph1->sig); + VPTRINIT(iph1->sig_p); + oakley_delcert(iph1->cert); + iph1->cert = NULL; + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + oakley_delcert(iph1->cr_p); + iph1->cr_p = NULL; + VPTRINIT(iph1->id); + VPTRINIT(iph1->id_p); + + if (iph1->ivm) { + oakley_delivm(iph1->ivm); + iph1->ivm = NULL; + } + + VPTRINIT(iph1->sa); + VPTRINIT(iph1->sa_ret); + +#ifdef HAVE_GSSAPI + VPTRINIT(iph1->gi_i); + VPTRINIT(iph1->gi_r); + + gssapi_free_state(iph1); +#endif + + racoon_free(iph1); +} + +/* + * create new isakmp Phase 1 status record to handle isakmp in Phase1 + */ +int +insph1(iph1) + struct ph1handle *iph1; +{ + /* validity check */ + if (iph1->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid isakmp SA handler. no remote address.\n"); + return -1; + } + LIST_INSERT_HEAD(&ph1tree, iph1, chain); + + return 0; +} + +void +remph1(iph1) + struct ph1handle *iph1; +{ + LIST_REMOVE(iph1, chain); +} + +/* + * flush isakmp-sa + */ +void +flushph1() +{ + struct ph1handle *p, *next; + + for (p = LIST_FIRST(&ph1tree); p; p = next) { + next = LIST_NEXT(p, chain); + + /* send delete information */ + if (p->status == PHASE1ST_ESTABLISHED) + isakmp_info_send_d1(p); + + remph1(p); + delph1(p); + } +} + +void +initph1tree() +{ + LIST_INIT(&ph1tree); +} + +/* %%% management phase 2 handler */ +/* + * search ph2handle with policy id. + */ +struct ph2handle * +getph2byspid(spid) + u_int32_t spid; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + /* + * there are ph2handle independent on policy + * such like informational exchange. + */ + if (p->spid == spid) + return p; + } + + return NULL; +} + +/* + * search ph2handle with sequence number. + */ +struct ph2handle * +getph2byseq(seq) + u_int32_t seq; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + if (p->seq == seq) + return p; + } + + return NULL; +} + +/* + * search ph2handle with message id. + */ +struct ph2handle * +getph2bymsgid(iph1, msgid) + struct ph1handle *iph1; + u_int32_t msgid; +{ + struct ph2handle *p; + + LIST_FOREACH(p, &ph2tree, chain) { + if (p->msgid == msgid) + return p; + } + + return NULL; +} + +/* + * call by pk_recvexpire(). + */ +struct ph2handle * +getph2bysaidx(src, dst, proto_id, spi) + struct sockaddr *src, *dst; + u_int proto_id; + u_int32_t spi; +{ + struct ph2handle *iph2; + struct saproto *pr; + + LIST_FOREACH(iph2, &ph2tree, chain) { + if (iph2->proposal == NULL && iph2->approval == NULL) + continue; + if (iph2->approval != NULL) { + for (pr = iph2->approval->head; pr != NULL; + pr = pr->next) { + if (proto_id != pr->proto_id) + break; + if (spi == pr->spi || spi == pr->spi_p) + return iph2; + } + } else if (iph2->proposal != NULL) { + for (pr = iph2->proposal->head; pr != NULL; + pr = pr->next) { + if (proto_id != pr->proto_id) + break; + if (spi == pr->spi) + return iph2; + } + } + } + + return NULL; +} + +/* + * create new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +struct ph2handle * +newph2() +{ + struct ph2handle *iph2 = NULL; + + /* create new iph2 */ + iph2 = racoon_calloc(1, sizeof(*iph2)); + if (iph2 == NULL) + return NULL; + + iph2->status = PHASE1ST_SPAWN; + + return iph2; +} + +/* + * initialize ph2handle + * NOTE: don't initialize src/dst. + * SPI in the proposal is cleared. + */ +void +initph2(iph2) + struct ph2handle *iph2; +{ + sched_scrub_param(iph2); + iph2->sce = NULL; + iph2->scr = NULL; + + VPTRINIT(iph2->sendbuf); + VPTRINIT(iph2->msg1); + + /* clear spi, keep variables in the proposal */ + if (iph2->proposal) { + struct saproto *pr; + for (pr = iph2->proposal->head; pr != NULL; pr = pr->next) + pr->spi = 0; + } + + /* clear approval */ + if (iph2->approval) { + flushsaprop(iph2->approval); + iph2->approval = NULL; + } + + /* clear the generated policy */ + if (iph2->spidx_gen) { + delsp_bothdir((struct policyindex *)iph2->spidx_gen); + racoon_free(iph2->spidx_gen); + iph2->spidx_gen = NULL; + } + + if (iph2->pfsgrp) { + oakley_dhgrp_free(iph2->pfsgrp); + iph2->pfsgrp = NULL; + } + + VPTRINIT(iph2->dhpriv); + VPTRINIT(iph2->dhpub); + VPTRINIT(iph2->dhpub_p); + VPTRINIT(iph2->dhgxy); + VPTRINIT(iph2->id); + VPTRINIT(iph2->id_p); + VPTRINIT(iph2->nonce); + VPTRINIT(iph2->nonce_p); + VPTRINIT(iph2->sa); + VPTRINIT(iph2->sa_ret); + + if (iph2->ivm) { + oakley_delivm(iph2->ivm); + iph2->ivm = NULL; + } +} + +/* + * delete new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +void +delph2(iph2) + struct ph2handle *iph2; +{ + initph2(iph2); + + if (iph2->src) { + racoon_free(iph2->src); + iph2->src = NULL; + } + if (iph2->dst) { + racoon_free(iph2->dst); + iph2->dst = NULL; + } + if (iph2->src_id) { + racoon_free(iph2->src_id); + iph2->src_id = NULL; + } + if (iph2->dst_id) { + racoon_free(iph2->dst_id); + iph2->dst_id = NULL; + } + + if (iph2->proposal) { + flushsaprop(iph2->proposal); + iph2->proposal = NULL; + } + + racoon_free(iph2); +} + +/* + * create new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +int +insph2(iph2) + struct ph2handle *iph2; +{ + LIST_INSERT_HEAD(&ph2tree, iph2, chain); + + return 0; +} + +void +remph2(iph2) + struct ph2handle *iph2; +{ + LIST_REMOVE(iph2, chain); +} + +void +initph2tree() +{ + LIST_INIT(&ph2tree); +} + +void +flushph2() +{ + struct ph2handle *p, *next; + + for (p = LIST_FIRST(&ph2tree); p; p = next) { + next = LIST_NEXT(p, chain); + + /* send delete information */ + if (p->status == PHASE2ST_ESTABLISHED) + isakmp_info_send_d2(p); + + unbindph12(p); + remph2(p); + delph2(p); + } +} + +/* + * Delete all Phase 2 handlers for this src/dst/proto. This + * is used during INITIAL-CONTACT processing (so no need to + * send a message to the peer). + */ +void +deleteallph2(src, dst, proto_id) + struct sockaddr *src, *dst; + u_int proto_id; +{ + struct ph2handle *iph2, *next; + struct saproto *pr; + + for (iph2 = LIST_FIRST(&ph2tree); iph2 != NULL; iph2 = next) { + next = LIST_NEXT(iph2, chain); + if (iph2->proposal == NULL && iph2->approval == NULL) + continue; + if (iph2->approval != NULL) { + for (pr = iph2->approval->head; pr != NULL; + pr = pr->next) { + if (proto_id == pr->proto_id) + goto zap_it; + } + } else if (iph2->proposal != NULL) { + for (pr = iph2->proposal->head; pr != NULL; + pr = pr->next) { + if (proto_id == pr->proto_id) + goto zap_it; + } + } + continue; + zap_it: + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } +} + +/* %%% */ +void +bindph12(iph1, iph2) + struct ph1handle *iph1; + struct ph2handle *iph2; +{ + iph2->ph1 = iph1; + LIST_INSERT_HEAD(&iph1->ph2tree, iph2, ph1bind); +} + +void +unbindph12(iph2) + struct ph2handle *iph2; +{ + if (iph2->ph1 != NULL) { + iph2->ph1 = NULL; + LIST_REMOVE(iph2, ph1bind); + } +} + +/* %%% management contacted list */ +/* + * search contacted list. + */ +struct contacted * +getcontacted(remote) + struct sockaddr *remote; +{ + struct contacted *p; + + LIST_FOREACH(p, &ctdtree, chain) { + if (cmpsaddrstrict(remote, p->remote) == 0) + return p; + } + + return NULL; +} + +/* + * create new isakmp Phase 2 status record to handle isakmp in Phase2 + */ +int +inscontacted(remote) + struct sockaddr *remote; +{ + struct contacted *new; + + /* create new iph2 */ + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return -1; + + new->remote = dupsaddr(remote); + + LIST_INSERT_HEAD(&ctdtree, new, chain); + + return 0; +} + +void +initctdtree() +{ + LIST_INIT(&ctdtree); +} + +/* + * check the response has been sent to the peer. when not, simply reply + * the buffered packet to the peer. + * OUT: + * 0: the packet is received at the first time. + * 1: the packet was processed before. + * 2: the packet was processed before, but the address mismatches. + * -1: error happened. + */ +int +check_recvdpkt(remote, local, rbuf) + struct sockaddr *remote, *local; + vchar_t *rbuf; +{ + vchar_t *hash; + struct recvdpkt *r; + time_t t; + int len, s; + + /* set current time */ + t = time(NULL); + + hash = eay_md5_one(rbuf); + if (!hash) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + return -1; + } + + LIST_FOREACH(r, &rcptree, chain) { + if (memcmp(hash->v, r->hash->v, r->hash->l) == 0) + break; + } + vfree(hash); + + /* this is the first time to receive the packet */ + if (r == NULL) + return 0; + + /* + * the packet was processed before, but the remote address mismatches. + */ + if (cmpsaddrstrict(remote, r->remote) != 0) + return 2; + + /* + * it should not check the local address because the packet + * may arrive at other interface. + */ + + /* check the previous time to send */ + if (t - r->time_send < 1) { + plog(LLV_WARNING, LOCATION, NULL, + "the packet retransmitted in a short time from %s\n", + saddr2str(remote)); + /*XXX should it be error ? */ + } + + /* select the socket to be sent */ + s = getsockmyaddr(r->local); + if (s == -1) + return -1; + + /* resend the packet if needed */ + len = sendfromto(s, r->sendbuf->v, r->sendbuf->l, + r->local, r->remote, lcconf->count_persend); + if (len == -1) { + plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n"); + return -1; + } + + /* check the retry counter */ + r->retry_counter--; + if (r->retry_counter <= 0) { + rem_recvdpkt(r); + del_recvdpkt(r); + plog(LLV_DEBUG, LOCATION, NULL, + "deleted the retransmission packet to %s.\n", + saddr2str(remote)); + } else + r->time_send = t; + + return 1; +} + +/* + * adding a hash of received packet into the received list. + */ +int +add_recvdpkt(remote, local, sbuf, rbuf) + struct sockaddr *remote, *local; + vchar_t *sbuf, *rbuf; +{ + struct recvdpkt *new = NULL; + + if (lcconf->retry_counter == 0) { + /* no need to add it */ + return 0; + } + + new = racoon_calloc(1, sizeof(*new)); + if (!new) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + return -1; + } + + new->hash = eay_md5_one(rbuf); + if (!new->hash) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + new->remote = dupsaddr(remote); + if (new->remote == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + new->local = dupsaddr(local); + if (new->local == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + new->sendbuf = vdup(sbuf); + if (new->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + del_recvdpkt(new); + return -1; + } + + new->retry_counter = lcconf->retry_counter; + new->time_send = 0; + new->created = time(NULL); + + LIST_INSERT_HEAD(&rcptree, new, chain); + + return 0; +} + +void +del_recvdpkt(r) + struct recvdpkt *r; +{ + if (r->remote) + racoon_free(r->remote); + if (r->local) + racoon_free(r->local); + if (r->hash) + vfree(r->hash); + if (r->sendbuf) + vfree(r->sendbuf); + racoon_free(r); +} + +void +rem_recvdpkt(r) + struct recvdpkt *r; +{ + LIST_REMOVE(r, chain); +} + +void +sweep_recvdpkt(dummy) + void *dummy; +{ + struct recvdpkt *r, *next; + time_t t, lt; + + /* set current time */ + t = time(NULL); + + /* set the lifetime of the retransmission */ + lt = lcconf->retry_counter * lcconf->retry_interval; + + for (r = LIST_FIRST(&rcptree); r; r = next) { + next = LIST_NEXT(r, chain); + + if (t - r->created > lt) { + rem_recvdpkt(r); + del_recvdpkt(r); + } + } + + sched_new(lt, sweep_recvdpkt, NULL); +} + +void +init_recvdpkt() +{ + time_t lt = lcconf->retry_counter * lcconf->retry_interval; + + LIST_INIT(&rcptree); + + sched_new(lt, sweep_recvdpkt, NULL); +} diff --git a/racoon.tproj/handler.h b/racoon.tproj/handler.h new file mode 100644 index 0000000..484376b --- /dev/null +++ b/racoon.tproj/handler.h @@ -0,0 +1,422 @@ +/* $KAME: handler.h,v 1.42 2001/12/12 15:29:13 sakane 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. 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. + */ + +/* Phase 1 handler */ +/* + * main mode: + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 (---) 1st valid msg received + * 3 1st msg sent 1st msg sent + * 4 1st valid msg received 2st valid msg received + * 5 2nd msg sent 2nd msg sent + * 6 2nd valid msg received 3rd valid msg received + * 7 3rd msg sent 3rd msg sent + * 8 3rd valid msg received (---) + * 9 SA established SA established + * + * aggressive mode: + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 (---) 1st valid msg received + * 3 1st msg sent 1st msg sent + * 4 1st valid msg received 2st valid msg received + * 5 (---) (---) + * 6 (---) (---) + * 7 (---) (---) + * 8 (---) (---) + * 9 SA established SA established + * + * base mode: + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 (---) 1st valid msg received + * 3 1st msg sent 1st msg sent + * 4 1st valid msg received 2st valid msg received + * 5 2nd msg sent (---) + * 6 (---) (---) + * 7 (---) (---) + * 8 (---) (---) + * 9 SA established SA established + */ +#define PHASE1ST_SPAWN 0 +#define PHASE1ST_START 1 +#define PHASE1ST_MSG1RECEIVED 2 +#define PHASE1ST_MSG1SENT 3 +#define PHASE1ST_MSG2RECEIVED 4 +#define PHASE1ST_MSG2SENT 5 +#define PHASE1ST_MSG3RECEIVED 6 +#define PHASE1ST_MSG3SENT 7 +#define PHASE1ST_MSG4RECEIVED 8 +#define PHASE1ST_ESTABLISHED 9 +#define PHASE1ST_EXPIRED 10 +#define PHASE1ST_MAX 11 + +/* About address semantics in each case. + * initiator(addr=I) responder(addr=R) + * src dst src dst + * (local) (remote) (local) (remote) + * phase 1 handler I R R I + * phase 2 handler I R R I + * getspi msg R I I R + * aquire msg I R + * ID payload I R I R + */ +struct ph1handle { + isakmp_index index; + + int status; /* status of this SA */ + int side; /* INITIATOR or RESPONDER */ + + struct sockaddr *remote; /* remote address to negosiate ph1 */ + struct sockaddr *local; /* local address to negosiate ph1 */ + /* XXX copy from rmconf due to anonymous configuration. + * If anonymous will be forbidden, we do delete them. */ + + struct remoteconf *rmconf; /* pointer to remote configuration */ + + struct isakmpsa *approval; /* pointer to SA(s) approved. */ + vchar_t *authstr; /* place holder of string for auth. */ + /* for example pre-shared key */ + + u_int8_t version; /* ISAKMP version */ + u_int8_t etype; /* Exchange type actually for use */ + u_int8_t flags; /* Flags */ + u_int32_t msgid; /* message id */ + + struct sched *sce; /* schedule for expire */ + + struct sched *scr; /* schedule for resend */ + int retry_counter; /* for resend. */ + vchar_t *sendbuf; /* buffer for re-sending */ + + vchar_t *dhpriv; /* DH; private value */ + vchar_t *dhpub; /* DH; public value */ + vchar_t *dhpub_p; /* DH; partner's public value */ + vchar_t *dhgxy; /* DH; shared secret */ + vchar_t *nonce; /* nonce value */ + vchar_t *nonce_p; /* partner's nonce value */ + vchar_t *skeyid; /* SKEYID */ + vchar_t *skeyid_d; /* SKEYID_d */ + vchar_t *skeyid_a; /* SKEYID_a, i.e. hash */ + vchar_t *skeyid_e; /* SKEYID_e, i.e. encryption */ + vchar_t *key; /* cipher key */ + vchar_t *hash; /* HASH minus general header */ + vchar_t *sig; /* SIG minus general header */ + vchar_t *sig_p; /* peer's SIG minus general header */ + cert_t *cert; /* CERT minus general header */ + cert_t *cert_p; /* peer's CERT minus general header */ + cert_t *crl_p; /* peer's CRL minus general header */ + cert_t *cr_p; /* peer's CR not including general */ + vchar_t *id; /* ID minus gen header */ + vchar_t *id_p; /* partner's ID minus general header */ + /* i.e. strut ipsecdoi_id_b*. */ + struct isakmp_ivm *ivm; /* IVs */ + + vchar_t *sa; /* whole SA payload to send/to be sent*/ + /* to calculate HASH */ + /* NOT INCLUDING general header. */ + + vchar_t *sa_ret; /* SA payload to reply/to be replyed */ + /* NOT INCLUDING general header. */ + /* NOTE: Should be release after use. */ + +#ifdef HAVE_GSSAPI + void *gssapi_state; /* GSS-API specific state. */ + /* Allocated when needed */ + vchar_t *gi_i; /* optional initiator GSS id */ + vchar_t *gi_r; /* optional responder GSS id */ +#endif + + struct isakmp_pl_hash *pl_hash; /* pointer to hash payload */ + + time_t created; /* timestamp for establish */ +#ifdef ENABLE_STATS + struct timeval start; + struct timeval end; +#endif + + u_int32_t msgid2; /* msgid counter for Phase 2 */ + int ph2cnt; /* the number which is negotiated by this phase 1 */ + LIST_HEAD(_ph2ofph1_, ph2handle) ph2tree; + + LIST_ENTRY(ph1handle) chain; +}; + +/* Phase 2 handler */ +/* allocated per a SA or SA bundles of a pair of peer's IP addresses. */ +/* + * initiator responder + * 0 (---) (---) + * 1 start start (1st msg received) + * 2 acquire msg get 1st valid msg received + * 3 getspi request sent getspi request sent + * 4 getspi done getspi done + * 5 1st msg sent 1st msg sent + * 6 1st valid msg received 2nd valid msg received + * 7 (commit bit) (commit bit) + * 8 SAs added SAs added + * 9 SAs established SAs established + * 10 SAs expired SAs expired + */ +#define PHASE2ST_SPAWN 0 +#define PHASE2ST_START 1 +#define PHASE2ST_STATUS2 2 +#define PHASE2ST_GETSPISENT 3 +#define PHASE2ST_GETSPIDONE 4 +#define PHASE2ST_MSG1SENT 5 +#define PHASE2ST_STATUS6 6 +#define PHASE2ST_COMMIT 7 +#define PHASE2ST_ADDSA 8 +#define PHASE2ST_ESTABLISHED 9 +#define PHASE2ST_EXPIRED 10 +#define PHASE2ST_MAX 11 + +struct ph2handle { + struct sockaddr *src; /* my address of SA. */ + struct sockaddr *dst; /* peer's address of SA. */ + + /* + * copy ip address from ID payloads when ID type is ip address. + * In other case, they must be null. + */ + struct sockaddr *src_id; + struct sockaddr *dst_id; + + u_int32_t spid; /* policy id by kernel */ + + int status; /* ipsec sa status */ + u_int8_t side; /* INITIATOR or RESPONDER */ + + struct sched *sce; /* schedule for expire */ + struct sched *scr; /* schedule for resend */ + int retry_counter; /* for resend. */ + vchar_t *sendbuf; /* buffer for re-sending */ + vchar_t *msg1; /* buffer for re-sending */ + /* used for responder's first message */ + + int retry_checkph1; /* counter to wait phase 1 finished. */ + /* NOTE: actually it's timer. */ + + u_int32_t seq; /* sequence number used by PF_KEY */ + /* + * NOTE: In responder side, we can't identify each SAs + * with same destination address for example, when + * socket based SA is required. So we set a identifier + * number to "seq", and sent kernel by pfkey. + */ + u_int8_t satype; /* satype in PF_KEY */ + /* + * saved satype in the original PF_KEY request from + * the kernel in order to reply a error. + */ + + u_int8_t flags; /* Flags for phase 2 */ + u_int32_t msgid; /* msgid for phase 2 */ + + struct sainfo *sainfo; /* place holder of sainfo */ + struct saprop *proposal; /* SA(s) proposal. */ + struct saprop *approval; /* SA(s) approved. */ + caddr_t spidx_gen; /* policy from peer's proposal */ + + struct dhgroup *pfsgrp; /* DH; prime number */ + vchar_t *dhpriv; /* DH; private value */ + vchar_t *dhpub; /* DH; public value */ + vchar_t *dhpub_p; /* DH; partner's public value */ + vchar_t *dhgxy; /* DH; shared secret */ + vchar_t *id; /* ID minus gen header */ + vchar_t *id_p; /* peer's ID minus general header */ + vchar_t *nonce; /* nonce value in phase 2 */ + vchar_t *nonce_p; /* partner's nonce value in phase 2 */ + + vchar_t *sa; /* whole SA payload to send/to be sent*/ + /* to calculate HASH */ + /* NOT INCLUDING general header. */ + + vchar_t *sa_ret; /* SA payload to reply/to be replyed */ + /* NOT INCLUDING general header. */ + /* NOTE: Should be release after use. */ + + struct isakmp_ivm *ivm; /* IVs */ + +#ifdef ENABLE_STATS + struct timeval start; + struct timeval end; +#endif + struct ph1handle *ph1; /* back pointer to isakmp status */ + + LIST_ENTRY(ph2handle) chain; + LIST_ENTRY(ph2handle) ph1bind; /* chain to ph1handle */ +}; + +/* + * for handling initial contact. + */ +struct contacted { + struct sockaddr *remote; /* remote address to negosiate ph1 */ + LIST_ENTRY(contacted) chain; +}; + +/* + * for checking a packet retransmited. + */ +struct recvdpkt { + struct sockaddr *remote; /* the remote address */ + struct sockaddr *local; /* the local address */ + vchar_t *hash; /* hash of the received packet */ + vchar_t *sendbuf; /* buffer for the response */ + int retry_counter; /* how many times to send */ + time_t time_send; /* timestamp to send a packet */ + time_t created; /* timestamp to create a queue */ + + struct sched *scr; /* schedule for resend, may not used */ + + LIST_ENTRY(recvdpkt) chain; +}; + +/* for parsing ISAKMP header. */ +struct isakmp_parse_t { + u_char type; /* payload type of mine */ + int len; /* ntohs(ptr->len) */ + struct isakmp_gen *ptr; +}; + +/* + * for IV management. + * + * - normal case + * initiator responder + * ------------------------- -------------------------- + * initialize iv(A), ive(A). initialize iv(A), ive(A). + * encode by ive(A). + * save to iv(B). ---[packet(B)]--> save to ive(B). + * decode by iv(A). + * packet consistency. + * sync iv(B) with ive(B). + * check auth, integrity. + * encode by ive(B). + * save to ive(C). <--[packet(C)]--- save to iv(C). + * decoded by iv(B). + * : + * + * - In the case that a error is found while cipher processing, + * initiator responder + * ------------------------- -------------------------- + * initialize iv(A), ive(A). initialize iv(A), ive(A). + * encode by ive(A). + * save to iv(B). ---[packet(B)]--> save to ive(B). + * decode by iv(A). + * packet consistency. + * sync iv(B) with ive(B). + * check auth, integrity. + * error found. + * create notify. + * get ive2(X) from iv(B). + * encode by ive2(X). + * get iv2(X) from iv(B). <--[packet(Y)]--- save to iv2(Y). + * save to ive2(Y). + * decoded by iv2(X). + * : + * + * The reason why the responder synchronizes iv with ive after checking the + * packet consistency is that it is required to leave the IV for decoding + * packet. Because there is a potential of error while checking the packet + * consistency. Also the reason why that is before authentication and + * integirty check is that the IV for informational exchange has to be made + * by the IV which is after packet decoded and checking the packet consistency. + * Otherwise IV mismatched happens between the intitiator and the responder. + */ +struct isakmp_ivm { + vchar_t *iv; /* for decoding packet */ + /* if phase 1, it's for computing phase2 iv */ + vchar_t *ive; /* for encoding packet */ +}; + +/* for dumping */ +struct ph1dump { + isakmp_index index; + int status; + int side; + struct sockaddr_storage remote; + struct sockaddr_storage local; + u_int8_t version; + u_int8_t etype; + time_t created; + int ph2cnt; +}; + +struct sockaddr; +struct ph1handle; +struct ph2handle; +struct policyindex; + +extern struct ph1handle *getph1byindex __P((isakmp_index *)); +extern struct ph1handle *getph1byindex0 __P((isakmp_index *)); +extern struct ph1handle *getph1byaddr __P((struct sockaddr *, + struct sockaddr *)); +extern vchar_t *dumpph1 __P((void)); +extern struct ph1handle *newph1 __P((void)); +extern void delph1 __P((struct ph1handle *)); +extern int insph1 __P((struct ph1handle *)); +extern void remph1 __P((struct ph1handle *)); +extern void flushph1 __P((void)); +extern void initph1tree __P((void)); + +extern struct ph2handle *getph2byspidx __P((struct policyindex *)); +extern struct ph2handle *getph2byspid __P((u_int32_t)); +extern struct ph2handle *getph2byseq __P((u_int32_t)); +extern struct ph2handle *getph2bymsgid __P((struct ph1handle *, u_int32_t)); +extern struct ph2handle *getph2bysaidx __P((struct sockaddr *, + struct sockaddr *, u_int, u_int32_t)); +extern struct ph2handle *newph2 __P((void)); +extern void initph2 __P((struct ph2handle *)); +extern void delph2 __P((struct ph2handle *)); +extern int insph2 __P((struct ph2handle *)); +extern void remph2 __P((struct ph2handle *)); +extern void flushph2 __P((void)); +extern void deleteallph2 __P((struct sockaddr *, struct sockaddr *, u_int)); +extern void initph2tree __P((void)); + +extern void bindph12 __P((struct ph1handle *, struct ph2handle *)); +extern void unbindph12 __P((struct ph2handle *)); + +extern struct contacted *getcontacted __P((struct sockaddr *)); +extern int inscontacted __P((struct sockaddr *)); +extern void initctdtree __P((void)); + +extern int check_recvdpkt __P((struct sockaddr *, + struct sockaddr *, vchar_t *)); +extern int add_recvdpkt __P((struct sockaddr *, struct sockaddr *, + vchar_t *, vchar_t *)); +extern void init_recvdpkt __P((void)); diff --git a/racoon.tproj/ipsec_doi.c b/racoon.tproj/ipsec_doi.c new file mode 100644 index 0000000..2b039c5 --- /dev/null +++ b/racoon.tproj/ipsec_doi.c @@ -0,0 +1,3910 @@ +/* $KAME: ipsec_doi.c,v 1.154 2001/12/31 20:13:40 thorpej 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. 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. + */ + +#include +#include +#include + +#include +#include + +#ifdef IPV6_INRIA_VERSION +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "var.h" +#include "vmbuf.h" +#include "misc.h" +#include "plog.h" +#include "debug.h" + +#include "cfparse.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "remoteconf.h" +#include "localconf.h" +#include "sockmisc.h" +#include "handler.h" +#include "policy.h" +#include "algorithm.h" +#include "sainfo.h" +#include "proposal.h" +#include "crypto_openssl.h" +#include "strnames.h" +#include "gcmalloc.h" + +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif + +int verbose_proposal_check = 1; + +static vchar_t *get_ph1approval __P((struct ph1handle *, struct prop_pair **)); +static struct isakmpsa *get_ph1approvalx __P((struct prop_pair *, + struct isakmpsa *, struct isakmpsa *)); +static void print_ph1mismatched __P((struct prop_pair *, struct isakmpsa *)); +static int t2isakmpsa __P((struct isakmp_pl_t *, struct isakmpsa *)); +static int cmp_aproppair_i __P((struct prop_pair *, struct prop_pair *)); +static struct prop_pair *get_ph2approval __P((struct ph2handle *, + struct prop_pair **)); +static struct prop_pair *get_ph2approvalx __P((struct ph2handle *, + struct prop_pair *)); +static void free_proppair0 __P((struct prop_pair *)); + +static int get_transform + __P((struct isakmp_pl_p *, struct prop_pair **, int *)); +static u_int32_t ipsecdoi_set_ld __P((vchar_t *)); + +static int check_doi __P((u_int32_t)); +static int check_situation __P((u_int32_t)); + +static int check_prot_main __P((int)); +static int check_prot_quick __P((int)); +static int (*check_protocol[]) __P((int)) = { + check_prot_main, /* IPSECDOI_TYPE_PH1 */ + check_prot_quick, /* IPSECDOI_TYPE_PH2 */ +}; + +static int check_spi_size __P((int, int)); + +static int check_trns_isakmp __P((int)); +static int check_trns_ah __P((int)); +static int check_trns_esp __P((int)); +static int check_trns_ipcomp __P((int)); +static int (*check_transform[]) __P((int)) = { + 0, + check_trns_isakmp, /* IPSECDOI_PROTO_ISAKMP */ + check_trns_ah, /* IPSECDOI_PROTO_IPSEC_AH */ + check_trns_esp, /* IPSECDOI_PROTO_IPSEC_ESP */ + check_trns_ipcomp, /* IPSECDOI_PROTO_IPCOMP */ +}; + +static int check_attr_isakmp __P((struct isakmp_pl_t *)); +static int check_attr_ah __P((struct isakmp_pl_t *)); +static int check_attr_esp __P((struct isakmp_pl_t *)); +static int check_attr_ipsec __P((int, struct isakmp_pl_t *)); +static int check_attr_ipcomp __P((struct isakmp_pl_t *)); +static int (*check_attributes[]) __P((struct isakmp_pl_t *)) = { + 0, + check_attr_isakmp, /* IPSECDOI_PROTO_ISAKMP */ + check_attr_ah, /* IPSECDOI_PROTO_IPSEC_AH */ + check_attr_esp, /* IPSECDOI_PROTO_IPSEC_ESP */ + check_attr_ipcomp, /* IPSECDOI_PROTO_IPCOMP */ +}; + +static int setph1prop __P((struct isakmpsa *, caddr_t)); +static int setph1trns __P((struct isakmpsa *, caddr_t)); +static int setph1attr __P((struct isakmpsa *, caddr_t)); +static vchar_t *setph2proposal0 __P((const struct ph2handle *, + const struct saprop *, const struct saproto *)); + +static vchar_t *getidval __P((int, vchar_t *)); + +#ifdef HAVE_GSSAPI +static struct isakmpsa *fixup_initiator_sa __P((struct isakmpsa *, + struct isakmpsa *)); +#endif + +/*%%%*/ +/* + * check phase 1 SA payload. + * make new SA payload to be replyed not including general header. + * the pointer to one of isakmpsa in proposal is set into iph1->approval. + * OUT: + * positive: the pointer to new buffer of SA payload. + * network byte order. + * NULL : error occurd. + */ +int +ipsecdoi_checkph1proposal(sa, iph1) + vchar_t *sa; + struct ph1handle *iph1; +{ + vchar_t *newsa; /* new SA payload approved. */ + struct prop_pair **pair; + + /* get proposal pair */ + pair = get_proppair(sa, IPSECDOI_TYPE_PH1); + if (pair == NULL) + return -1; + + /* check and get one SA for use */ + newsa = get_ph1approval(iph1, pair); + + free_proppair(pair); + + if (newsa == NULL) + return -1; + + iph1->sa_ret = newsa; + + return 0; +} + +/* + * acceptable check for remote configuration. + * return a new SA payload to be reply to peer. + */ +static vchar_t * +get_ph1approval(iph1, pair) + struct ph1handle *iph1; + struct prop_pair **pair; +{ + vchar_t *newsa; + struct isakmpsa *sa, tsa; + struct prop_pair *s, *p; + int prophlen; + int i; + + iph1->approval = NULL; + + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + for (s = pair[i]; s; s = s->next) { + prophlen = sizeof(struct isakmp_pl_p) + + s->prop->spi_size; + /* compare proposal and select one */ + for (p = s; p; p = p->tnext) { + sa = get_ph1approvalx(p, iph1->rmconf->proposal, + &tsa); + if (sa != NULL) + goto found; + } + } + } + + /* + * if there is no suitable proposal, racoon complains about all of + * mismatched items in those proposal. + */ + if (verbose_proposal_check) { + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + for (s = pair[i]; s; s = s->next) { + prophlen = sizeof(struct isakmp_pl_p) + + s->prop->spi_size; + for (p = s; p; p = p->tnext) { + print_ph1mismatched(p, + iph1->rmconf->proposal); + } + } + } + } + plog(LLV_ERROR, LOCATION, NULL, "no suitable proposal found.\n"); + + return NULL; + +found: + plog(LLV_DEBUG, LOCATION, NULL, "an acceptable proposal found.\n"); + + /* check DH group settings */ + if (sa->dhgrp) { + if (sa->dhgrp->prime && sa->dhgrp->gen1) { + /* it's ok */ + goto saok; + } + plog(LLV_WARNING, LOCATION, NULL, + "invalid DH parameter found, use default.\n"); + oakley_dhgrp_free(sa->dhgrp); + } + + if (oakley_setdhgroup(sa->dh_group, &sa->dhgrp) == -1) { + sa->dhgrp = NULL; + return NULL; + } + +saok: +#ifdef HAVE_GSSAPI + if (sa->gssid != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "gss id in new sa '%s'\n", + sa->gssid->v); + if (iph1-> side == INITIATOR) { + if (iph1->rmconf->proposal->gssid != NULL) + iph1->gi_i = vdup(iph1->rmconf->proposal->gssid); + if (tsa.gssid != NULL) + iph1->gi_r = vdup(tsa.gssid); + iph1->approval = fixup_initiator_sa(sa, &tsa); + } else { + if (tsa.gssid != NULL) { + iph1->gi_r = vdup(tsa.gssid); + if (iph1->rmconf->proposal->gssid != NULL) + iph1->gi_i = + vdup(iph1->rmconf->proposal->gssid); + else + iph1->gi_i = gssapi_get_default_id(iph1); + if (sa->gssid == NULL && iph1->gi_i != NULL) + sa->gssid = vdup(iph1->gi_i); + } + iph1->approval = sa; + } + if (iph1->gi_i != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "GIi is %*s\n", + iph1->gi_i->l, iph1->gi_i->v); + if (iph1->gi_r != NULL) + plog(LLV_DEBUG, LOCATION, NULL, "GIr is %*s\n", + iph1->gi_r->l, iph1->gi_r->v); +#else + iph1->approval = sa; +#endif + + newsa = get_sabyproppair(p, iph1); + if (newsa == NULL) + iph1->approval = NULL; + + return newsa; +} + +/* + * compare peer's single proposal and all of my proposal. + * and select one if suiatable. + * p : one of peer's proposal. + * proposal: my proposals. + */ +static struct isakmpsa * +get_ph1approvalx(p, proposal, sap) + struct prop_pair *p; + struct isakmpsa *proposal, *sap; +{ +#ifdef YIPS_DEBUG + struct isakmp_pl_p *prop = p->prop; +#endif + struct isakmp_pl_t *trns = p->trns; + struct isakmpsa sa, *s, *tsap; + + plog(LLV_DEBUG, LOCATION, NULL, + "prop#=%d, prot-id=%s, spi-size=%d, #trns=%d\n", + prop->p_no, s_ipsecdoi_proto(prop->proto_id), + prop->spi_size, prop->num_t); + + plog(LLV_DEBUG, LOCATION, NULL, + "trns#=%d, trns-id=%s\n", + trns->t_no, + s_ipsecdoi_trns(prop->proto_id, trns->t_id)); + + tsap = sap != NULL ? sap : &sa; + + memset(tsap, 0, sizeof(*tsap)); + if (t2isakmpsa(trns, tsap) < 0) + return NULL; + for (s = proposal; s != NULL; s = s->next) { + plog(LLV_DEBUG, LOCATION, NULL, "Compared: DB:Peer\n"); + plog(LLV_DEBUG, LOCATION, NULL, "(lifetime = %ld:%ld)\n", + s->lifetime, tsap->lifetime); + plog(LLV_DEBUG, LOCATION, NULL, "(lifebyte = %ld:%ld)\n", + s->lifebyte, tsap->lifebyte); + plog(LLV_DEBUG, LOCATION, NULL, "enctype = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + s->enctype), + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + tsap->enctype)); + plog(LLV_DEBUG, LOCATION, NULL, "(encklen = %d:%d)\n", + s->encklen, tsap->encklen); + plog(LLV_DEBUG, LOCATION, NULL, "hashtype = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + s->hashtype), + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + tsap->hashtype)); + plog(LLV_DEBUG, LOCATION, NULL, "authmethod = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + s->authmethod), + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + tsap->authmethod)); + plog(LLV_DEBUG, LOCATION, NULL, "dh_group = %s:%s\n", + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + s->dh_group), + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + tsap->dh_group)); +#if 0 + /* XXX to be considered */ + if (tsap->lifetime > s->lifetime) ; + if (tsap->lifebyte > s->lifebyte) ; +#endif + /* + * if responder side and peer's key length in proposal + * is bigger than mine, it might be accepted. + */ + if(tsap->enctype == s->enctype + && tsap->authmethod == s->authmethod + && tsap->hashtype == s->hashtype + && tsap->dh_group == s->dh_group + && tsap->encklen == s->encklen) + break; + } + + if (tsap->dhgrp != NULL) + oakley_dhgrp_free(tsap->dhgrp); + return s; +} + +/* + * print all of items in peer's proposal which are mismatched to my proposal. + * p : one of peer's proposal. + * proposal: my proposals. + */ +static void +print_ph1mismatched(p, proposal) + struct prop_pair *p; + struct isakmpsa *proposal; +{ + struct isakmpsa sa, *s; + + memset(&sa, 0, sizeof(sa)); + if (t2isakmpsa(p->trns, &sa) < 0) + return; + for (s = proposal; s ; s = s->next) { + if (sa.enctype != s->enctype) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected enctype: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + s->enctype), + s_oakley_attr_v(OAKLEY_ATTR_ENC_ALG, + sa.enctype)); + } + if (sa.authmethod != s->authmethod) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected authmethod: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + s->authmethod), + s_oakley_attr_v(OAKLEY_ATTR_AUTH_METHOD, + sa.authmethod)); + } + if (sa.hashtype != s->hashtype) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected hashtype: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + s->hashtype), + s_oakley_attr_v(OAKLEY_ATTR_HASH_ALG, + sa.hashtype)); + } + if (sa.dh_group != s->dh_group) { + plog(LLV_ERROR, LOCATION, NULL, + "rejected dh_group: " + "DB(prop#%d:trns#%d):Peer(prop#%d:trns#%d) = " + "%s:%s\n", + s->prop_no, s->trns_no, + p->prop->p_no, p->trns->t_no, + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + s->dh_group), + s_oakley_attr_v(OAKLEY_ATTR_GRP_DESC, + sa.dh_group)); + } + } + + if (sa.dhgrp != NULL) + oakley_dhgrp_free(sa.dhgrp); +} + +/* + * get ISAKMP data attributes + */ +static int +t2isakmpsa(trns, sa) + struct isakmp_pl_t *trns; + struct isakmpsa *sa; +{ + struct isakmp_data *d, *prev; + int flag, type; + int error = -1; + int life_t; + int keylen = 0; + vchar_t *val = NULL; + int len, tlen; + u_char *p; + + tlen = ntohs(trns->h.len) - sizeof(*trns); + prev = (struct isakmp_data *)NULL; + d = (struct isakmp_data *)(trns + 1); + + /* default */ + life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT; + sa->lifetime = OAKLEY_ATTR_SA_LD_SEC_DEFAULT; + sa->lifebyte = 0; + sa->dhgrp = racoon_calloc(1, sizeof(struct dhgroup)); + if (!sa->dhgrp) + goto err; + + while (tlen > 0) { + + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_oakley_attr(type), flag, + s_oakley_attr_v(type, ntohs(d->lorv))); + + /* get variable-sized item */ + switch (type) { + case OAKLEY_ATTR_GRP_PI: + case OAKLEY_ATTR_GRP_GEN_ONE: + case OAKLEY_ATTR_GRP_GEN_TWO: + case OAKLEY_ATTR_GRP_CURVE_A: + case OAKLEY_ATTR_GRP_CURVE_B: + case OAKLEY_ATTR_SA_LD: + case OAKLEY_ATTR_GRP_ORDER: + if (flag) { /*TV*/ + len = 2; + p = (u_char *)&d->lorv; + } else { /*TLV*/ + len = ntohs(d->lorv); + p = (u_char *)(d + 1); + } + val = vmalloc(len); + if (!val) + return -1; + memcpy(val->v, p, len); + break; + + default: + break; + } + + switch (type) { + case OAKLEY_ATTR_ENC_ALG: + sa->enctype = (u_int16_t)ntohs(d->lorv); + break; + + case OAKLEY_ATTR_HASH_ALG: + sa->hashtype = (u_int16_t)ntohs(d->lorv); + break; + + case OAKLEY_ATTR_AUTH_METHOD: + sa->authmethod = ntohs(d->lorv); + break; + + case OAKLEY_ATTR_GRP_DESC: + sa->dh_group = (u_int16_t)ntohs(d->lorv); + break; + + case OAKLEY_ATTR_GRP_TYPE: + { + int type = (int)ntohs(d->lorv); + if (type == OAKLEY_ATTR_GRP_TYPE_MODP) + sa->dhgrp->type = type; + else + return -1; + break; + } + case OAKLEY_ATTR_GRP_PI: + sa->dhgrp->prime = val; + break; + + case OAKLEY_ATTR_GRP_GEN_ONE: + vfree(val); + if (!flag) + sa->dhgrp->gen1 = ntohs(d->lorv); + else { + int len = ntohs(d->lorv); + sa->dhgrp->gen1 = 0; + if (len > 4) + return -1; + memcpy(&sa->dhgrp->gen1, d + 1, len); + sa->dhgrp->gen1 = ntohl(sa->dhgrp->gen1); + } + break; + + case OAKLEY_ATTR_GRP_GEN_TWO: + vfree(val); + if (!flag) + sa->dhgrp->gen2 = ntohs(d->lorv); + else { + int len = ntohs(d->lorv); + sa->dhgrp->gen2 = 0; + if (len > 4) + return -1; + memcpy(&sa->dhgrp->gen2, d + 1, len); + sa->dhgrp->gen2 = ntohl(sa->dhgrp->gen2); + } + break; + + case OAKLEY_ATTR_GRP_CURVE_A: + sa->dhgrp->curve_a = val; + break; + + case OAKLEY_ATTR_GRP_CURVE_B: + sa->dhgrp->curve_b = val; + break; + + case OAKLEY_ATTR_SA_LD_TYPE: + { + int type = (int)ntohs(d->lorv); + switch (type) { + case OAKLEY_ATTR_SA_LD_TYPE_SEC: + case OAKLEY_ATTR_SA_LD_TYPE_KB: + life_t = type; + break; + default: + life_t = OAKLEY_ATTR_SA_LD_TYPE_DEFAULT; + break; + } + break; + } + case OAKLEY_ATTR_SA_LD: + if (!prev + || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) != + OAKLEY_ATTR_SA_LD_TYPE) { + plog(LLV_ERROR, LOCATION, NULL, + "life duration must follow ltype\n"); + break; + } + + switch (life_t) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + sa->lifetime = ipsecdoi_set_ld(val); + vfree(val); + if (sa->lifetime == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto err; + } + break; + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + sa->lifebyte = ipsecdoi_set_ld(val); + vfree(val); + if (sa->lifetime == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto err; + } + break; + default: + vfree(val); + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type: %d\n", life_t); + goto err; + } + break; + + case OAKLEY_ATTR_KEY_LEN: + { + int len = ntohs(d->lorv); + if (len % 8 != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "keylen %d: not multiple of 8\n", + len); + goto err; + } + sa->encklen = (u_int16_t)len; + keylen++; + break; + } + case OAKLEY_ATTR_PRF: + case OAKLEY_ATTR_FIELD_SIZE: + /* unsupported */ + break; + + case OAKLEY_ATTR_GRP_ORDER: + sa->dhgrp->order = val; + break; +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_GSS_ID: + { + int len = ntohs(d->lorv); + + sa->gssid = vmalloc(len); + memcpy(sa->gssid->v, d + 1, len); + plog(LLV_DEBUG, LOCATION, NULL, + "received gss id '%s' (len %d)\n", sa->gssid->v, + sa->gssid->l); + break; + } +#endif + + default: + break; + } + + prev = d; + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + ntohs(d->lorv)); + d = (struct isakmp_data *)((char *)d + sizeof(*d) + ntohs(d->lorv)); + } + } + + /* key length must not be specified on some algorithms */ + if (keylen) { + if (sa->enctype == OAKLEY_ATTR_ENC_ALG_DES +#ifdef HAVE_OPENSSL_IDEA_H + || sa->enctype == OAKLEY_ATTR_ENC_ALG_IDEA +#endif + || sa->enctype == OAKLEY_ATTR_ENC_ALG_3DES) { + plog(LLV_ERROR, LOCATION, NULL, + "keylen must not be specified " + "for encryption algorithm %d\n", + sa->enctype); + return -1; + } + } + + return 0; +err: + return error; +} + +/*%%%*/ +/* + * check phase 2 SA payload and select single proposal. + * make new SA payload to be replyed not including general header. + * This function is called by responder only. + * OUT: + * 0: succeed. + * -1: error occured. + */ +int +ipsecdoi_selectph2proposal(iph2) + struct ph2handle *iph2; +{ + struct prop_pair **pair; + struct prop_pair *ret; + + /* get proposal pair */ + pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + if (pair == NULL) + return -1; + + /* check and select a proposal. */ + ret = get_ph2approval(iph2, pair); + free_proppair(pair); + if (ret == NULL) + return -1; + + /* make a SA to be replayed. */ + /* SPI must be updated later. */ + iph2->sa_ret = get_sabyproppair(ret, iph2->ph1); + free_proppair0(ret); + if (iph2->sa_ret == NULL) + return -1; + + return 0; +} + +/* + * check phase 2 SA payload returned from responder. + * This function is called by initiator only. + * OUT: + * 0: valid. + * -1: invalid. + */ +int +ipsecdoi_checkph2proposal(iph2) + struct ph2handle *iph2; +{ + struct prop_pair **rpair = NULL, **spair = NULL; + struct prop_pair *p; + int i, n, num; + int error = -1; + + /* get proposal pair of SA sent. */ + spair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + if (spair == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get prop pair.\n"); + goto end; + } + + /* XXX should check the number of transform */ + + /* get proposal pair of SA replyed */ + rpair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2); + if (rpair == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get prop pair.\n"); + goto end; + } + + /* check proposal is only one ? */ + n = 0; + num = 0; + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (rpair[i]) { + n = i; + num++; + } + } + if (num == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no proposal received.\n"); + goto end; + } + if (num != 1) { + plog(LLV_ERROR, LOCATION, NULL, + "some proposals received.\n"); + goto end; + } + + if (spair[n] == NULL) { + plog(LLV_WARNING, LOCATION, NULL, + "invalid proposal number:%d received.\n", i); + } + + + if (rpair[n]->tnext != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "multi transforms replyed.\n"); + goto end; + } + + if (cmp_aproppair_i(rpair[n], spair[n])) { + plog(LLV_ERROR, LOCATION, NULL, + "proposal mismathed.\n"); + goto end; + } + + /* + * check and select a proposal. + * ensure that there is no modification of the proposal by + * cmp_aproppair_i() + */ + p = get_ph2approval(iph2, rpair); + if (p == NULL) + goto end; + + /* make a SA to be replayed. */ + vfree(iph2->sa_ret); + iph2->sa_ret = get_sabyproppair(p, iph2->ph1); + free_proppair0(p); + if (iph2->sa_ret == NULL) + goto end; + + error = 0; + +end: + if (rpair) + free_proppair(rpair); + if (spair) + free_proppair(spair); + + return error; +} + +/* + * compare two prop_pair which is assumed to have same proposal number. + * the case of bundle or single SA, NOT multi transforms. + * a: a proposal that is multi protocols and single transform, usually replyed. + * b: a proposal that is multi protocols and multi transform, usually sent. + * NOTE: this function is for initiator. + * OUT + * 0: equal + * 1: not equal + * XXX cannot understand the comment! + */ +static int +cmp_aproppair_i(a, b) + struct prop_pair *a, *b; +{ + struct prop_pair *p, *q, *r; + int len; + + for (p = a, q = b; p && q; p = p->next, q = q->next) { + for (r = q; r; r = r->tnext) { + /* compare trns */ + if (p->trns->t_no == r->trns->t_no) + break; + } + if (!r) { + /* no suitable transform found */ + plog(LLV_ERROR, LOCATION, NULL, + "no suitable transform found.\n"); + return -1; + } + + /* compare prop */ + if (p->prop->p_no != r->prop->p_no) { + plog(LLV_WARNING, LOCATION, NULL, + "proposal #%d mismatched, " + "expected #%d.\n", + r->prop->p_no, p->prop->p_no); + /*FALLTHROUGH*/ + } + + if (p->prop->proto_id != r->prop->proto_id) { + plog(LLV_ERROR, LOCATION, NULL, + "proto_id mismathed: my:%d peer:%d\n", + r->prop->proto_id, p->prop->proto_id); + return -1; + } + + if (p->prop->proto_id != r->prop->proto_id) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid spi size: %d.\n", + p->prop->proto_id); + return -1; + } + + /* check #of transforms */ + if (p->prop->num_t != 1) { + plog(LLV_WARNING, LOCATION, NULL, + "#of transform is %d, " + "but expected 1.\n", p->prop->num_t); + /*FALLTHROUGH*/ + } + + if (p->trns->t_id != r->trns->t_id) { + plog(LLV_WARNING, LOCATION, NULL, + "transform number has been modified.\n"); + /*FALLTHROUGH*/ + } + if (p->trns->reserved != r->trns->reserved) { + plog(LLV_WARNING, LOCATION, NULL, + "reserved field should be zero.\n"); + /*FALLTHROUGH*/ + } + + /* compare attribute */ + len = ntohs(r->trns->h.len) - sizeof(*p->trns); + if (memcmp(p->trns + 1, r->trns + 1, len) != 0) { + plog(LLV_WARNING, LOCATION, NULL, + "attribute has been modified.\n"); + /*FALLTHROUGH*/ + } + } + if ((p && !q) || (!p && q)) { + /* # of protocols mismatched */ + plog(LLV_ERROR, LOCATION, NULL, + "#of protocols mismatched.\n"); + return -1; + } + + return 0; +} + +/* + * acceptable check for policy configuration. + * return a new SA payload to be reply to peer. + */ +static struct prop_pair * +get_ph2approval(iph2, pair) + struct ph2handle *iph2; + struct prop_pair **pair; +{ + struct prop_pair *ret; + int i; + + iph2->approval = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, + "begin compare proposals.\n"); + + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + plog(LLV_DEBUG, LOCATION, NULL, + "pair[%d]: %p\n", i, pair[i]); + print_proppair(LLV_DEBUG, pair[i]);; + + /* compare proposal and select one */ + ret = get_ph2approvalx(iph2, pair[i]); + if (ret != NULL) { + /* found */ + return ret; + } + } + + plog(LLV_ERROR, LOCATION, NULL, "no suitable policy found.\n"); + + return NULL; +} + +/* + * compare my proposal and peers just one proposal. + * set a approval. + */ +static struct prop_pair * +get_ph2approvalx(iph2, pp) + struct ph2handle *iph2; + struct prop_pair *pp; +{ + struct prop_pair *ret = NULL; + struct saprop *pr0, *pr = NULL; + struct saprop *q1, *q2; + + pr0 = aproppair2saprop(pp); + if (pr0 == NULL) + return NULL; + + for (q1 = pr0; q1; q1 = q1->next) { + for (q2 = iph2->proposal; q2; q2 = q2->next) { + plog(LLV_DEBUG, LOCATION, NULL, + "peer's single bundle:\n"); + printsaprop0(LLV_DEBUG, q1); + plog(LLV_DEBUG, LOCATION, NULL, + "my single bundle:\n"); + printsaprop0(LLV_DEBUG, q2); + + pr = cmpsaprop_alloc(iph2->ph1, q1, q2, iph2->side); + if (pr != NULL) + goto found; + + plog(LLV_ERROR, LOCATION, NULL, + "not matched\n"); + } + } + /* no proposal matching */ +err: + flushsaprop(pr0); + return NULL; + +found: + flushsaprop(pr0); + plog(LLV_DEBUG, LOCATION, NULL, "matched\n"); + iph2->approval = pr; + + { + struct saproto *sp; + struct prop_pair *p, *n, *x; + + ret = NULL; + + for (p = pp; p; p = p->next) { + /* + * find a proposal with matching proto_id. + * we have analyzed validity already, in cmpsaprop_alloc(). + */ + for (sp = pr->head; sp; sp = sp->next) { + if (sp->proto_id == p->prop->proto_id) + break; + } + if (!sp) + goto err; + if (sp->head->next) + goto err; /* XXX */ + + for (x = p; x; x = x->tnext) + if (sp->head->trns_no == x->trns->t_no) + break; + if (!x) + goto err; /* XXX */ + + n = racoon_calloc(1, sizeof(struct prop_pair)); + if (!n) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + goto err; + } + + n->prop = x->prop; + n->trns = x->trns; + + /* need to preserve the order */ + for (x = ret; x && x->next; x = x->next) + ; + if (x && x->prop == n->prop) { + for (/*nothing*/; x && x->tnext; x = x->tnext) + ; + x->tnext = n; + } else { + if (x) + x->next = n; + else { + ret = n; + } + } + + /* #of transforms should be updated ? */ + } + } + + return ret; +} + +void +free_proppair(pair) + struct prop_pair **pair; +{ + int i; + + for (i = 0; i < MAXPROPPAIRLEN; i++) { + free_proppair0(pair[i]); + pair[i] = NULL; + } + racoon_free(pair); +} + +static void +free_proppair0(pair) + struct prop_pair *pair; +{ + struct prop_pair *p, *q, *r, *s; + + for (p = pair; p; p = q) { + q = p->next; + for (r = p; r; r = s) { + s = r->tnext; + racoon_free(r); + } + } +} + +/* + * get proposal pairs from SA payload. + * tiny check for proposal payload. + */ +struct prop_pair ** +get_proppair(sa, mode) + vchar_t *sa; + int mode; +{ + struct prop_pair **pair; + int num_p = 0; /* number of proposal for use */ + int tlen; + caddr_t bp; + int i; + struct ipsecdoi_sa_b *sab = (struct ipsecdoi_sa_b *)sa->v; + + plog(LLV_DEBUG, LOCATION, NULL, "total SA len=%d\n", sa->l); + plogdump(LLV_DEBUG, sa->v, sa->l); + + /* check SA payload size */ + if (sa->l < sizeof(*sab)) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid SA length = %d.\n", sa->l); + return NULL; + } + + /* check DOI */ + if (check_doi(ntohl(sab->doi)) < 0) + return NULL; + + /* check SITUATION */ + if (check_situation(ntohl(sab->sit)) < 0) + return NULL; + + pair = racoon_calloc(1, MAXPROPPAIRLEN * sizeof(*pair)); + if (pair == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + return NULL; + } + memset(pair, 0, sizeof(pair)); + + bp = (caddr_t)(sab + 1); + tlen = sa->l - sizeof(*sab); + + { + struct isakmp_pl_p *prop; + int proplen; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + + pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_P, (struct isakmp_gen *)bp, tlen); + if (pbuf == NULL) + return NULL; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + /* check the value of next payload */ + if (pa->type != ISAKMP_NPTYPE_P) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid payload type=%u\n", pa->type); + vfree(pbuf); + return NULL; + } + + prop = (struct isakmp_pl_p *)pa->ptr; + proplen = pa->len; + + plog(LLV_DEBUG, LOCATION, NULL, + "proposal #%u len=%d\n", prop->p_no, proplen); + + if (proplen == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proposal with length %d\n", proplen); + vfree(pbuf); + return NULL; + } + + /* check Protocol ID */ + if (!check_protocol[mode]) { + plog(LLV_ERROR, LOCATION, NULL, + "unsupported mode %d\n", mode); + continue; + } + + if (check_protocol[mode](prop->proto_id) < 0) + continue; + + /* check SPI length when IKE. */ + if (check_spi_size(prop->proto_id, prop->spi_size) < 0) + continue; + + /* get transform */ + if (get_transform(prop, pair, &num_p) < 0) { + vfree(pbuf); + return NULL; + } + } + vfree(pbuf); + pbuf = NULL; + } + + { + int notrans, nprop; + struct prop_pair *p, *q; + + /* check for proposals with no transforms */ + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (!pair[i]) + continue; + + plog(LLV_DEBUG, LOCATION, NULL, "pair %d:\n", i); + print_proppair(LLV_DEBUG, pair[i]); + + notrans = nprop = 0; + for (p = pair[i]; p; p = p->next) { + if (p->trns == NULL) { + notrans++; + break; + } + for (q = p; q; q = q->tnext) + nprop++; + } + +#if 0 + /* + * XXX at this moment, we cannot accept proposal group + * with multiple proposals. this should be fixed. + */ + if (pair[i]->next) { + plog(LLV_WARNING, LOCATION, NULL, + "proposal #%u ignored " + "(multiple proposal not supported)\n", + pair[i]->prop->p_no); + notrans++; + } +#endif + + if (notrans) { + for (p = pair[i]; p; p = q) { + q = p->next; + racoon_free(p); + } + pair[i] = NULL; + num_p--; + } else { + plog(LLV_DEBUG, LOCATION, NULL, + "proposal #%u: %d transform\n", + pair[i]->prop->p_no, nprop); + } + } + } + + /* bark if no proposal is found. */ + if (num_p <= 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no Proposal found.\n"); + return NULL; + } + + return pair; +} + +/* + * check transform payload. + * OUT: + * positive: return the pointer to the payload of valid transform. + * 0 : No valid transform found. + */ +static int +get_transform(prop, pair, num_p) + struct isakmp_pl_p *prop; + struct prop_pair **pair; + int *num_p; +{ + int tlen; /* total length of all transform in a proposal */ + caddr_t bp; + struct isakmp_pl_t *trns; + int trnslen; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + struct prop_pair *p = NULL, *q; + int num_t; + + bp = (caddr_t)prop + sizeof(struct isakmp_pl_p) + prop->spi_size; + tlen = ntohs(prop->h.len) + - (sizeof(struct isakmp_pl_p) + prop->spi_size); + pbuf = isakmp_parsewoh(ISAKMP_NPTYPE_T, (struct isakmp_gen *)bp, tlen); + if (pbuf == NULL) + return -1; + + /* check and get transform for use */ + num_t = 0; + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + num_t++; + + /* check the value of next payload */ + if (pa->type != ISAKMP_NPTYPE_T) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid payload type=%u\n", pa->type); + break; + } + + trns = (struct isakmp_pl_t *)pa->ptr; + trnslen = pa->len; + + plog(LLV_DEBUG, LOCATION, NULL, + "transform #%u len=%u\n", trns->t_no, trnslen); + + /* check transform ID */ + if (prop->proto_id >= ARRAYLEN(check_transform)) { + plog(LLV_WARNING, LOCATION, NULL, + "unsupported proto_id %u\n", + prop->proto_id); + continue; + } + if (prop->proto_id >= ARRAYLEN(check_attributes)) { + plog(LLV_WARNING, LOCATION, NULL, + "unsupported proto_id %u\n", + prop->proto_id); + continue; + } + + if (!check_transform[prop->proto_id] + || !check_attributes[prop->proto_id]) { + plog(LLV_WARNING, LOCATION, NULL, + "unsupported proto_id %u\n", + prop->proto_id); + continue; + } + if (check_transform[prop->proto_id](trns->t_id) < 0) + continue; + + /* check data attributes */ + if (check_attributes[prop->proto_id](trns) != 0) + continue; + + p = racoon_calloc(1, sizeof(*p)); + if (p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + vfree(pbuf); + return -1; + } + p->prop = prop; + p->trns = trns; + + /* need to preserve the order */ + for (q = pair[prop->p_no]; q && q->next; q = q->next) + ; + if (q && q->prop == p->prop) { + for (/*nothing*/; q && q->tnext; q = q->tnext) + ; + q->tnext = p; + } else { + if (q) + q->next = p; + else { + pair[prop->p_no] = p; + (*num_p)++; + } + } + } + + vfree(pbuf); + + return 0; +} + +/* + * make a new SA payload from prop_pair. + * NOTE: this function make spi value clear. + */ +vchar_t * +get_sabyproppair(pair, iph1) + struct prop_pair *pair; + struct ph1handle *iph1; +{ + vchar_t *newsa; + int newtlen; + u_int8_t *np_p = NULL; + struct prop_pair *p; + int prophlen, trnslen; + caddr_t bp; + + newtlen = sizeof(struct ipsecdoi_sa_b); + for (p = pair; p; p = p->next) { + newtlen += (sizeof(struct isakmp_pl_p) + + p->prop->spi_size + + ntohs(p->trns->h.len)); + } + + newsa = vmalloc(newtlen); + if (newsa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n"); + return NULL; + } + bp = newsa->v; + + ((struct isakmp_gen *)bp)->len = htons(newtlen); + + /* update some of values in SA header */ + ((struct ipsecdoi_sa_b *)bp)->doi = htonl(iph1->rmconf->doitype); + ((struct ipsecdoi_sa_b *)bp)->sit = htonl(iph1->rmconf->sittype); + bp += sizeof(struct ipsecdoi_sa_b); + + /* create proposal payloads */ + for (p = pair; p; p = p->next) { + prophlen = sizeof(struct isakmp_pl_p) + + p->prop->spi_size; + trnslen = ntohs(p->trns->h.len); + + if (np_p) + *np_p = ISAKMP_NPTYPE_P; + + /* create proposal */ + + memcpy(bp, p->prop, prophlen); + ((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen); + ((struct isakmp_pl_p *)bp)->num_t = 1; + np_p = &((struct isakmp_pl_p *)bp)->h.np; + memset(bp + sizeof(struct isakmp_pl_p), 0, p->prop->spi_size); + bp += prophlen; + + /* create transform */ + memcpy(bp, p->trns, trnslen); + ((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_t *)bp)->h.len = htons(trnslen); + bp += trnslen; + } + + return newsa; +} + +/* + * update responder's spi + */ +int +ipsecdoi_updatespi(iph2) + struct ph2handle *iph2; +{ + struct prop_pair **pair, *p; + struct saprop *pp; + struct saproto *pr; + int i; + int error = -1; + u_int8_t *spi; + + pair = get_proppair(iph2->sa_ret, IPSECDOI_TYPE_PH2); + if (pair == NULL) + return -1; + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i]) + break; + } + if (i == MAXPROPPAIRLEN || pair[i]->tnext) { + /* multiple transform must be filtered by selectph2proposal.*/ + goto end; + } + + pp = iph2->approval; + + /* create proposal payloads */ + for (p = pair[i]; p; p = p->next) { + /* + * find a proposal/transform with matching proto_id/t_id. + * we have analyzed validity already, in cmpsaprop_alloc(). + */ + for (pr = pp->head; pr; pr = pr->next) { + if (p->prop->proto_id == pr->proto_id && + p->trns->t_id == pr->head->trns_id) { + break; + } + } + if (!pr) + goto end; + + /* + * XXX SPI bits are left-filled, for use with IPComp. + * we should be switching to variable-length spi field... + */ + spi = (u_int8_t *)&pr->spi; + spi += sizeof(pr->spi); + spi -= pr->spisize; + memcpy((caddr_t)p->prop + sizeof(*p->prop), spi, pr->spisize); + } + + error = 0; +end: + free_proppair(pair); + return error; +} + +/* + * make a new SA payload from prop_pair. + */ +vchar_t * +get_sabysaprop(pp0, sa0) + struct saprop *pp0; + vchar_t *sa0; +{ + struct prop_pair **pair; + vchar_t *newsa; + int newtlen; + u_int8_t *np_p = NULL; + struct prop_pair *p = NULL; + struct saprop *pp; + struct saproto *pr; + struct satrns *tr; + int prophlen, trnslen; + caddr_t bp; + + /* get proposal pair */ + pair = get_proppair(sa0, IPSECDOI_TYPE_PH2); + if (pair == NULL) + return NULL; + + newtlen = sizeof(struct ipsecdoi_sa_b); + for (pp = pp0; pp; pp = pp->next) { + + if (pair[pp->prop_no] == NULL) + return NULL; + + for (pr = pp->head; pr; pr = pr->next) { + newtlen += (sizeof(struct isakmp_pl_p) + + pr->spisize); + + for (tr = pr->head; tr; tr = tr->next) { + for (p = pair[pp->prop_no]; p; p = p->tnext) { + if (tr->trns_no == p->trns->t_no) + break; + } + if (p == NULL) + return NULL; + + newtlen += ntohs(p->trns->h.len); + } + } + } + + newsa = vmalloc(newtlen); + if (newsa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to get newsa.\n"); + return NULL; + } + bp = newsa->v; + + /* some of values of SA must be updated in the out of this function */ + ((struct isakmp_gen *)bp)->len = htons(newtlen); + bp += sizeof(struct ipsecdoi_sa_b); + + /* create proposal payloads */ + for (pp = pp0; pp; pp = pp->next) { + + for (pr = pp->head; pr; pr = pr->next) { + prophlen = sizeof(struct isakmp_pl_p) + + p->prop->spi_size; + + for (tr = pr->head; tr; tr = tr->next) { + for (p = pair[pp->prop_no]; p; p = p->tnext) { + if (tr->trns_no == p->trns->t_no) + break; + } + if (p == NULL) + return NULL; + + trnslen = ntohs(p->trns->h.len); + + if (np_p) + *np_p = ISAKMP_NPTYPE_P; + + /* create proposal */ + + memcpy(bp, p->prop, prophlen); + ((struct isakmp_pl_p *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_p *)bp)->h.len = htons(prophlen + trnslen); + ((struct isakmp_pl_p *)bp)->num_t = 1; + np_p = &((struct isakmp_pl_p *)bp)->h.np; + bp += prophlen; + + /* create transform */ + memcpy(bp, p->trns, trnslen); + ((struct isakmp_pl_t *)bp)->h.np = ISAKMP_NPTYPE_NONE; + ((struct isakmp_pl_t *)bp)->h.len = htons(trnslen); + bp += trnslen; + } + } + } + + return newsa; +} + +/* + * If some error happens then return 0. Although 0 means that lifetime is zero, + * such a value should not be accepted. + * Also 0 of lifebyte should not be included in a packet although 0 means not + * to care of it. + */ +static u_int32_t +ipsecdoi_set_ld(buf) + vchar_t *buf; +{ + u_int32_t ld; + + if (buf == 0) + return 0; + + switch (buf->l) { + case 2: + ld = ntohs(*(u_int16_t *)buf->v); + break; + case 4: + ld = ntohl(*(u_int32_t *)buf->v); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "length %d of life duration " + "isn't supported.\n", buf->l); + return 0; + } + + return ld; +} + +/*%%%*/ +/* + * check DOI + */ +static int +check_doi(doi) + u_int32_t doi; +{ + switch (doi) { + case IPSEC_DOI: + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid value of DOI 0x%08x.\n", doi); + return -1; + } + /* NOT REACHED */ +} + +/* + * check situation + */ +static int +check_situation(sit) + u_int32_t sit; +{ + switch (sit) { + case IPSECDOI_SIT_IDENTITY_ONLY: + return 0; + + case IPSECDOI_SIT_SECRECY: + case IPSECDOI_SIT_INTEGRITY: + plog(LLV_ERROR, LOCATION, NULL, + "situation 0x%08x unsupported yet.\n", sit); + return -1; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid situation 0x%08x.\n", sit); + return -1; + } + /* NOT REACHED */ +} + +/* + * check protocol id in main mode + */ +static int +check_prot_main(proto_id) + int proto_id; +{ + switch (proto_id) { + case IPSECDOI_PROTO_ISAKMP: + return 0; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Illegal protocol id=%u.\n", proto_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check protocol id in quick mode + */ +static int +check_prot_quick(proto_id) + int proto_id; +{ + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_AH: + case IPSECDOI_PROTO_IPSEC_ESP: + return 0; + + case IPSECDOI_PROTO_IPCOMP: + return 0; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid protocol id %d.\n", proto_id); + return -1; + } + /* NOT REACHED */ +} + +static int +check_spi_size(proto_id, size) + int proto_id, size; +{ + switch (proto_id) { + case IPSECDOI_PROTO_ISAKMP: + if (size != 0) { + /* WARNING */ + plog(LLV_WARNING, LOCATION, NULL, + "SPI size isn't zero, but IKE proposal.\n"); + } + return 0; + + case IPSECDOI_PROTO_IPSEC_AH: + case IPSECDOI_PROTO_IPSEC_ESP: + if (size != 4) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid SPI size=%d for IPSEC proposal.\n", + size); + return -1; + } + return 0; + + case IPSECDOI_PROTO_IPCOMP: + if (size != 2 && size != 4) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid SPI size=%d for IPCOMP proposal.\n", + size); + return -1; + } + return 0; + + default: + /* ??? */ + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in ISAKMP. + */ +static int +check_trns_isakmp(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_KEY_IKE: + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in proto_id=%u.\n", + t_id, IPSECDOI_KEY_IKE); + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in AH. + */ +static int +check_trns_ah(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_AH_MD5: + case IPSECDOI_AH_SHA: + return 0; + case IPSECDOI_AH_DES: + plog(LLV_ERROR, LOCATION, NULL, + "not support transform-id=%u in AH.\n", t_id); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in AH.\n", t_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in ESP. + */ +static int +check_trns_esp(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_ESP_DES: + case IPSECDOI_ESP_3DES: + case IPSECDOI_ESP_NULL: + case IPSECDOI_ESP_RC5: + case IPSECDOI_ESP_CAST: + case IPSECDOI_ESP_BLOWFISH: + case IPSECDOI_ESP_RIJNDAEL: + case IPSECDOI_ESP_TWOFISH: + return 0; + case IPSECDOI_ESP_DES_IV32: + case IPSECDOI_ESP_DES_IV64: + case IPSECDOI_ESP_IDEA: + case IPSECDOI_ESP_3IDEA: + case IPSECDOI_ESP_RC4: + plog(LLV_ERROR, LOCATION, NULL, + "not support transform-id=%u in ESP.\n", t_id); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in ESP.\n", t_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check transform ID in IPCOMP. + */ +static int +check_trns_ipcomp(t_id) + int t_id; +{ + switch (t_id) { + case IPSECDOI_IPCOMP_OUI: + case IPSECDOI_IPCOMP_DEFLATE: + case IPSECDOI_IPCOMP_LZS: + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid transform-id=%u in IPCOMP.\n", t_id); + return -1; + } + /* NOT REACHED */ +} + +/* + * check data attributes in IKE. + */ +static int +check_attr_isakmp(trns) + struct isakmp_pl_t *trns; +{ + struct isakmp_data *d; + int tlen; + int flag, type; + u_int16_t lorv; + + tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t); + d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t)); + + while (tlen > 0) { + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + lorv = ntohs(d->lorv); + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_oakley_attr(type), flag, + s_oakley_attr_v(type, lorv)); + + /* + * some of the attributes must be encoded in TV. + * see RFC2409 Appendix A "Attribute Classes". + */ + switch (type) { + case OAKLEY_ATTR_ENC_ALG: + case OAKLEY_ATTR_HASH_ALG: + case OAKLEY_ATTR_AUTH_METHOD: + case OAKLEY_ATTR_GRP_DESC: + case OAKLEY_ATTR_GRP_TYPE: + case OAKLEY_ATTR_SA_LD_TYPE: + case OAKLEY_ATTR_PRF: + case OAKLEY_ATTR_KEY_LEN: + case OAKLEY_ATTR_FIELD_SIZE: + if (!flag) { /* TLV*/ + plog(LLV_ERROR, LOCATION, NULL, + "oakley attribute %d must be TV.\n", + type); + return -1; + } + break; + } + + /* sanity check for TLV. length must be specified. */ + if (!flag && lorv == 0) { /*TLV*/ + plog(LLV_ERROR, LOCATION, NULL, + "invalid length %d for TLV attribute %d.\n", + lorv, type); + return -1; + } + + switch (type) { + case OAKLEY_ATTR_ENC_ALG: + if (!alg_oakley_encdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalied encryption algorithm=%d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_HASH_ALG: + if (!alg_oakley_hashdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalied hash algorithm=%d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_AUTH_METHOD: + switch (lorv) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + plog(LLV_ERROR, LOCATION, NULL, + "auth method %d isn't supported.\n", + lorv); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid auth method %d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_DESC: + if (!alg_oakley_dhdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid DH group %d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_TYPE: + switch (lorv) { + case OAKLEY_ATTR_GRP_TYPE_MODP: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported DH group type %d.\n", + lorv); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_PI: + case OAKLEY_ATTR_GRP_GEN_ONE: + /* sanity checks? */ + break; + + case OAKLEY_ATTR_GRP_GEN_TWO: + case OAKLEY_ATTR_GRP_CURVE_A: + case OAKLEY_ATTR_GRP_CURVE_B: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + case OAKLEY_ATTR_SA_LD_TYPE: + switch (lorv) { + case OAKLEY_ATTR_SA_LD_TYPE_SEC: + case OAKLEY_ATTR_SA_LD_TYPE_KB: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type %d.\n", lorv); + return -1; + } + break; + + case OAKLEY_ATTR_SA_LD: + /* should check the value */ + break; + + case OAKLEY_ATTR_PRF: + case OAKLEY_ATTR_KEY_LEN: + break; + + case OAKLEY_ATTR_FIELD_SIZE: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + case OAKLEY_ATTR_GRP_ORDER: + break; + + case OAKLEY_ATTR_GSS_ID: + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attribute type %d.\n", type); + return -1; + } + + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + lorv); + d = (struct isakmp_data *)((char *)d + + sizeof(*d) + lorv); + } + } + + return 0; +} + +/* + * check data attributes in IPSEC AH/ESP. + */ +static int +check_attr_ah(trns) + struct isakmp_pl_t *trns; +{ + return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_AH, trns); +} + +static int +check_attr_esp(trns) + struct isakmp_pl_t *trns; +{ + return check_attr_ipsec(IPSECDOI_PROTO_IPSEC_ESP, trns); +} + +static int +check_attr_ipsec(proto_id, trns) + int proto_id; + struct isakmp_pl_t *trns; +{ + struct isakmp_data *d; + int tlen; + int flag, type = 0; + u_int16_t lorv; + int attrseen[16]; /* XXX magic number */ + + tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t); + d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t)); + memset(attrseen, 0, sizeof(attrseen)); + + while (tlen > 0) { + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + lorv = ntohs(d->lorv); + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_ipsecdoi_attr(type), flag, + s_ipsecdoi_attr_v(type, lorv)); + + if (type < sizeof(attrseen)/sizeof(attrseen[0])) + attrseen[type]++; + + switch (type) { + case IPSECDOI_ATTR_ENC_MODE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when ENC_MODE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_ENC_MODE_TUNNEL: + case IPSECDOI_ATTR_ENC_MODE_TRNS: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption mode=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_AUTH: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when AUTH.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_AUTH_HMAC_MD5: + if (proto_id == IPSECDOI_PROTO_IPSEC_AH + && trns->t_id != IPSECDOI_AH_MD5) { +ahmismatch: + plog(LLV_ERROR, LOCATION, NULL, + "auth algorithm %u conflicts " + "with transform %u.\n", + lorv, trns->t_id); + return -1; + } + break; + case IPSECDOI_ATTR_AUTH_HMAC_SHA1: + if (proto_id == IPSECDOI_PROTO_IPSEC_AH) { + if (trns->t_id != IPSECDOI_AH_SHA) + goto ahmismatch; + } + break; + case IPSECDOI_ATTR_AUTH_DES_MAC: + case IPSECDOI_ATTR_AUTH_KPDK: + plog(LLV_ERROR, LOCATION, NULL, + "auth algorithm %u isn't supported.\n", + lorv); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid auth algorithm=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD_TYPE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when LD_TYPE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type %d.\n", lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD: + if (flag) { + /* i.e. ISAKMP_GEN_TV */ + plog(LLV_DEBUG, LOCATION, NULL, + "life duration was in TLV.\n"); + } else { + /* i.e. ISAKMP_GEN_TLV */ + if (lorv == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid length of LD\n"); + return -1; + } + } + break; + + case IPSECDOI_ATTR_GRP_DESC: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when GRP_DESC.\n"); + return -1; + } + + if (!alg_oakley_dhdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid group description=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_KEY_LENGTH: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when KEY_LENGTH.\n"); + return -1; + } + break; + + case IPSECDOI_ATTR_KEY_ROUNDS: + case IPSECDOI_ATTR_COMP_DICT_SIZE: + case IPSECDOI_ATTR_COMP_PRIVALG: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attribute type %d.\n", type); + return -1; + } + + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + lorv); + d = (struct isakmp_data *)((caddr_t)d + + sizeof(*d) + lorv); + } + } + + if (proto_id == IPSECDOI_PROTO_IPSEC_AH + && !attrseen[IPSECDOI_ATTR_AUTH]) { + plog(LLV_ERROR, LOCATION, NULL, + "attr AUTH must be present for AH.\n", type); + return -1; + } + + return 0; +} + +static int +check_attr_ipcomp(trns) + struct isakmp_pl_t *trns; +{ + struct isakmp_data *d; + int tlen; + int flag, type = 0; + u_int16_t lorv; + int attrseen[16]; /* XXX magic number */ + + tlen = ntohs(trns->h.len) - sizeof(struct isakmp_pl_t); + d = (struct isakmp_data *)((caddr_t)trns + sizeof(struct isakmp_pl_t)); + memset(attrseen, 0, sizeof(attrseen)); + + while (tlen > 0) { + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + lorv = ntohs(d->lorv); + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%d, flag=0x%04x, lorv=0x%04x\n", + type, flag, lorv); + + if (type < sizeof(attrseen)/sizeof(attrseen[0])) + attrseen[type]++; + + switch (type) { + case IPSECDOI_ATTR_ENC_MODE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when ENC_MODE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_ENC_MODE_TUNNEL: + case IPSECDOI_ATTR_ENC_MODE_TRNS: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption mode=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD_TYPE: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when LD_TYPE.\n"); + return -1; + } + + switch (lorv) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type %d.\n", lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_SA_LD: + if (flag) { + /* i.e. ISAKMP_GEN_TV */ + plog(LLV_DEBUG, LOCATION, NULL, + "life duration was in TLV.\n"); + } else { + /* i.e. ISAKMP_GEN_TLV */ + if (lorv == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid length of LD\n"); + return -1; + } + } + break; + + case IPSECDOI_ATTR_GRP_DESC: + if (! flag) { + plog(LLV_ERROR, LOCATION, NULL, + "must be TV when GRP_DESC.\n"); + return -1; + } + + if (!alg_oakley_dhdef_ok(lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid group description=%u.\n", + lorv); + return -1; + } + break; + + case IPSECDOI_ATTR_AUTH: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attr type=%u.\n", type); + return -1; + + case IPSECDOI_ATTR_KEY_LENGTH: + case IPSECDOI_ATTR_KEY_ROUNDS: + case IPSECDOI_ATTR_COMP_DICT_SIZE: + case IPSECDOI_ATTR_COMP_PRIVALG: + plog(LLV_ERROR, LOCATION, NULL, + "attr type=%u isn't supported.\n", type); + return -1; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid attribute type %d.\n", type); + return -1; + } + + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + lorv); + d = (struct isakmp_data *)((caddr_t)d + + sizeof(*d) + lorv); + } + } + +#if 0 + if (proto_id == IPSECDOI_PROTO_IPCOMP + && !attrseen[IPSECDOI_ATTR_AUTH]) { + plog(LLV_ERROR, LOCATION, NULL, + "attr AUTH must be present for AH.\n", type); + return -1; + } +#endif + + return 0; +} + +/* %%% */ +/* + * create phase1 proposal from remote configuration. + * NOT INCLUDING isakmp general header of SA payload + */ +vchar_t * +ipsecdoi_setph1proposal(props) + struct isakmpsa *props; +{ + vchar_t *mysa; + int sablen; + + /* count total size of SA minus isakmp general header */ + /* not including isakmp general header of SA payload */ + sablen = sizeof(struct ipsecdoi_sa_b); + sablen += setph1prop(props, NULL); + + mysa = vmalloc(sablen); + if (mysa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate my sa buffer\n"); + return NULL; + } + + /* create SA payload */ + /* not including isakmp general header */ + ((struct ipsecdoi_sa_b *)mysa->v)->doi = htonl(props->rmconf->doitype); + ((struct ipsecdoi_sa_b *)mysa->v)->sit = htonl(props->rmconf->sittype); + + (void)setph1prop(props, mysa->v + sizeof(struct ipsecdoi_sa_b)); + + return mysa; +} + +static int +setph1prop(props, buf) + struct isakmpsa *props; + caddr_t buf; +{ + struct isakmp_pl_p *prop = NULL; + struct isakmpsa *s = NULL; + int proplen, trnslen; + u_int8_t *np_t; /* pointer next trns type in previous header */ + int trns_num; + caddr_t p = buf; + + proplen = sizeof(*prop); + if (buf) { + /* create proposal */ + prop = (struct isakmp_pl_p *)p; + prop->h.np = ISAKMP_NPTYPE_NONE; + prop->p_no = props->prop_no; + prop->proto_id = IPSECDOI_PROTO_ISAKMP; + prop->spi_size = 0; + p += sizeof(*prop); + } + + np_t = NULL; + trns_num = 0; + + for (s = props; s != NULL; s = s->next) { + if (np_t) + *np_t = ISAKMP_NPTYPE_T; + + trnslen = setph1trns(s, p); + proplen += trnslen; + if (buf) { + /* save buffer to pre-next payload */ + np_t = &((struct isakmp_pl_t *)p)->h.np; + p += trnslen; + + /* count up transform length */ + trns_num++; + } + } + + /* update proposal length */ + if (buf) { + prop->h.len = htons(proplen); + prop->num_t = trns_num; + } + + return proplen; +} + +static int +setph1trns(sa, buf) + struct isakmpsa *sa; + caddr_t buf; +{ + struct isakmp_pl_t *trns = NULL; + int trnslen, attrlen; + caddr_t p = buf; + + trnslen = sizeof(*trns); + if (buf) { + /* create transform */ + trns = (struct isakmp_pl_t *)p; + trns->h.np = ISAKMP_NPTYPE_NONE; + trns->t_no = sa->trns_no; + trns->t_id = IPSECDOI_KEY_IKE; + p += sizeof(*trns); + } + + attrlen = setph1attr(sa, p); + trnslen += attrlen; + if (buf) + p += attrlen; + + if (buf) + trns->h.len = htons(trnslen); + + return trnslen; +} + +static int +setph1attr(sa, buf) + struct isakmpsa *sa; + caddr_t buf; +{ + caddr_t p = buf; + int attrlen = 0; + + if (sa->lifetime) { + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (sa->lifetime > 0xffff) + attrlen += sizeof(sa->lifetime); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE, + OAKLEY_ATTR_SA_LD_TYPE_SEC); + if (sa->lifetime > 0xffff) { + u_int32_t v = htonl((u_int32_t)sa->lifetime); + p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + } else { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD, + sa->lifetime); + } + } + } + + if (sa->lifebyte) { + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (sa->lifebyte > 0xffff) + attrlen += sizeof(sa->lifebyte); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD_TYPE, + OAKLEY_ATTR_SA_LD_TYPE_KB); + if (sa->lifebyte > 0xffff) { + u_int32_t v = htonl((u_int32_t)sa->lifebyte); + p = isakmp_set_attr_v(p, OAKLEY_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + } else { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_SA_LD, + sa->lifebyte); + } + } + } + + if (sa->enctype) { + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_ENC_ALG, sa->enctype); + } + if (sa->encklen) { + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_KEY_LEN, sa->encklen); + } + if (sa->authmethod) { + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_AUTH_METHOD, sa->authmethod); + } + if (sa->hashtype) { + attrlen += sizeof(struct isakmp_data); + if (buf) + p = isakmp_set_attr_l(p, OAKLEY_ATTR_HASH_ALG, sa->hashtype); + } + switch (sa->dh_group) { + case OAKLEY_ATTR_GRP_DESC_MODP768: + case OAKLEY_ATTR_GRP_DESC_MODP1024: + case OAKLEY_ATTR_GRP_DESC_MODP1536: + case OAKLEY_ATTR_GRP_DESC_MODP2048: + case OAKLEY_ATTR_GRP_DESC_MODP3072: + case OAKLEY_ATTR_GRP_DESC_MODP4096: + case OAKLEY_ATTR_GRP_DESC_MODP6144: + case OAKLEY_ATTR_GRP_DESC_MODP8192: + /* don't attach group type for known groups */ + attrlen += sizeof(struct isakmp_data); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_DESC, + sa->dh_group); + } + break; + case OAKLEY_ATTR_GRP_DESC_EC2N155: + case OAKLEY_ATTR_GRP_DESC_EC2N185: + /* don't attach group type for known groups */ + attrlen += sizeof(struct isakmp_data); + if (buf) { + p = isakmp_set_attr_l(p, OAKLEY_ATTR_GRP_TYPE, + OAKLEY_ATTR_GRP_TYPE_EC2N); + } + break; + case 0: + default: + break; + } + +#ifdef HAVE_GSSAPI + if (sa->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + sa->gssid != NULL) { + attrlen += sizeof(struct isakmp_data); + attrlen += sa->gssid->l; + if (buf) { + plog(LLV_DEBUG, LOCATION, NULL, "gss id attr: len %d, " + "val '%s'\n", sa->gssid->l, sa->gssid->v); + p = isakmp_set_attr_v(p, OAKLEY_ATTR_GSS_ID, + (caddr_t)sa->gssid->v, + sa->gssid->l); + } + } +#endif + + return attrlen; +} + +static vchar_t * +setph2proposal0(iph2, pp, pr) + const struct ph2handle *iph2; + const struct saprop *pp; + const struct saproto *pr; +{ + vchar_t *p; + struct isakmp_pl_p *prop; + struct isakmp_pl_t *trns; + struct satrns *tr; + int attrlen; + size_t trnsoff; + caddr_t x0, x; + u_int8_t *np_t; /* pointer next trns type in previous header */ + const u_int8_t *spi; + + p = vmalloc(sizeof(*prop) + sizeof(pr->spi)); + if (p == NULL) + return NULL; + + /* create proposal */ + prop = (struct isakmp_pl_p *)p->v; + prop->h.np = ISAKMP_NPTYPE_NONE; + prop->p_no = pp->prop_no; + prop->proto_id = pr->proto_id; + prop->num_t = 1; + + spi = (const u_int8_t *)&pr->spi; + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPCOMP: + /* + * draft-shacham-ippcp-rfc2393bis-05.txt: + * construct 16bit SPI (CPI). + * XXX we may need to provide a configuration option to + * generate 32bit SPI. otherwise we cannot interoeprate + * with nodes that uses 32bit SPI, in case we are initiator. + */ + prop->spi_size = sizeof(u_int16_t); + spi += sizeof(pr->spi) - sizeof(u_int16_t); + p->l -= sizeof(pr->spi); + p->l += sizeof(u_int16_t); + break; + default: + prop->spi_size = sizeof(pr->spi); + break; + } + memcpy(prop + 1, spi, prop->spi_size); + + /* create transform */ + trnsoff = sizeof(*prop) + prop->spi_size; + np_t = NULL; + + for (tr = pr->head; tr; tr = tr->next) { + + if (np_t) { + *np_t = ISAKMP_NPTYPE_T; + prop->num_t++; + } + + /* get attribute length */ + attrlen = 0; + if (pp->lifetime) { + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (pp->lifetime > 0xffff) + attrlen += sizeof(u_int32_t); + } + if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) { + attrlen += sizeof(struct isakmp_data) + + sizeof(struct isakmp_data); + if (pp->lifebyte > 0xffff) + attrlen += sizeof(u_int32_t); + } + attrlen += sizeof(struct isakmp_data); /* enc mode */ + if (tr->encklen) + attrlen += sizeof(struct isakmp_data); + + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + /* non authentication mode ? */ + if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE) + attrlen += sizeof(struct isakmp_data); + break; + case IPSECDOI_PROTO_IPSEC_AH: + if (tr->authtype == IPSECDOI_ATTR_AUTH_NONE) { + plog(LLV_ERROR, LOCATION, NULL, + "no authentication algorithm found " + "but protocol is AH.\n"); + vfree(p); + return NULL; + } + attrlen += sizeof(struct isakmp_data); + break; + case IPSECDOI_PROTO_IPCOMP: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid protocol: %d\n", pr->proto_id); + vfree(p); + return NULL; + } + + if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group)) + attrlen += sizeof(struct isakmp_data); + + p = vrealloc(p, p->l + sizeof(*trns) + attrlen); + if (p == NULL) + return NULL; + prop = (struct isakmp_pl_p *)p->v; + + /* set transform's values */ + trns = (struct isakmp_pl_t *)(p->v + trnsoff); + trns->h.np = ISAKMP_NPTYPE_NONE; + trns->t_no = tr->trns_no; + trns->t_id = tr->trns_id; + + /* set attributes */ + x = x0 = p->v + trnsoff + sizeof(*trns); + + if (pp->lifetime) { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_SEC); + if (pp->lifetime > 0xffff) { + u_int32_t v = htonl((u_int32_t)pp->lifetime); + x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + } else { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD, + pp->lifetime); + } + } + + if (pp->lifebyte && pp->lifebyte != IPSECDOI_ATTR_SA_LD_KB_MAX) { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_KB); + if (pp->lifebyte > 0xffff) { + u_int32_t v = htonl((u_int32_t)pp->lifebyte); + x = isakmp_set_attr_v(x, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + } else { + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_SA_LD, + pp->lifebyte); + } + } + + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_ENC_MODE, pr->encmode); + + if (tr->encklen) + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_KEY_LENGTH, tr->encklen); + + /* mandatory check has done above. */ + if ((pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP && tr->authtype != IPSECDOI_ATTR_AUTH_NONE) + || pr->proto_id == IPSECDOI_PROTO_IPSEC_AH) + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_AUTH, tr->authtype); + + if (alg_oakley_dhdef_ok(iph2->sainfo->pfs_group)) + x = isakmp_set_attr_l(x, IPSECDOI_ATTR_GRP_DESC, + iph2->sainfo->pfs_group); + + /* update length of this transform. */ + trns = (struct isakmp_pl_t *)(p->v + trnsoff); + trns->h.len = htons(sizeof(*trns) + attrlen); + + /* save buffer to pre-next payload */ + np_t = &trns->h.np; + + trnsoff += (sizeof(*trns) + attrlen); + } + + /* update length of this protocol. */ + prop->h.len = htons(p->l); + + return p; +} + +/* + * create phase2 proposal from policy configuration. + * NOT INCLUDING isakmp general header of SA payload. + * This function is called by initiator only. + */ +int +ipsecdoi_setph2proposal(iph2) + struct ph2handle *iph2; +{ + struct saprop *proposal, *a; + struct saproto *b = NULL; + vchar_t *q; + struct ipsecdoi_sa_b *sab; + struct isakmp_pl_p *prop; + size_t propoff; /* for previous field of type of next payload. */ + + proposal = iph2->proposal; + + iph2->sa = vmalloc(sizeof(*sab)); + if (iph2->sa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate my sa buffer\n"); + return -1; + } + + /* create SA payload */ + sab = (struct ipsecdoi_sa_b *)iph2->sa->v; + sab->doi = htonl(IPSEC_DOI); + sab->sit = htonl(IPSECDOI_SIT_IDENTITY_ONLY); /* XXX configurable ? */ + + prop = NULL; + propoff = 0; + for (a = proposal; a; a = a->next) { + for (b = a->head; b; b = b->next) { + q = setph2proposal0(iph2, a, b); + if (q == NULL) { + vfree(iph2->sa); + return -1; + } + + iph2->sa = vrealloc(iph2->sa, iph2->sa->l + q->l); + if (iph2->sa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate my sa buffer\n"); + if (q) + vfree(q); + return -1; + } + memcpy(iph2->sa->v + iph2->sa->l - q->l, q->v, q->l); + if (propoff != 0) { + prop = (struct isakmp_pl_p *)(iph2->sa->v + + propoff); + prop->h.np = ISAKMP_NPTYPE_P; + } + propoff = iph2->sa->l - q->l; + + vfree(q); + } + } + + return 0; +} + +/* + * return 1 if all of the proposed protocols are transport mode. + */ +int +ipsecdoi_transportmode(iph2) + struct ph2handle *iph2; +{ + struct saprop *pp; + struct saproto *pr = NULL; + + for (pp = iph2->proposal; pp; pp = pp->next) { + for (pr = pp->head; pr; pr = pr->next) { + if (pr->encmode != IPSECDOI_ATTR_ENC_MODE_TRNS) + return 0; + } + } + + return 1; +} + +int +ipsecdoi_get_defaultlifetime() +{ + return IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; +} + +int +ipsecdoi_checkalgtypes(proto_id, enc, auth, comp) + int proto_id, enc, auth, comp; +{ +#define TMPALGTYPE2STR(n) s_algtype(algclass_ipsec_##n, n) + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + if (enc == 0 || comp != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "illegal algorithm defined " + "ESP enc=%s auth=%s comp=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(auth), + TMPALGTYPE2STR(comp)); + return -1; + } + break; + case IPSECDOI_PROTO_IPSEC_AH: + if (enc != 0 || auth == 0 || comp != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "illegal algorithm defined " + "AH enc=%s auth=%s comp=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(auth), + TMPALGTYPE2STR(comp)); + return -1; + } + break; + case IPSECDOI_PROTO_IPCOMP: + if (enc != 0 || auth != 0 || comp == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "illegal algorithm defined " + "IPcomp enc=%s auth=%s comp=%s.\n", + TMPALGTYPE2STR(enc), + TMPALGTYPE2STR(auth), + TMPALGTYPE2STR(comp)); + return -1; + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid ipsec protocol %d\n", proto_id); + return -1; + } +#undef TMPALGTYPE2STR + return 0; +} + +int +ipproto2doi(proto) + int proto; +{ + switch (proto) { + case IPPROTO_AH: + return IPSECDOI_PROTO_IPSEC_AH; + case IPPROTO_ESP: + return IPSECDOI_PROTO_IPSEC_ESP; + case IPPROTO_IPCOMP: + return IPSECDOI_PROTO_IPCOMP; + } + return -1; /* XXX */ +} + +int +doi2ipproto(proto) + int proto; +{ + switch (proto) { + case IPSECDOI_PROTO_IPSEC_AH: + return IPPROTO_AH; + case IPSECDOI_PROTO_IPSEC_ESP: + return IPPROTO_ESP; + case IPSECDOI_PROTO_IPCOMP: + return IPPROTO_IPCOMP; + } + return -1; /* XXX */ +} + +/* + * check the following: + * - In main mode with pre-shared key, only address type can be used. + * - if proper type for phase 1 ? + * - if phase 1 ID payload conformed RFC2407 4.6.2. + * (proto, port) must be (0, 0), (udp, 500) or (udp, [specified]). + * - if ID payload sent from peer is equal to the ID expected by me. + * + * both of "id" and "id_p" should be ID payload without general header, + */ +int +ipsecdoi_checkid1(iph1) + struct ph1handle *iph1; +{ + struct ipsecdoi_id_b *id_b; + + if (iph1->id_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid iph1 passed id_p == NULL\n"); + return ISAKMP_INTERNAL_ERROR; + } + if (iph1->id_p->l < sizeof(*id_b)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid value passed as \"ident\" (len=%lu)\n", + (u_long)iph1->id_p->l); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; + + /* In main mode with pre-shared key, only address type can be used. */ + if (iph1->etype == ISAKMP_ETYPE_IDENT + && iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_PSKEY) { + if (id_b->type != IPSECDOI_ID_IPV4_ADDR + && id_b->type != IPSECDOI_ID_IPV6_ADDR) { + plog(LLV_ERROR, LOCATION, NULL, + "Expecting IP address type in main mode, " + "but %s.\n", s_ipsecdoi_ident(id_b->type)); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + } + + /* if proper type for phase 1 ? */ + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + plog(LLV_WARNING, LOCATION, NULL, + "such ID type %s is not proper.\n", + s_ipsecdoi_ident(id_b->type)); + /*FALLTHROUGH*/ + } + + /* if phase 1 ID payload conformed RFC2407 4.6.2. */ + if (id_b->type == IPSECDOI_ID_IPV4_ADDR + && id_b->type == IPSECDOI_ID_IPV6_ADDR) { + + if (id_b->proto_id == 0 && ntohs(id_b->port) != 0) { + plog(LLV_WARNING, LOCATION, NULL, + "protocol ID and Port mismatched. " + "proto_id:%d port:%d\n", + id_b->proto_id, ntohs(id_b->port)); + /*FALLTHROUGH*/ + + } else if (id_b->proto_id == IPPROTO_UDP) { + /* + * copmaring with expecting port. + * always permit if port is equal to PORT_ISAKMP + */ + if (ntohs(id_b->port) != PORT_ISAKMP) { + + u_int16_t port; + + switch (iph1->remote->sa_family) { + case AF_INET: + port = ((struct sockaddr_in *)iph1->remote)->sin_port; + break; +#ifdef INET6 + case AF_INET6: + port = ((struct sockaddr_in6 *)iph1->remote)->sin6_port; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", + iph1->remote->sa_family); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + if (ntohs(id_b->port) != port) { + plog(LLV_WARNING, LOCATION, NULL, + "port %d expected, but %d\n", + port, ntohs(id_b->port)); + /*FALLTHROUGH*/ + } + } + } + } + + /* compare with the ID if specified. */ + if (iph1->rmconf->idv_p) { + vchar_t *ident0 = NULL; + vchar_t ident; + + /* check the type of both IDs */ + if (iph1->rmconf->idvtype_p != doi2idtype(id_b->type)) { + plog(LLV_WARNING, LOCATION, NULL, + "ID type mismatched.\n"); + if (iph1->rmconf->verify_identifier) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + /* compare defined ID with the ID sent by peer. */ + ident0 = getidval(iph1->rmconf->idvtype_p, iph1->rmconf->idv_p); + + switch (iph1->rmconf->idvtype_p) { + case IDTYPE_ASN1DN: + ident.v = (caddr_t)(id_b + 1); + ident.l = ident0->l; + if (eay_cmp_asn1dn(ident0, &ident)) { + plog(LLV_WARNING, LOCATION, NULL, + "ID value mismatched.\n"); + if (iph1->rmconf->verify_identifier) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + break; + default: + if (memcmp(ident0->v, id_b + 1, ident0->l)) { + plog(LLV_WARNING, LOCATION, NULL, + "ID value mismatched.\n"); + if (iph1->rmconf->verify_identifier) + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + break; + } + vfree(ident0); + } + + return 0; +} + +/* + * create ID payload for phase 1 and set into iph1->id. + * NOT INCLUDING isakmp general header. + * see, RFC2407 4.6.2.1 + */ +int +ipsecdoi_setid1(iph1) + struct ph1handle *iph1; +{ + vchar_t *ret = NULL; + struct ipsecdoi_id_b id_b; + vchar_t *ident = NULL; + struct sockaddr *ipid = NULL; + + /* init */ + id_b.proto_id = 0; + id_b.port = 0; + ident = NULL; + + switch (iph1->rmconf->idvtype) { + case IDTYPE_FQDN: + id_b.type = IPSECDOI_ID_FQDN; + ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + break; + case IDTYPE_USERFQDN: + id_b.type = IPSECDOI_ID_USER_FQDN; + ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + break; + case IDTYPE_KEYID: + id_b.type = IPSECDOI_ID_KEY_ID; + ident = getidval(iph1->rmconf->idvtype, iph1->rmconf->idv); + break; +#ifdef HAVE_SIGNING_C + case IDTYPE_ASN1DN: + id_b.type = IPSECDOI_ID_DER_ASN1_DN; + if (iph1->rmconf->idv) { + /* XXX it must be encoded to asn1dn. */ + ident = vdup(iph1->rmconf->idv); + } else { + if (oakley_getmycert(iph1) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get own CERT.\n"); + goto err; + } + ident = eay_get_x509asn1subjectname(&iph1->cert->cert); + } + break; +#endif + case IDTYPE_ADDRESS: + /* + * if the value of the id type was set by the configuration + * file, then use it. otherwise the value is get from local + * ip address by using ike negotiation. + */ + if (iph1->rmconf->idv) + ipid = (struct sockaddr *)iph1->rmconf->idv->v; + /*FALLTHROUGH*/ + default: + { + int l; + caddr_t p; + + if (ipid == NULL) + ipid = iph1->local; + + /* use IP address */ + switch (ipid->sa_family) { + case AF_INET: + id_b.type = IPSECDOI_ID_IPV4_ADDR; + l = sizeof(struct in_addr); + p = (caddr_t)&((struct sockaddr_in *)ipid)->sin_addr; + break; +#ifdef INET6 + case AF_INET6: + id_b.type = IPSECDOI_ID_IPV6_ADDR; + l = sizeof(struct in6_addr); + p = (caddr_t)&((struct sockaddr_in6 *)ipid)->sin6_addr; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid address family.\n"); + goto err; + } + id_b.proto_id = IPPROTO_UDP; + id_b.port = htons(PORT_ISAKMP); + ident = vmalloc(l); + if (!ident) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + return 0; + } + memcpy(ident->v, p, ident->l); + } + } + if (!ident) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + return 0; + } + + ret = vmalloc(sizeof(id_b) + ident->l); + if (ret == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + goto err; + } + + memcpy(ret->v, &id_b, sizeof(id_b)); + memcpy(ret->v + sizeof(id_b), ident->v, ident->l); + + iph1->id = ret; + + plog(LLV_DEBUG, LOCATION, NULL, + "use ID type of %s\n", s_ipsecdoi_ident(id_b.type)); + if (ident) + vfree(ident); + return 0; + +err: + if (ident) + vfree(ident); + plog(LLV_ERROR, LOCATION, NULL, "failed get my ID\n"); + return -1; +} + +static vchar_t * +getidval(type, val) + int type; + vchar_t *val; +{ + vchar_t *new = NULL; + + if (val) + new = vdup(val); + else if (lcconf->ident[type]) + new = vdup(lcconf->ident[type]); + + return new; +} + +/* it's only called by cfparse.y. */ +int +set_identifier(vpp, type, value) + vchar_t **vpp, *value; + int type; +{ + vchar_t *new = NULL; + + /* simply return if value is null. */ + if (!value) + return 0; + + switch (type) { + case IDTYPE_FQDN: + case IDTYPE_USERFQDN: + /* length is adjusted since QUOTEDSTRING teminates NULL. */ + new = vmalloc(value->l - 1); + if (new == NULL) + return -1; + memcpy(new->v, value->v, new->l); + break; + case IDTYPE_KEYID: + { + FILE *fp; + char b[512]; + int tlen, len; + + fp = fopen(value->v, "r"); + if (fp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "can not open %s\n", value->v); + return -1; + } + tlen = 0; + while ((len = fread(b, 1, sizeof(b), fp)) != 0) { + new = vrealloc(new, tlen + len); + if (!new) { + fclose(fp); + return -1; + } + memcpy(new->v + tlen, b, len); + tlen += len; + } + break; + } + case IDTYPE_ADDRESS: + { + struct sockaddr *sa; + + /* length is adjusted since QUOTEDSTRING teminates NULL. */ + if (value->l == 0) + break; + + sa = str2saddr(value->v, NULL); + if (sa == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid ip address %s\n", value->v); + return -1; + } + + new = vmalloc(sa->sa_len); + if (new == NULL) + return -1; + memcpy(new->v, sa, new->l); + break; + } + case IDTYPE_ASN1DN: + new = eay_str2asn1dn(value->v, value->l - 1); + if (new == NULL) + return -1; + break; + } + + *vpp = new; + + return 0; +} + +/* + * create ID payload for phase 2, and set into iph2->id and id_p. There are + * NOT INCLUDING isakmp general header. + * this function is for initiator. responder will get to copy from payload. + * responder ID type is always address type. + * see, RFC2407 4.6.2.1 + */ +int +ipsecdoi_setid2(iph2) + struct ph2handle *iph2; +{ + struct secpolicy *sp; + + /* check there is phase 2 handler ? */ + sp = getspbyspid(iph2->spid); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no policy found for spid:%lu.\n", iph2->spid); + return -1; + } + + if (!iph2->sainfo->idv) { + iph2->id = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.src, + sp->spidx.prefs, sp->spidx.ul_proto); + if (iph2->id == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp->spidx)); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, "use local ID type %s\n", + s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id->v)->type)); + } else { + struct ipsecdoi_id_b id_b; + vchar_t *ident; + + id_b.type = idtype2doi(iph2->sainfo->idvtype); + id_b.proto_id = 0; + id_b.port = 0; + + ident = getidval(iph2->sainfo->idvtype, iph2->sainfo->idv); + if (!ident) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID value.\n"); + return -1; + } + iph2->id = vmalloc(sizeof(id_b) + ident->l); + if (iph2->id == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + vfree(ident); + return -1; + } + + memcpy(iph2->id->v, &id_b, sizeof(id_b)); + memcpy(iph2->id->v + sizeof(id_b), ident->v, ident->l); + vfree(ident); + } + + /* remote side */ + iph2->id_p = ipsecdoi_sockaddr2id((struct sockaddr *)&sp->spidx.dst, + sp->spidx.prefd, sp->spidx.ul_proto); + if (iph2->id_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp->spidx)); + vfree(iph2->id); + iph2->id = NULL; + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "use remote ID type %s\n", + s_ipsecdoi_ident(((struct ipsecdoi_id_b *)iph2->id_p->v)->type)); + + return 0; +} + +/* + * set address type of ID. + * NOT INCLUDING general header. + */ +vchar_t * +ipsecdoi_sockaddr2id(saddr, prefixlen, ul_proto) + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + vchar_t *new; + int type, len1, len2; + caddr_t sa; + u_short port; + + /* + * Q. When type is SUBNET, is it allowed to be ::1/128. + * A. Yes. (consensus at bake-off) + */ + switch (saddr->sa_family) { + case AF_INET: + len1 = sizeof(struct in_addr); + if (prefixlen == (sizeof(struct in_addr) << 3)) { + type = IPSECDOI_ID_IPV4_ADDR; + len2 = 0; + } else { + type = IPSECDOI_ID_IPV4_ADDR_SUBNET; + len2 = sizeof(struct in_addr); + } + sa = (caddr_t)&((struct sockaddr_in *)(saddr))->sin_addr; + port = ((struct sockaddr_in *)(saddr))->sin_port; + break; +#ifdef INET6 + case AF_INET6: + len1 = sizeof(struct in6_addr); + if (prefixlen == (sizeof(struct in6_addr) << 3)) { + type = IPSECDOI_ID_IPV6_ADDR; + len2 = 0; + } else { + type = IPSECDOI_ID_IPV6_ADDR_SUBNET; + len2 = sizeof(struct in6_addr); + } + sa = (caddr_t)&((struct sockaddr_in6 *)(saddr))->sin6_addr; + port = ((struct sockaddr_in6 *)(saddr))->sin6_port; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d.\n", saddr->sa_family); + return NULL; + } + + /* get ID buffer */ + new = vmalloc(sizeof(struct ipsecdoi_id_b) + len1 + len2); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID buffer.\n"); + return NULL; + } + + memset(new->v, 0, new->l); + + /* set the part of header. */ + ((struct ipsecdoi_id_b *)new->v)->type = type; + + /* set ul_proto and port */ + /* + * NOTE: we use both IPSEC_ULPROTO_ANY and IPSEC_PORT_ANY as wild card + * because 0 means port number of 0. Instead of 0, we use IPSEC_*_ANY. + */ + ((struct ipsecdoi_id_b *)new->v)->proto_id = + ul_proto == IPSEC_ULPROTO_ANY ? 0 : ul_proto; + ((struct ipsecdoi_id_b *)new->v)->port = + port == IPSEC_PORT_ANY ? 0 : port; + memcpy(new->v + sizeof(struct ipsecdoi_id_b), sa, len1); + + /* set address */ + + /* set prefix */ + if (len2) { + u_char *p = new->v + sizeof(struct ipsecdoi_id_b) + len1; + u_int bits = prefixlen; + + while (bits >= 8) { + *p++ = 0xff; + bits -= 8; + } + + if (bits > 0) + *p = ~((1 << (8 - bits)) - 1); + } + + return new; +} + +/* + * create sockaddr structure from ID payload (buf). + * buffers (saddr, prefixlen, ul_proto) must be allocated. + * see, RFC2407 4.6.2.1 + */ +int +ipsecdoi_id2sockaddr(buf, saddr, prefixlen, ul_proto) + vchar_t *buf; + struct sockaddr *saddr; + u_int8_t *prefixlen; + u_int16_t *ul_proto; +{ + struct ipsecdoi_id_b *id_b = (struct ipsecdoi_id_b *)buf->v; + u_int plen = 0; + + /* + * When a ID payload of subnet type with a IP address of full bit + * masked, it has to be processed as host address. + * e.g. below 2 type are same. + * type = ipv6 subnet, data = 2001::1/128 + * type = ipv6 address, data = 2001::1 + */ + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + saddr->sa_len = sizeof(struct sockaddr_in); + saddr->sa_family = AF_INET; + ((struct sockaddr_in *)saddr)->sin_port = + (id_b->port == 0 + ? IPSEC_PORT_ANY + : id_b->port); /* see sockaddr2id() */ + memcpy(&((struct sockaddr_in *)saddr)->sin_addr, + buf->v + sizeof(*id_b), sizeof(struct in_addr)); + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + saddr->sa_len = sizeof(struct sockaddr_in6); + saddr->sa_family = AF_INET6; + ((struct sockaddr_in6 *)saddr)->sin6_port = + (id_b->port == 0 + ? IPSEC_PORT_ANY + : id_b->port); /* see sockaddr2id() */ + memcpy(&((struct sockaddr_in6 *)saddr)->sin6_addr, + buf->v + sizeof(*id_b), sizeof(struct in6_addr)); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported ID type %d\n", id_b->type); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + /* get prefix length */ + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + case IPSECDOI_ID_IPV4_ADDR_SUBNET: +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_SUBNET: +#endif + { + u_char *p; + u_int max; + int alen = sizeof(struct in_addr); + + switch (id_b->type) { + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + alen = sizeof(struct in_addr); + break; +#ifdef INET6 + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + alen = sizeof(struct in6_addr); + break; +#endif + } + + /* sanity check */ + if (buf->l < alen) + return ISAKMP_INTERNAL_ERROR; + + /* get subnet mask length */ + plen = 0; + max = alen <<3; + + p = buf->v + + sizeof(struct ipsecdoi_id_b) + + alen; + + for (; *p == 0xff; p++) { + if (plen >= max) + break; + plen += 8; + } + + if (plen < max) { + u_int l = 0; + u_char b = ~(*p); + + while (b) { + b >>= 1; + l++; + } + + l = 8 - l; + plen += l; + } + } + break; + } + + *prefixlen = plen; + *ul_proto = id_b->proto_id == 0 + ? IPSEC_ULPROTO_ANY + : id_b->proto_id; /* see sockaddr2id() */ + + return 0; +} + +/* + * make printable string from ID payload except of general header. + */ +const char * +ipsecdoi_id2str(id) + const vchar_t *id; +{ + static char buf[256]; + + /* XXX */ + buf[0] = '\0'; + + return buf; +} + +/* + * set IPsec data attributes into a proposal. + * NOTE: MUST called per a transform. + */ +int +ipsecdoi_t2satrns(t, pp, pr, tr) + struct isakmp_pl_t *t; + struct saprop *pp; + struct saproto *pr; + struct satrns *tr; +{ + struct isakmp_data *d, *prev; + int flag, type; + int error = -1; + int life_t; + int tlen; + + tr->trns_no = t->t_no; + tr->trns_id = t->t_id; + + tlen = ntohs(t->h.len) - sizeof(*t); + prev = (struct isakmp_data *)NULL; + d = (struct isakmp_data *)(t + 1); + + /* default */ + life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT; + pp->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; + pp->lifebyte = 0; + tr->authtype = IPSECDOI_ATTR_AUTH_NONE; + + while (tlen > 0) { + + type = ntohs(d->type) & ~ISAKMP_GEN_MASK; + flag = ntohs(d->type) & ISAKMP_GEN_MASK; + + plog(LLV_DEBUG, LOCATION, NULL, + "type=%s, flag=0x%04x, lorv=%s\n", + s_ipsecdoi_attr(type), flag, + s_ipsecdoi_attr_v(type, ntohs(d->lorv))); + + switch (type) { + case IPSECDOI_ATTR_SA_LD_TYPE: + { + int type = ntohs(d->lorv); + switch (type) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + life_t = type; + break; + default: + plog(LLV_WARNING, LOCATION, NULL, + "invalid life duration type. " + "use default\n"); + life_t = IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT; + break; + } + break; + } + case IPSECDOI_ATTR_SA_LD: + if (prev == NULL + || (ntohs(prev->type) & ~ISAKMP_GEN_MASK) != + IPSECDOI_ATTR_SA_LD_TYPE) { + plog(LLV_ERROR, LOCATION, NULL, + "life duration must follow ltype\n"); + break; + } + + { + u_int32_t t; + vchar_t *ld_buf = NULL; + + if (flag) { + /* i.e. ISAKMP_GEN_TV */ + ld_buf = vmalloc(sizeof(d->lorv)); + if (ld_buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get LD buffer.\n"); + goto end; + } + memcpy(ld_buf->v, &d->lorv, sizeof(d->lorv)); + } else { + int len = ntohs(d->lorv); + /* i.e. ISAKMP_GEN_TLV */ + ld_buf = vmalloc(len); + if (ld_buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get LD buffer.\n"); + goto end; + } + memcpy(ld_buf->v, d + 1, len); + } + switch (life_t) { + case IPSECDOI_ATTR_SA_LD_TYPE_SEC: + t = ipsecdoi_set_ld(ld_buf); + vfree(ld_buf); + if (t == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto end; + } + /* lifetime must be equal in a proposal. */ + if (pp->lifetime == IPSECDOI_ATTR_SA_LD_SEC_DEFAULT) + pp->lifetime = t; + else if (pp->lifetime != t) { + plog(LLV_ERROR, LOCATION, NULL, + "lifetime mismatched " + "in a proposal, " + "prev:%ld curr:%ld.\n", + pp->lifetime, t); + goto end; + } + break; + case IPSECDOI_ATTR_SA_LD_TYPE_KB: + t = ipsecdoi_set_ld(ld_buf); + vfree(ld_buf); + if (t == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid life duration.\n"); + goto end; + } + /* lifebyte must be equal in a proposal. */ + if (pp->lifebyte == 0) + pp->lifebyte = t; + else if (pp->lifebyte != t) { + plog(LLV_ERROR, LOCATION, NULL, + "lifebyte mismatched " + "in a proposal, " + "prev:%ld curr:%ld.\n", + pp->lifebyte, t); + goto end; + } + break; + default: + vfree(ld_buf); + plog(LLV_ERROR, LOCATION, NULL, + "invalid life type: %d\n", life_t); + goto end; + } + } + break; + + case IPSECDOI_ATTR_GRP_DESC: + /* + * RFC2407: 4.5 IPSEC Security Association Attributes + * Specifies the Oakley Group to be used in a PFS QM + * negotiation. For a list of supported values, see + * Appendix A of [IKE]. + */ + if (pp->pfs_group == 0) + pp->pfs_group = (u_int16_t)ntohs(d->lorv); + else if (pp->pfs_group != (u_int16_t)ntohs(d->lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfs_group mismatched " + "in a proposal.\n"); + goto end; + } + break; + + case IPSECDOI_ATTR_ENC_MODE: + if (pr->encmode + && pr->encmode != (u_int16_t)ntohs(d->lorv)) { + plog(LLV_ERROR, LOCATION, NULL, + "multiple encmode exist " + "in a transform.\n"); + goto end; + } + pr->encmode = (u_int16_t)ntohs(d->lorv); + break; + + case IPSECDOI_ATTR_AUTH: + if (tr->authtype != IPSECDOI_ATTR_AUTH_NONE) { + plog(LLV_ERROR, LOCATION, NULL, + "multiple authtype exist " + "in a transform.\n"); + goto end; + } + tr->authtype = (u_int16_t)ntohs(d->lorv); + break; + + case IPSECDOI_ATTR_KEY_LENGTH: + if (pr->proto_id != IPSECDOI_PROTO_IPSEC_ESP) { + plog(LLV_ERROR, LOCATION, NULL, + "key length defined but not ESP"); + goto end; + } + tr->encklen = ntohs(d->lorv); + break; + + case IPSECDOI_ATTR_KEY_ROUNDS: + case IPSECDOI_ATTR_COMP_DICT_SIZE: + case IPSECDOI_ATTR_COMP_PRIVALG: + default: + break; + } + + prev = d; + if (flag) { + tlen -= sizeof(*d); + d = (struct isakmp_data *)((char *)d + sizeof(*d)); + } else { + tlen -= (sizeof(*d) + ntohs(d->lorv)); + d = (struct isakmp_data *)((caddr_t)d + sizeof(*d) + ntohs(d->lorv)); + } + } + + error = 0; +end: + return error; +} + +int +ipsecdoi_authalg2trnsid(alg) + int alg; +{ + switch (alg) { + case IPSECDOI_ATTR_AUTH_HMAC_MD5: + return IPSECDOI_AH_MD5; + case IPSECDOI_ATTR_AUTH_HMAC_SHA1: + return IPSECDOI_AH_SHA; + case IPSECDOI_ATTR_AUTH_DES_MAC: + return IPSECDOI_AH_DES; + case IPSECDOI_ATTR_AUTH_KPDK: + return IPSECDOI_AH_MD5; /* XXX */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication algorithm:%d\n", alg); + } + return -1; +} + +#ifdef HAVE_GSSAPI +struct isakmpsa * +fixup_initiator_sa(match, received) + struct isakmpsa *match, *received; +{ + struct isakmpsa *newsa; + + if (received->gssid == NULL) + return match; + + newsa = newisakmpsa(); + memcpy(newsa, match, sizeof *newsa); + + if (match->dhgrp != NULL) { + newsa->dhgrp = racoon_calloc(1, sizeof(struct dhgroup)); + memcpy(newsa->dhgrp, match->dhgrp, sizeof (struct dhgroup)); + } + newsa->next = NULL; + newsa->rmconf = NULL; + + newsa->gssid = vdup(received->gssid); + + return newsa; +} +#endif + +static int rm_idtype2doi[] = { + IPSECDOI_ID_FQDN, + IPSECDOI_ID_USER_FQDN, + IPSECDOI_ID_KEY_ID, + -1, /* it's type of "address" + * it expands into 4 types by another function. */ + IPSECDOI_ID_DER_ASN1_DN, +}; + +/* + * convert idtype to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +idtype2doi(idtype) + int idtype; +{ + if (ARRAYLEN(rm_idtype2doi) > idtype) + return rm_idtype2doi[idtype]; + return -1; +} + +int +doi2idtype(doi) + int doi; +{ + switch(doi) { + case IPSECDOI_ID_FQDN: + return(IDTYPE_FQDN); + case IPSECDOI_ID_USER_FQDN: + return(IDTYPE_USERFQDN); + case IPSECDOI_ID_KEY_ID: + return(IDTYPE_KEYID); + case IPSECDOI_ID_DER_ASN1_DN: + return(IDTYPE_ASN1DN); + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + return(IDTYPE_ADDRESS); + default: + plog(LLV_WARNING, LOCATION, NULL, + "Inproper idtype:%d in this function.\n", + s_ipsecdoi_ident(doi)); + return(IDTYPE_ADDRESS); /* XXX */ + } + /*NOTREACHED*/ +} + diff --git a/racoon.tproj/ipsec_doi.h b/racoon.tproj/ipsec_doi.h new file mode 100644 index 0000000..b901a98 --- /dev/null +++ b/racoon.tproj/ipsec_doi.h @@ -0,0 +1,212 @@ +/* $KAME: ipsec_doi.h,v 1.33 2001/08/14 12:26:06 sakane 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. 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. + */ + +/* refered to RFC2407 */ + +#define IPSEC_DOI 1 + +/* 4.2 IPSEC Situation Definition */ +#define IPSECDOI_SIT_IDENTITY_ONLY 0x00000001 +#define IPSECDOI_SIT_SECRECY 0x00000002 +#define IPSECDOI_SIT_INTEGRITY 0x00000004 + +/* 4.4.1 IPSEC Security Protocol Identifiers */ + /* 4.4.2 IPSEC ISAKMP Transform Values */ +#define IPSECDOI_PROTO_ISAKMP 1 +#define IPSECDOI_KEY_IKE 1 + +/* 4.4.1 IPSEC Security Protocol Identifiers */ +#define IPSECDOI_PROTO_IPSEC_AH 2 + /* 4.4.3 IPSEC AH Transform Values */ +#define IPSECDOI_AH_MD5 2 +#define IPSECDOI_AH_SHA 3 +#define IPSECDOI_AH_DES 4 +#define IPSECDOI_AH_SHA2_256 5 +#define IPSECDOI_AH_SHA2_384 6 +#define IPSECDOI_AH_SHA2_512 7 + +/* 4.4.1 IPSEC Security Protocol Identifiers */ +#define IPSECDOI_PROTO_IPSEC_ESP 3 + /* 4.4.4 IPSEC ESP Transform Identifiers */ +#define IPSECDOI_ESP_DES_IV64 1 +#define IPSECDOI_ESP_DES 2 +#define IPSECDOI_ESP_3DES 3 +#define IPSECDOI_ESP_RC5 4 +#define IPSECDOI_ESP_IDEA 5 +#define IPSECDOI_ESP_CAST 6 +#define IPSECDOI_ESP_BLOWFISH 7 +#define IPSECDOI_ESP_3IDEA 8 +#define IPSECDOI_ESP_DES_IV32 9 +#define IPSECDOI_ESP_RC4 10 +#define IPSECDOI_ESP_NULL 11 +#define IPSECDOI_ESP_RIJNDAEL 12 +#define IPSECDOI_ESP_AES 12 +#if 1 + /* draft-ietf-ipsec-ciph-aes-cbc-00.txt */ +#define IPSECDOI_ESP_TWOFISH 253 +#else + /* SSH uses these value for now */ +#define IPSECDOI_ESP_TWOFISH 250 +#endif + +/* 4.4.1 IPSEC Security Protocol Identifiers */ +#define IPSECDOI_PROTO_IPCOMP 4 + /* 4.4.5 IPSEC IPCOMP Transform Identifiers */ +#define IPSECDOI_IPCOMP_OUI 1 +#define IPSECDOI_IPCOMP_DEFLATE 2 +#define IPSECDOI_IPCOMP_LZS 3 + +/* 4.5 IPSEC Security Association Attributes */ +/* NOTE: default value is not included in a packet. */ +#define IPSECDOI_ATTR_SA_LD_TYPE 1 /* B */ +#define IPSECDOI_ATTR_SA_LD_TYPE_DEFAULT 1 +#define IPSECDOI_ATTR_SA_LD_TYPE_SEC 1 +#define IPSECDOI_ATTR_SA_LD_TYPE_KB 2 +#define IPSECDOI_ATTR_SA_LD_TYPE_MAX 3 +#define IPSECDOI_ATTR_SA_LD 2 /* V */ +#define IPSECDOI_ATTR_SA_LD_SEC_DEFAULT 28800 /* 8 hours */ +#define IPSECDOI_ATTR_SA_LD_KB_MAX (~(1 << ((sizeof(int) << 3) - 1))) +#define IPSECDOI_ATTR_GRP_DESC 3 /* B */ +#define IPSECDOI_ATTR_ENC_MODE 4 /* B */ + /* default value: host dependent */ +#define IPSECDOI_ATTR_ENC_MODE_ANY 0 /* NOTE:internal use */ +#define IPSECDOI_ATTR_ENC_MODE_TUNNEL 1 +#define IPSECDOI_ATTR_ENC_MODE_TRNS 2 +#define IPSECDOI_ATTR_AUTH 5 /* B */ + /* 0 means not to use authentication. */ +#define IPSECDOI_ATTR_AUTH_HMAC_MD5 1 +#define IPSECDOI_ATTR_AUTH_HMAC_SHA1 2 +#define IPSECDOI_ATTR_AUTH_DES_MAC 3 +#define IPSECDOI_ATTR_AUTH_KPDK 4 /*RFC-1826(Key/Pad/Data/Key)*/ +#define IPSECDOI_ATTR_SHA2_256 5 +#define IPSECDOI_ATTR_SHA2_384 6 +#define IPSECDOI_ATTR_SHA2_512 7 +#define IPSECDOI_ATTR_AUTH_NONE 254 /* NOTE:internal use */ + /* + * When negotiating ESP without authentication, the Auth + * Algorithm attribute MUST NOT be included in the proposal. + * When negotiating ESP without confidentiality, the Auth + * Algorithm attribute MUST be included in the proposal and + * the ESP transform ID must be ESP_NULL. + */ +#define IPSECDOI_ATTR_KEY_LENGTH 6 /* B */ +#define IPSECDOI_ATTR_KEY_ROUNDS 7 /* B */ +#define IPSECDOI_ATTR_COMP_DICT_SIZE 8 /* B */ +#define IPSECDOI_ATTR_COMP_PRIVALG 9 /* V */ + +/* 4.6.1 Security Association Payload */ +struct ipsecdoi_pl_sa { + struct isakmp_gen h; + struct ipsecdoi_sa_b { + u_int32_t doi; /* Domain of Interpretation */ + u_int32_t sit; /* Situation */ + } b; + /* followed by Leveled Domain Identifier and so on. */ +} __attribute__((__packed__)); + +struct ipsecdoi_secrecy_h { + u_int16_t len; + u_int16_t reserved; + /* followed by the value */ +} __attribute__((__packed__)); + +/* 4.6.2 Identification Payload Content */ +struct ipsecdoi_pl_id { + struct isakmp_gen h; + struct ipsecdoi_id_b { + u_int8_t type; /* ID Type */ + u_int8_t proto_id; /* Protocol ID */ + u_int16_t port; /* Port */ + } b; + /* followed by Identification Data */ +} __attribute__((__packed__)); + +#define IPSECDOI_ID_IPV4_ADDR 1 +#define IPSECDOI_ID_FQDN 2 +#define IPSECDOI_ID_USER_FQDN 3 +#define IPSECDOI_ID_IPV4_ADDR_SUBNET 4 +#define IPSECDOI_ID_IPV6_ADDR 5 +#define IPSECDOI_ID_IPV6_ADDR_SUBNET 6 +#define IPSECDOI_ID_IPV4_ADDR_RANGE 7 +#define IPSECDOI_ID_IPV6_ADDR_RANGE 8 +#define IPSECDOI_ID_DER_ASN1_DN 9 +#define IPSECDOI_ID_DER_ASN1_GN 10 +#define IPSECDOI_ID_KEY_ID 11 + +/* compressing doi type, it's internal use. */ +#define IDTYPE_FQDN 0 +#define IDTYPE_USERFQDN 1 +#define IDTYPE_KEYID 2 +#define IDTYPE_ADDRESS 3 +#define IDTYPE_ASN1DN 4 + +/* The use for checking proposal payload. This is not exchange type. */ +#define IPSECDOI_TYPE_PH1 0 +#define IPSECDOI_TYPE_PH2 1 + +struct isakmpsa; +struct ipsecdoi_pl_sa; +struct saprop; +struct saproto; +struct satrns; +struct prop_pair; + +extern int ipsecdoi_checkph1proposal __P((vchar_t *, struct ph1handle *)); +extern int ipsecdoi_selectph2proposal __P((struct ph2handle *)); +extern int ipsecdoi_checkph2proposal __P((struct ph2handle *)); + +extern struct prop_pair **get_proppair __P((vchar_t *, int)); +extern vchar_t *get_sabyproppair __P((struct prop_pair *, struct ph1handle *)); +extern int ipsecdoi_updatespi __P((struct ph2handle *iph2)); +extern vchar_t *get_sabysaprop __P((struct saprop *, vchar_t *)); +extern int ipsecdoi_checkid1 __P((struct ph1handle *)); +extern int ipsecdoi_setid1 __P((struct ph1handle *)); +extern int set_identifier __P((vchar_t **, int, vchar_t *)); +extern int ipsecdoi_setid2 __P((struct ph2handle *)); +extern vchar_t *ipsecdoi_sockaddr2id __P((struct sockaddr *, u_int, u_int)); +extern int ipsecdoi_id2sockaddr __P((vchar_t *, struct sockaddr *, + u_int8_t *, u_int16_t *)); +extern const char *ipsecdoi_id2str __P((const vchar_t *)); + +extern vchar_t *ipsecdoi_setph1proposal __P((struct isakmpsa *)); +extern int ipsecdoi_setph2proposal __P((struct ph2handle *)); +extern int ipsecdoi_transportmode __P((struct ph2handle *)); +extern int ipsecdoi_get_defaultlifetime __P((void)); +extern int ipsecdoi_checkalgtypes __P((int, int, int, int)); +extern int ipproto2doi __P((int)); +extern int doi2ipproto __P((int)); + +extern int ipsecdoi_t2satrns __P((struct isakmp_pl_t *, + struct saprop *, struct saproto *, struct satrns *)); +extern int ipsecdoi_authalg2trnsid __P((int)); +extern int idtype2doi __P((int)); +extern int doi2idtype __P((int)); + diff --git a/racoon.tproj/isakmp.c b/racoon.tproj/isakmp.c new file mode 100644 index 0000000..d2fa6e1 --- /dev/null +++ b/racoon.tproj/isakmp.c @@ -0,0 +1,2418 @@ +/* $KAME: isakmp.c,v 1.171 2001/12/12 22:35:37 itojun 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. 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. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#if !defined(HAVE_GETADDRINFO) || !defined(HAVE_GETNAMEINFO) +#include "addrinfo.h" +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "remoteconf.h" +#include "localconf.h" +#include "grabmyaddr.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "pfkey.h" +#include "crypto_openssl.h" +#include "policy.h" +#include "isakmp_ident.h" +#include "isakmp_agg.h" +#include "isakmp_base.h" +#include "isakmp_quick.h" +#include "isakmp_inf.h" +#include "isakmp_newg.h" +#include "strnames.h" + +static int nostate1 __P((struct ph1handle *, vchar_t *)); +static int nostate2 __P((struct ph2handle *, vchar_t *)); + +extern caddr_t val2str(const char *, size_t); + +static int (*ph1exchange[][2][PHASE1ST_MAX]) + __P((struct ph1handle *, vchar_t *)) = { + /* error */ + { {}, {}, }, + /* Identity Protection exchange */ + { + { nostate1, ident_i1send, nostate1, ident_i2recv, ident_i2send, + ident_i3recv, ident_i3send, ident_i4recv, ident_i4send, nostate1, }, + { nostate1, ident_r1recv, ident_r1send, ident_r2recv, ident_r2send, + ident_r3recv, ident_r3send, nostate1, nostate1, nostate1, }, + }, + /* Aggressive exchange */ + { + { nostate1, agg_i1send, nostate1, agg_i2recv, agg_i2send, + nostate1, nostate1, nostate1, nostate1, nostate1, }, + { nostate1, agg_r1recv, agg_r1send, agg_r2recv, agg_r2send, + nostate1, nostate1, nostate1, nostate1, nostate1, }, + }, + /* Base exchange */ + { + { nostate1, base_i1send, nostate1, base_i2recv, base_i2send, + base_i3recv, base_i3send, nostate1, nostate1, nostate1, }, + { nostate1, base_r1recv, base_r1send, base_r2recv, base_r2send, + nostate1, nostate1, nostate1, nostate1, nostate1, }, + }, +}; + +static int (*ph2exchange[][2][PHASE2ST_MAX]) + __P((struct ph2handle *, vchar_t *)) = { + /* error */ + { {}, {}, }, + /* Quick mode for IKE*/ + { + { nostate2, nostate2, quick_i1prep, nostate2, quick_i1send, + quick_i2recv, quick_i2send, quick_i3recv, nostate2, nostate2, }, + { nostate2, quick_r1recv, quick_r1prep, nostate2, quick_r2send, + quick_r3recv, quick_r3prep, quick_r3send, nostate2, nostate2, } + }, +}; + +static u_char r_ck0[] = { 0,0,0,0,0,0,0,0 }; /* used to verify the r_ck. */ + +static int isakmp_main __P((vchar_t *, struct sockaddr *, struct sockaddr *)); +static int ph1_main __P((struct ph1handle *, vchar_t *)); +static int quick_main __P((struct ph2handle *, vchar_t *)); +static int isakmp_ph1begin_r __P((vchar_t *, + struct sockaddr *, struct sockaddr *, u_int8_t)); +static int isakmp_ph2begin_i __P((struct ph1handle *, struct ph2handle *)); +static int isakmp_ph2begin_r __P((struct ph1handle *, vchar_t *)); +static int etypesw1 __P((int)); +static int etypesw2 __P((int)); + +/* + * isakmp packet handler + */ +int +isakmp_handler(so_isakmp) + int so_isakmp; +{ + struct isakmp isakmp; + struct sockaddr_storage remote; + struct sockaddr_storage local; + int remote_len = sizeof(remote); + int local_len = sizeof(local); + int len; + u_short port; + vchar_t *buf = NULL; + int error = -1; + + /* read message by MSG_PEEK */ + while ((len = recvfromto(so_isakmp, (char *)&isakmp, sizeof(isakmp), + MSG_PEEK, (struct sockaddr *)&remote, &remote_len, + (struct sockaddr *)&local, &local_len)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to receive isakmp packet\n"); + goto end; + } + + /* check isakmp header length */ + if (len < sizeof(isakmp)) { + plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, + "packet shorter than isakmp header size.\n"); + /* dummy receive */ + if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp), + 0, (struct sockaddr *)&remote, &remote_len)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to receive isakmp packet\n"); + } + goto end; + } + + /* read real message */ + if ((buf = vmalloc(ntohl(isakmp.len))) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate reading buffer\n"); + /* dummy receive */ + if ((len = recvfrom(so_isakmp, (char *)&isakmp, sizeof(isakmp), + 0, (struct sockaddr *)&remote, &remote_len)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to receive isakmp packet\n"); + } + goto end; + } + + while ((len = recvfromto(so_isakmp, buf->v, buf->l, + 0, (struct sockaddr *)&remote, &remote_len, + (struct sockaddr *)&local, &local_len)) < 0) { + if (errno == EINTR) + continue; + plog(LLV_ERROR, LOCATION, NULL, + "failed to receive isakmp packet\n"); + goto end; + } + + if (len != buf->l) { + plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, + "received invalid length, why ?\n"); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + plog(LLV_DEBUG, LOCATION, (struct sockaddr *)&local, + "%d bytes message received from %s\n", + len, saddr2str((struct sockaddr *)&remote)); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* avoid packets with malicious port/address */ + switch (remote.ss_family) { + case AF_INET: + port = ((struct sockaddr_in *)&remote)->sin_port; + break; +#ifdef INET6 + case AF_INET6: + port = ((struct sockaddr_in6 *)&remote)->sin6_port; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", remote.ss_family); + goto end; + } + if (port == 0) { + plog(LLV_ERROR, LOCATION, (struct sockaddr *)&remote, + "src port == 0 (valid as UDP but not with IKE)\n"); + goto end; + } + + /* XXX: check sender whether to be allowed or not to accept */ + + /* XXX: I don't know how to check isakmp half connection attack. */ + + /* simply reply if the packet was processed. */ + if (check_recvdpkt((struct sockaddr *)&remote, + (struct sockaddr *)&local, buf)) { + plog(LLV_NOTIFY, LOCATION, NULL, + "the packet is retransmitted by %s.\n", + saddr2str((struct sockaddr *)&remote)); + error = 0; + goto end; + } + + /* isakmp main routine */ + if (isakmp_main(buf, (struct sockaddr *)&remote, + (struct sockaddr *)&local) != 0) goto end; + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + + return(error); +} + +/* + * main processing to handle isakmp payload + */ +static int +isakmp_main(msg, remote, local) + vchar_t *msg; + struct sockaddr *remote, *local; +{ + struct isakmp *isakmp = (struct isakmp *)msg->v; + isakmp_index *index = (isakmp_index *)isakmp; + u_int32_t msgid = isakmp->msgid; + struct ph1handle *iph1; + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(msg, remote, local, 0); +#endif + + /* the initiator's cookie must not be zero */ + if (memcmp(&isakmp->i_ck, r_ck0, sizeof(cookie_t)) == 0) { + plog(LLV_ERROR, LOCATION, remote, + "malformed cookie received.\n"); + return -1; + } + + /* Check the Major and Minor Version fields. */ + /* + * XXX Is is right to check version here ? + * I think it may no be here because the version depends + * on exchange status. + */ + if (isakmp->v < ISAKMP_VERSION_NUMBER) { + if (ISAKMP_GETMAJORV(isakmp->v) < ISAKMP_MAJOR_VERSION) { + plog(LLV_ERROR, LOCATION, remote, + "invalid major version %d.\n", + ISAKMP_GETMAJORV(isakmp->v)); + return -1; + } +#if ISAKMP_MINOR_VERSION > 0 + if (ISAKMP_GETMINORV(isakmp->v) < ISAKMP_MINOR_VERSION) { + plog(LLV_ERROR, LOCATION, remote, + "invalid minor version %d.\n", + ISAKMP_GETMINORV(isakmp->v)); + return -1; + } +#endif + } + + /* check the Flags field. */ + /* XXX How is the exclusive check, E and A ? */ + if (isakmp->flags & ~(ISAKMP_FLAG_E | ISAKMP_FLAG_C | ISAKMP_FLAG_A)) { + plog(LLV_ERROR, LOCATION, remote, + "invalid flag 0x%02x.\n", isakmp->flags); + return -1; + } + + /* ignore commit bit. */ + if (ISSET(isakmp->flags, ISAKMP_FLAG_C)) { + if (isakmp->msgid == 0) { + isakmp_info_send_nx(isakmp, remote, local, + ISAKMP_NTYPE_INVALID_FLAGS, NULL); + plog(LLV_ERROR, LOCATION, remote, + "Commit bit on phase1 forbidden.\n"); + return -1; + } + } + + iph1 = getph1byindex(index); + if (iph1 != NULL) { + /* validity check */ + if (memcmp(&isakmp->r_ck, r_ck0, sizeof(cookie_t)) == 0 && + iph1->side == INITIATOR) { + plog(LLV_DEBUG, LOCATION, remote, + "malformed cookie received or " + "the initiator's cookies collide.\n"); + return -1; + } + + /* must be same addresses in one stream of a phase at least. */ + if (cmpsaddrstrict(iph1->remote, remote) != 0) { + char *saddr_db, *saddr_act; + + saddr_db = strdup(saddr2str(iph1->remote)); + saddr_act = strdup(saddr2str(remote)); + + plog(LLV_WARNING, LOCATION, remote, + "remote address mismatched. db=%s, act=%s\n", + saddr_db, saddr_act); + + racoon_free(saddr_db); + racoon_free(saddr_act); + } + /* + * don't check of exchange type here because other type will be + * with same index, for example, informational exchange. + */ + + /* XXX more acceptable check */ + } + + switch (isakmp->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + case ISAKMP_ETYPE_BASE: + /* phase 1 validity check */ + if (isakmp->msgid != 0) { + plog(LLV_ERROR, LOCATION, remote, + "message id should be zero in phase1.\n"); + return -1; + } + + /* search for isakmp status record of phase 1 */ + if (iph1 == NULL) { + /* + * the packet must be the 1st message from a initiator + * or the 2nd message from the responder. + */ + + /* search for phase1 handle by index without r_ck */ + iph1 = getph1byindex0(index); + if (iph1 == NULL) { + /*it must be the 1st message from a initiator.*/ + if (memcmp(&isakmp->r_ck, r_ck0, + sizeof(cookie_t)) != 0) { + + plog(LLV_DEBUG, LOCATION, remote, + "malformed cookie received " + "or the spi expired.\n"); + return -1; + } + + /* it must be responder's 1st exchange. */ + if (isakmp_ph1begin_r(msg, remote, local, + isakmp->etype) < 0) + return -1; + break; + + /*NOTREACHED*/ + } + + /* it must be the 2nd message from the responder. */ + if (iph1->side != INITIATOR) { + plog(LLV_DEBUG, LOCATION, remote, + "malformed cookie received. " + "it has to be as the initiator. %s\n", + isakmp_pindex(&iph1->index, 0)); + return -1; + } + } + + /* + * Don't delete phase 1 handler when the exchange type + * in handler is not equal to packet's one because of no + * authencication completed. + */ + if (iph1->etype != isakmp->etype) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "exchange type is mismatched: " + "db=%s packet=%s, ignore it.\n", + s_isakmp_etype(iph1->etype), + s_isakmp_etype(isakmp->etype)); + return -1; + } + + /* call main process of phase 1 */ + if (ph1_main(iph1, msg) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "phase1 negotiation failed.\n"); + remph1(iph1); + delph1(iph1); + return -1; + } + break; + + case ISAKMP_ETYPE_AUTH: + plog(LLV_INFO, LOCATION, remote, + "unsupported exchange %d received.\n", + isakmp->etype); + break; + + case ISAKMP_ETYPE_INFO: + case ISAKMP_ETYPE_ACKINFO: + /* + * iph1 must be present for Information message. + * if iph1 is null then trying to get the phase1 status + * as the packet from responder againt initiator's 1st + * exchange in phase 1. + * NOTE: We think such informational exchange should be ignored. + */ + if (iph1 == NULL) { + iph1 = getph1byindex0(index); + if (iph1 == NULL) { + plog(LLV_ERROR, LOCATION, remote, + "unknown Informational " + "exchange received.\n"); + return -1; + } + if (cmpsaddrstrict(iph1->remote, remote) != 0) { + plog(LLV_WARNING, LOCATION, remote, + "remote address mismatched. " + "db=%s\n", + saddr2str(iph1->remote)); + } + } + + if (isakmp_info_recv(iph1, msg) < 0) + return -1; + break; + + case ISAKMP_ETYPE_QUICK: + { + struct ph2handle *iph2; + + if (iph1 == NULL) { + isakmp_info_send_nx(isakmp, remote, local, + ISAKMP_NTYPE_INVALID_COOKIE, NULL); + plog(LLV_ERROR, LOCATION, remote, + "can't start the quick mode, " + "there is no ISAKMP-SA, %s\n", + isakmp_pindex((isakmp_index *)&isakmp->i_ck, + isakmp->msgid)); + return -1; + } + + /* check status of phase 1 whether negotiated or not. */ + if (iph1->status != PHASE1ST_ESTABLISHED) { + plog(LLV_ERROR, LOCATION, remote, + "can't start the quick mode, " + "there is no valid ISAKMP-SA, %s\n", + isakmp_pindex(&iph1->index, iph1->msgid)); + return -1; + } + + /* search isakmp phase 2 stauts record. */ + iph2 = getph2bymsgid(iph1, msgid); + if (iph2 == NULL) { + /* it must be new negotiation as responder */ + if (isakmp_ph2begin_r(iph1, msg) < 0) + return -1; + return 0; + /*NOTREACHED*/ + } + + /* commit bit. */ + /* XXX + * we keep to set commit bit during negotiation. + * When SA is configured, bit will be reset. + * XXX + * don't initiate commit bit. should be fixed in the future. + */ + if (ISSET(isakmp->flags, ISAKMP_FLAG_C)) + iph2->flags |= ISAKMP_FLAG_C; + + /* call main process of quick mode */ + if (quick_main(iph2, msg) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "phase2 negotiation failed.\n"); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + return -1; + } + } + break; + + case ISAKMP_ETYPE_NEWGRP: + if (iph1 == NULL) { + plog(LLV_ERROR, LOCATION, remote, + "Unknown new group mode exchange, " + "there is no ISAKMP-SA.\n"); + return -1; + } + isakmp_newgroup_r(iph1, msg); + break; + + case ISAKMP_ETYPE_NONE: + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid exchange type %d from %s.\n", + isakmp->etype, saddr2str(remote)); + return -1; + } + + return 0; +} + +/* + * main function of phase 1. + */ +static int +ph1_main(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + /* ignore a packet */ + if (iph1->status == PHASE1ST_ESTABLISHED) + return 0; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + /* receive */ + if (ph1exchange[etypesw1(iph1->etype)] + [iph1->side] + [iph1->status] == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "why isn't the function defined.\n"); + return -1; + } + error = (ph1exchange[etypesw1(iph1->etype)] + [iph1->side] + [iph1->status])(iph1, msg); + if (error != 0) { +#if 0 + /* XXX + * When an invalid packet is received on phase1, it should + * be selected to process this packet. That is to respond + * with a notify and delete phase 1 handler, OR not to respond + * and keep phase 1 handler. + */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to pre-process packet.\n"); + return -1; +#else + /* ignore the error and keep phase 1 handler */ + return 0; +#endif + } + + /* free resend buffer */ + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no buffer found as sendbuf\n"); + return -1; + } + vfree(iph1->sendbuf); + iph1->sendbuf = NULL; + + /* turn off schedule */ + if (iph1->scr) + SCHED_KILL(iph1->scr); + + /* send */ + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + if ((ph1exchange[etypesw1(iph1->etype)] + [iph1->side] + [iph1->status])(iph1, msg) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to process packet.\n"); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase1", s_isakmp_state(iph1->etype, iph1->side, iph1->status), + timedelta(&start, &end)); +#endif + if (iph1->status == PHASE1ST_ESTABLISHED) { + +#ifdef ENABLE_STATS + gettimeofday(&iph1->end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase1", s_isakmp_etype(iph1->etype), + timedelta(&iph1->start, &iph1->end)); +#endif + + /* save created date. */ + (void)time(&iph1->created); + + /* add to the schedule to expire, and seve back pointer. */ + iph1->sce = sched_new(iph1->approval->lifetime, + isakmp_ph1expire_stub, iph1); + + /* INITIAL-CONTACT processing */ + /* don't anything if local test mode. */ + if (!f_local + && iph1->rmconf->ini_contact && !getcontacted(iph1->remote)) { + /* send INITIAL-CONTACT */ + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INITIAL_CONTACT, NULL); + /* insert a node into contacted list. */ + if (inscontacted(iph1->remote) == -1) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to add contacted list.\n"); + /* ignore */ + } + } + + log_ph1established(iph1); + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + } + + return 0; +} + +/* + * main function of quick mode. + */ +static int +quick_main(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; +{ + struct isakmp *isakmp = (struct isakmp *)msg->v; + int error; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + /* ignore a packet */ + if (iph2->status == PHASE2ST_ESTABLISHED + || iph2->status == PHASE2ST_GETSPISENT) + return 0; + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + /* receive */ + if (ph2exchange[etypesw2(isakmp->etype)] + [iph2->side] + [iph2->status] == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "why isn't the function defined.\n"); + return -1; + } + error = (ph2exchange[etypesw2(isakmp->etype)] + [iph2->side] + [iph2->status])(iph2, msg); + if (error != 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "failed to pre-process packet.\n"); + if (error == ISAKMP_INTERNAL_ERROR) + return 0; + isakmp_info_send_n1(iph2->ph1, error, NULL); + return -1; + } + + /* when using commit bit, status will be reached here. */ + if (iph2->status == PHASE2ST_ADDSA) + return 0; + + /* free resend buffer */ + if (iph2->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no buffer found as sendbuf\n"); + return -1; + } + vfree(iph2->sendbuf); + iph2->sendbuf = NULL; + + /* turn off schedule */ + if (iph2->scr) + SCHED_KILL(iph2->scr); + + /* send */ + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + if ((ph2exchange[etypesw2(isakmp->etype)] + [iph2->side] + [iph2->status])(iph2, msg) != 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "failed to process packet.\n"); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase2", + s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), + timedelta(&start, &end)); +#endif + + return 0; +} + +/* new negotiation of phase 1 for initiator */ +int +isakmp_ph1begin_i(rmconf, remote) + struct remoteconf *rmconf; + struct sockaddr *remote; +{ + struct ph1handle *iph1; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + /* get new entry to isakmp status table. */ + iph1 = newph1(); + if (iph1 == NULL) + return -1; + + iph1->status = PHASE1ST_START; + iph1->rmconf = rmconf; + iph1->side = INITIATOR; + iph1->version = ISAKMP_VERSION_NUMBER; + iph1->msgid = 0; + iph1->flags = 0; + iph1->ph2cnt = 0; +#ifdef HAVE_GSSAPI + iph1->gssapi_state = NULL; +#endif + iph1->approval = NULL; + + /* XXX copy remote address */ + if (copy_ph1addresses(iph1, rmconf, remote, NULL) < 0) + return -1; + + (void)insph1(iph1); + + /* start phase 1 exchange */ + iph1->etype = rmconf->etypes->type; + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + { + char *a; + + a = strdup(saddr2str(iph1->local)); + plog(LLV_INFO, LOCATION, NULL, + "initiate new phase 1 negotiation: %s<=>%s\n", + a, saddr2str(iph1->remote)); + racoon_free(a); + } + plog(LLV_INFO, LOCATION, NULL, + "begin %s mode.\n", + s_isakmp_etype(iph1->etype)); + +#ifdef ENABLE_STATS + gettimeofday(&iph1->start, NULL); + gettimeofday(&start, NULL); +#endif + /* start exchange */ + if ((ph1exchange[etypesw1(iph1->etype)] + [iph1->side] + [iph1->status])(iph1, NULL) != 0) { + /* failed to start phase 1 negotiation */ + remph1(iph1); + delph1(iph1); + + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase1", + s_isakmp_state(iph1->etype, iph1->side, iph1->status), + timedelta(&start, &end)); +#endif + + return 0; +} + +/* new negotiation of phase 1 for responder */ +static int +isakmp_ph1begin_r(msg, remote, local, etype) + vchar_t *msg; + struct sockaddr *remote, *local; + u_int8_t etype; +{ + struct isakmp *isakmp = (struct isakmp *)msg->v; + struct remoteconf *rmconf; + struct ph1handle *iph1; + struct etypes *etypeok; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + /* look for my configuration */ + rmconf = getrmconf(remote); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, remote, + "couldn't find " + "configuration.\n"); + return -1; + } + + /* check to be acceptable exchange type */ + etypeok = check_etypeok(rmconf, etype); + if (etypeok == NULL) { + plog(LLV_ERROR, LOCATION, remote, + "not acceptable %s mode\n", s_isakmp_etype(etype)); + return -1; + } + + /* get new entry to isakmp status table. */ + iph1 = newph1(); + if (iph1 == NULL) + return -1; + + memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(iph1->index.i_ck)); + iph1->status = PHASE1ST_START; + iph1->rmconf = rmconf; + iph1->flags = 0; + iph1->side = RESPONDER; + iph1->etype = etypeok->type; + iph1->version = isakmp->v; + iph1->msgid = 0; +#ifdef HAVE_GSSAPI + iph1->gssapi_state = NULL; +#endif + iph1->approval = NULL; + + /* copy remote address */ + if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) + return -1; + + (void)insph1(iph1); + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + { + char *a; + + a = strdup(saddr2str(iph1->local)); + plog(LLV_INFO, LOCATION, NULL, + "respond new phase 1 negotiation: %s<=>%s\n", + a, saddr2str(iph1->remote)); + racoon_free(a); + } + plog(LLV_INFO, LOCATION, NULL, + "begin %s mode.\n", s_isakmp_etype(etype)); + +#ifdef ENABLE_STATS + gettimeofday(&iph1->start, NULL); + gettimeofday(&start, NULL); +#endif + /* start exchange */ + if ((ph1exchange[etypesw1(iph1->etype)] + [iph1->side] + [iph1->status])(iph1, msg) < 0 + || (ph1exchange[etypesw1(iph1->etype)] + [iph1->side] + [iph1->status])(iph1, msg) < 0) { + plog(LLV_ERROR, LOCATION, remote, + "failed to process packet.\n"); + remph1(iph1); + delph1(iph1); + return -1; + } +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase1", + s_isakmp_state(iph1->etype, iph1->side, iph1->status), + timedelta(&start, &end)); +#endif + + return 0; +} + +/* new negotiation of phase 2 for initiator */ +static int +isakmp_ph2begin_i(iph1, iph2) + struct ph1handle *iph1; + struct ph2handle *iph2; +{ + /* found ISAKMP-SA. */ + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n"); + { + char *a; + a = strdup(saddr2str(iph2->src)); + plog(LLV_INFO, LOCATION, NULL, + "initiate new phase 2 negotiation: %s<=>%s\n", + a, saddr2str(iph2->dst)); + racoon_free(a); + } + +#ifdef ENABLE_STATS + gettimeofday(&iph2->start, NULL); +#endif + /* found isakmp-sa */ + bindph12(iph1, iph2); + iph2->status = PHASE2ST_STATUS2; + + if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)] + [iph2->side] + [iph2->status])(iph2, NULL) < 0) { + unbindph12(iph2); + /* release ipsecsa handler due to internal error. */ + remph2(iph2); + delph2(iph2); + return -1; + } + return 0; +} + +/* new negotiation of phase 2 for responder */ +static int +isakmp_ph2begin_r(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp *isakmp = (struct isakmp *)msg->v; + struct ph2handle *iph2 = 0; + int error; +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + iph2 = newph2(); + if (iph2 == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate phase2 entry.\n"); + return -1; + } + + iph2->ph1 = iph1; + iph2->side = RESPONDER; + iph2->status = PHASE2ST_START; + iph2->flags = isakmp->flags; + iph2->msgid = isakmp->msgid; + iph2->seq = pk_getseq(); + iph2->ivm = oakley_newiv2(iph1, iph2->msgid); + if (iph2->ivm == NULL) { + delph2(iph2); + return -1; + } + iph2->dst = dupsaddr(iph1->remote); /* XXX should be considered */ + if (iph2->dst == NULL) { + delph2(iph2); + return -1; + } + switch (iph2->dst->sa_family) { + case AF_INET: + ((struct sockaddr_in *)iph2->dst)->sin_port = 0; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph2->dst->sa_family); + delph2(iph2); + return -1; + } + + iph2->src = dupsaddr(iph1->local); /* XXX should be considered */ + if (iph2->src == NULL) { + delph2(iph2); + return -1; + } + switch (iph2->src->sa_family) { + case AF_INET: + ((struct sockaddr_in *)iph2->src)->sin_port = 0; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph2->src->sa_family); + delph2(iph2); + return -1; + } + + /* add new entry to isakmp status table */ + insph2(iph2); + bindph12(iph1, iph2); + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + { + char *a; + + a = strdup(saddr2str(iph2->src)); + plog(LLV_INFO, LOCATION, NULL, + "respond new phase 2 negotiation: %s<=>%s\n", + a, saddr2str(iph2->dst)); + racoon_free(a); + } + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + + error = (ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)] + [iph2->side] + [iph2->status])(iph2, msg); + if (error != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to pre-process packet.\n"); + if (error != ISAKMP_INTERNAL_ERROR) + isakmp_info_send_n1(iph2->ph1, error, NULL); + /* + * release handler because it's wrong that ph2handle is kept + * after failed to check message for responder's. + */ + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + return -1; + } + + /* send */ + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + if ((ph2exchange[etypesw2(isakmp->etype)] + [iph2->side] + [iph2->status])(iph2, msg) < 0) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "failed to process packet.\n"); + /* don't release handler */ + return -1; + } +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase2", + s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), + timedelta(&start, &end)); +#endif + + return 0; +} + +/* + * parse ISAKMP payloads, without ISAKMP base header. + */ +vchar_t * +isakmp_parsewoh(np0, gen, len) + int np0; + struct isakmp_gen *gen; + int len; +{ + u_char np = np0 & 0xff; + int tlen, plen; + vchar_t *result; + struct isakmp_parse_t *p, *ep; + + plog(LLV_DEBUG, LOCATION, NULL, "begin.\n"); + + /* + * 5 is a magic number, but any value larger than 2 should be fine + * as we do vrealloc() in the following loop. + */ + result = vmalloc(sizeof(struct isakmp_parse_t) * 5); + if (result == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + return NULL; + } + p = (struct isakmp_parse_t *)result->v; + ep = (struct isakmp_parse_t *)(result->v + result->l - sizeof(*ep)); + + tlen = len; + + /* parse through general headers */ + while (0 < tlen && np != ISAKMP_NPTYPE_NONE) { + if (tlen <= sizeof(struct isakmp_gen)) { + /* don't send information, see isakmp_ident_r1() */ + plog(LLV_ERROR, LOCATION, NULL, + "invalid length of payload\n"); + vfree(result); + return NULL; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "seen nptype=%u(%s)\n", np, s_isakmp_nptype(np)); + + p->type = np; + p->len = ntohs(gen->len); + if (p->len == 0 || p->len > tlen) { + plog(LLV_DEBUG, LOCATION, NULL, + "invalid length of payload\n"); + vfree(result); + return NULL; + } + p->ptr = gen; + p++; + if (ep <= p) { + int off; + + off = p - (struct isakmp_parse_t *)result->v; + result = vrealloc(result, result->l * 2); + if (result == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "failed to realloc buffer.\n"); + vfree(result); + return NULL; + } + ep = (struct isakmp_parse_t *) + (result->v + result->l - sizeof(*ep)); + p = (struct isakmp_parse_t *)result->v; + p += off; + } + + np = gen->np; + plen = ntohs(gen->len); + gen = (struct isakmp_gen *)((caddr_t)gen + plen); + tlen -= plen; + } + p->type = ISAKMP_NPTYPE_NONE; + p->len = 0; + p->ptr = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "succeed.\n"); + + return result; +} + +/* + * parse ISAKMP payloads, including ISAKMP base header. + */ +vchar_t * +isakmp_parse(buf) + vchar_t *buf; +{ + struct isakmp *isakmp = (struct isakmp *)buf->v; + struct isakmp_gen *gen; + int tlen; + vchar_t *result; + u_char np; + + np = isakmp->np; + gen = (struct isakmp_gen *)(buf->v + sizeof(*isakmp)); + tlen = buf->l - sizeof(struct isakmp); + result = isakmp_parsewoh(np, gen, tlen); + + return result; +} + +/* %%% */ +int +isakmp_init() +{ + /* initialize a isakmp status table */ + initph1tree(); + initph2tree(); + initctdtree(); + init_recvdpkt(); + + srandom(time(0)); + + if (isakmp_open() < 0) + goto err; + + return(0); + +err: + isakmp_close(); + return(-1); +} + +/* + * make strings containing i_cookie + r_cookie + msgid + */ +const char * +isakmp_pindex(index, msgid) + const isakmp_index *index; + const u_int32_t msgid; +{ + static char buf[64]; + const u_char *p; + int i, j; + + memset(buf, 0, sizeof(buf)); + + /* copy index */ + p = (const u_char *)index; + for (j = 0, i = 0; i < sizeof(isakmp_index); i++) { + snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]); + j += 2; + switch (i) { + case 7: + buf[j++] = ':'; + } + } + + if (msgid == 0) + return buf; + + /* copy msgid */ + snprintf((char *)&buf[j], sizeof(buf) - j, ":%08x", ntohs(msgid)); + + return buf; +} + +/* open ISAKMP sockets. */ +int +isakmp_open() +{ + const int yes = 1; + int ifnum; +#ifdef INET6 + int pktinfo; +#endif + struct myaddrs *p; + + ifnum = 0; + for (p = lcconf->myaddrs; p; p = p->next) { + if (!p->addr) + continue; + + /* warn if wildcard address - should we forbid this? */ + switch (p->addr->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)p->addr)->sin_addr.s_addr == 0) + plog(LLV_WARNING, LOCATION, NULL, + "listening to wildcard address," + "broadcast IKE packet may kill you\n"); + break; +#ifdef INET6 + case AF_INET6: + if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)p->addr)->sin6_addr)) + plog(LLV_WARNING, LOCATION, NULL, + "listening to wildcard address, " + "broadcast IKE packet may kill you\n"); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported address family %d\n", + lcconf->default_af); + goto err_and_next; + } + + if ((p->sock = socket(p->addr->sa_family, SOCK_DGRAM, 0)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket (%s)\n", strerror(errno)); + goto err_and_next; + } + + /* receive my interface address on inbound packets. */ + switch (p->addr->sa_family) { + case AF_INET: + if (setsockopt(p->sock, IPPROTO_IP, IP_RECVDSTADDR, + (const void *)&yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", strerror(errno)); + goto err_and_next; + } + break; +#ifdef INET6 + case AF_INET6: +#ifdef ADVAPI +#ifdef IPV6_RECVPKTINFO + pktinfo = IPV6_RECVPKTINFO; +#else /* old adv. API */ + pktinfo = IPV6_PKTINFO; +#endif /* IPV6_RECVPKTINFO */ +#else + pktinfo = IPV6_RECVDSTADDR; +#endif + if (setsockopt(p->sock, IPPROTO_IPV6, pktinfo, + (const void *)&yes, sizeof(yes)) < 0) + { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt(%d): %s\n", + pktinfo, strerror(errno)); + goto err_and_next; + } + break; +#endif + } + +#ifdef IPV6_USE_MIN_MTU + if (p->addr->sa_family == AF_INET6 && + setsockopt(p->sock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + (void *)&yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", strerror(errno)); + return -1; + } +#endif + + if (setsockopt_bypass(p->sock, p->addr->sa_family) < 0) + goto err_and_next; + + if (bind(p->sock, p->addr, p->addr->sa_len) < 0) { + plog(LLV_ERROR, LOCATION, p->addr, + "failed to bind (%s).\n", strerror(errno)); + close(p->sock); + goto err_and_next; + } + + ifnum++; + + plog(LLV_INFO, LOCATION, NULL, + "%s used as isakmp port (fd=%d)\n", + saddr2str(p->addr), p->sock); + + continue; + + err_and_next: + racoon_free(p->addr); + p->addr = NULL; + if (! lcconf->autograbaddr && lcconf->strict_address) + return -1; + continue; + } + + if (!ifnum) { + plog(LLV_ERROR, LOCATION, NULL, + "no address could be bound.\n"); + return -1; + } + + return 0; +} + +void +isakmp_close() +{ + struct myaddrs *p, *next; + + for (p = lcconf->myaddrs; p; p = next) { + next = p->next; + + if (!p->addr) + continue; + close(p->sock); + racoon_free(p->addr); + racoon_free(p); + } + + lcconf->myaddrs = NULL; +} + +int +isakmp_send(iph1, sbuf) + struct ph1handle *iph1; + vchar_t *sbuf; +{ + int len = 0; + int s; + + /* select the socket to be sent */ + s = getsockmyaddr(iph1->local); + if (s == -1) + return -1; + + len = sendfromto(s, sbuf->v, sbuf->l, + iph1->local, iph1->remote, lcconf->count_persend); + if (len == -1) { + plog(LLV_ERROR, LOCATION, NULL, "sendfromto failed\n"); + return -1; + } + + return 0; +} + +/* called from scheduler */ +void +isakmp_ph1resend_stub(p) + void *p; +{ + (void)isakmp_ph1resend((struct ph1handle *)p); +} + +int +isakmp_ph1resend(iph1) + struct ph1handle *iph1; +{ + if (iph1->retry_counter < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "phase1 negotiation failed due to time up. %s\n", + isakmp_pindex(&iph1->index, iph1->msgid)); + + remph1(iph1); + delph1(iph1); + return -1; + } + + if (isakmp_send(iph1, iph1->sendbuf) < 0) + return -1; + + plog(LLV_DEBUG, LOCATION, NULL, + "resend phase1 packet %s\n", + isakmp_pindex(&iph1->index, iph1->msgid)); + + iph1->retry_counter--; + + iph1->scr = sched_new(iph1->rmconf->retry_interval, + isakmp_ph1resend_stub, iph1); + + return 0; +} + +/* called from scheduler */ +void +isakmp_ph2resend_stub(p) + void *p; +{ + + (void)isakmp_ph2resend((struct ph2handle *)p); +} + +int +isakmp_ph2resend(iph2) + struct ph2handle *iph2; +{ + if (iph2->retry_counter < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "phase2 negotiation failed due to time up. %s\n", + isakmp_pindex(&iph2->ph1->index, iph2->msgid)); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + return -1; + } + + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) + return -1; + + plog(LLV_DEBUG, LOCATION, NULL, + "resend phase2 packet %s\n", + isakmp_pindex(&iph2->ph1->index, iph2->msgid)); + + iph2->retry_counter--; + + iph2->scr = sched_new(iph2->ph1->rmconf->retry_interval, + isakmp_ph2resend_stub, iph2); + + return 0; +} + +/* called from scheduler */ +void +isakmp_ph1expire_stub(p) + void *p; +{ + + isakmp_ph1expire((struct ph1handle *)p); +} + +void +isakmp_ph1expire(iph1) + struct ph1handle *iph1; +{ + char *src, *dst; + + src = strdup(saddr2str(iph1->local)); + dst = strdup(saddr2str(iph1->remote)); + plog(LLV_INFO, LOCATION, NULL, + "ISAKMP-SA expired %s-%s spi:%s\n", + src, dst, + isakmp_pindex(&iph1->index, 0)); + racoon_free(src); + racoon_free(dst); + + SCHED_KILL(iph1->sce); + + iph1->status = PHASE1ST_EXPIRED; + + /* + * the phase1 deletion is postponed until there is no phase2. + */ + if (LIST_FIRST(&iph1->ph2tree) != NULL) { + iph1->sce = sched_new(1, isakmp_ph1expire_stub, iph1); + return; + } + + iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); +} + +/* called from scheduler */ +void +isakmp_ph1delete_stub(p) + void *p; +{ + + isakmp_ph1delete((struct ph1handle *)p); +} + +void +isakmp_ph1delete(iph1) + struct ph1handle *iph1; +{ + char *src, *dst; + + SCHED_KILL(iph1->sce); + + if (LIST_FIRST(&iph1->ph2tree) != NULL) { + iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); + return; + } + + /* don't re-negosiation when the phase 1 SA expires. */ + + src = strdup(saddr2str(iph1->local)); + dst = strdup(saddr2str(iph1->remote)); + plog(LLV_INFO, LOCATION, NULL, + "ISAKMP-SA deleted %s-%s spi:%s\n", + src, dst, isakmp_pindex(&iph1->index, 0)); + racoon_free(src); + racoon_free(dst); + + remph1(iph1); + delph1(iph1); + + return; +} + +/* called from scheduler. + * this function will call only isakmp_ph2delete(). + * phase 2 handler remain forever if kernel doesn't cry a expire of phase 2 SA + * by something cause. That's why this function is called after phase 2 SA + * expires in the userland. + */ +void +isakmp_ph2expire_stub(p) + void *p; +{ + + isakmp_ph2expire((struct ph2handle *)p); +} + +void +isakmp_ph2expire(iph2) + struct ph2handle *iph2; +{ + char *src, *dst; + + SCHED_KILL(iph2->sce); + + src = strdup(saddrwop2str(iph2->src)); + dst = strdup(saddrwop2str(iph2->dst)); + plog(LLV_INFO, LOCATION, NULL, + "phase2 sa expired %s-%s\n", src, dst); + racoon_free(src); + racoon_free(dst); + + iph2->status = PHASE2ST_EXPIRED; + + iph2->sce = sched_new(1, isakmp_ph2delete_stub, iph2); + + return; +} + +/* called from scheduler */ +void +isakmp_ph2delete_stub(p) + void *p; +{ + + isakmp_ph2delete((struct ph2handle *)p); +} + +void +isakmp_ph2delete(iph2) + struct ph2handle *iph2; +{ + char *src, *dst; + + SCHED_KILL(iph2->sce); + + src = strdup(saddrwop2str(iph2->src)); + dst = strdup(saddrwop2str(iph2->dst)); + plog(LLV_INFO, LOCATION, NULL, + "phase2 sa deleted %s-%s\n", src, dst); + racoon_free(src); + racoon_free(dst); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return; +} + +/* %%% + * Interface between PF_KEYv2 and ISAKMP + */ +/* + * receive ACQUIRE from kernel, and begin either phase1 or phase2. + * if phase1 has been finished, begin phase2. + */ +int +isakmp_post_acquire(iph2) + struct ph2handle *iph2; +{ + struct remoteconf *rmconf; + struct ph1handle *iph1 = NULL; + + /* search appropreate configuration with masking port. */ + rmconf = getrmconf(iph2->dst); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no configuration found for %s.\n", + saddrwop2str(iph2->dst)); + return -1; + } + + /* if passive mode, ignore the acquire message */ + if (rmconf->passive) { + plog(LLV_DEBUG, LOCATION, NULL, + "because of passive mode, " + "ignore the acquire message for %s.\n", + saddrwop2str(iph2->dst)); + return 0; + } + + /* search isakmp status table by address with masking port */ + iph1 = getph1byaddr(iph2->src, iph2->dst); + + /* no ISAKMP-SA found. */ + if (iph1 == NULL) { + struct sched *sc; + + iph2->retry_checkph1 = lcconf->retry_checkph1; + sc = sched_new(1, isakmp_chkph1there_stub, iph2); + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA request for %s queued " + "due to no phase1 found.\n", + saddrwop2str(iph2->dst)); + + /* start phase 1 negotiation as a initiator. */ + if (isakmp_ph1begin_i(rmconf, iph2->dst) < 0) { + SCHED_KILL(sc); + return -1; + } + + return 0; + /*NOTREACHED*/ + } + + /* found ISAKMP-SA, but on negotiation. */ + if (iph1->status != PHASE1ST_ESTABLISHED) { + iph2->retry_checkph1 = lcconf->retry_checkph1; + sched_new(1, isakmp_chkph1there_stub, iph2); + plog(LLV_INFO, LOCATION, iph2->dst, + "request for establishing IPsec-SA was queued " + "due to no phase1 found.\n"); + return 0; + /*NOTREACHED*/ + } + + /* found established ISAKMP-SA */ + /* i.e. iph1->status == PHASE1ST_ESTABLISHED */ + + /* found ISAKMP-SA. */ + plog(LLV_DEBUG, LOCATION, NULL, "begin QUICK mode.\n"); + + /* begin quick mode */ + if (isakmp_ph2begin_i(iph1, iph2)) + return -1; + + return 0; +} + +/* + * receive GETSPI from kernel. + */ +int +isakmp_post_getspi(iph2) + struct ph2handle *iph2; +{ +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + + /* don't process it because there is no suitable phase1-sa. */ + if (iph2->ph1->status == PHASE2ST_EXPIRED) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "the negotiation is stopped, " + "because there is no suitable ISAKMP-SA.\n"); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + if ((ph2exchange[etypesw2(ISAKMP_ETYPE_QUICK)] + [iph2->side] + [iph2->status])(iph2, NULL) != 0) + return -1; +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase2", + s_isakmp_state(ISAKMP_ETYPE_QUICK, iph2->side, iph2->status), + timedelta(&start, &end)); +#endif + + return 0; +} + +/* called by scheduler */ +void +isakmp_chkph1there_stub(p) + void *p; +{ + isakmp_chkph1there((struct ph2handle *)p); +} + +void +isakmp_chkph1there(iph2) + struct ph2handle *iph2; +{ + struct ph1handle *iph1; + + iph2->retry_checkph1--; + if (iph2->retry_checkph1 < 0) { + plog(LLV_ERROR, LOCATION, iph2->dst, + "phase2 negotiation failed " + "due to time up waiting for phase1. %s\n", + sadbsecas2str(iph2->dst, iph2->src, + iph2->satype, 0, 0)); + plog(LLV_INFO, LOCATION, NULL, + "delete phase 2 handler.\n"); + + /* send acquire to kernel as error */ + pk_sendeacquire(iph2); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return; + } + + iph1 = getph1byaddr(iph2->src, iph2->dst); + + /* XXX Even if ph1 as responder is there, should we not start + * phase 2 negotiation ? */ + if (iph1 != NULL + && iph1->status == PHASE1ST_ESTABLISHED) { + /* found isakmp-sa */ + /* begin quick mode */ + (void)isakmp_ph2begin_i(iph1, iph2); + return; + } + + /* no isakmp-sa found */ + sched_new(1, isakmp_chkph1there_stub, iph2); + + return; +} + +/* copy variable data into ALLOCATED buffer. */ +caddr_t +isakmp_set_attr_v(buf, type, val, len) + caddr_t buf; + int type; + caddr_t val; + int len; +{ + struct isakmp_data *data; + + data = (struct isakmp_data *)buf; + data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV); + data->lorv = htons((u_int16_t)len); + memcpy(data + 1, val, len); + + return buf + sizeof(*data) + len; +} + +/* copy fixed length data into ALLOCATED buffer. */ +caddr_t +isakmp_set_attr_l(buf, type, val) + caddr_t buf; + int type; + u_int32_t val; +{ + struct isakmp_data *data; + + data = (struct isakmp_data *)buf; + data->type = htons((u_int16_t)type | ISAKMP_GEN_TV); + data->lorv = htons((u_int16_t)val); + + return buf + sizeof(*data); +} + +/* add a variable data attribute to the buffer by reallocating it. */ +vchar_t * +isakmp_add_attr_v(buf0, type, val, len) + vchar_t *buf0; + int type; + caddr_t val; + int len; +{ + vchar_t *buf = NULL; + struct isakmp_data *data; + int tlen; + int oldlen = 0; + + tlen = sizeof(*data) + len; + + if (buf0) { + oldlen = buf0->l; + buf = vrealloc(buf0, oldlen + tlen); + } else + buf = vmalloc(tlen); + if (!buf) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a attribute buffer.\n"); + return NULL; + } + + data = (struct isakmp_data *)(buf->v + oldlen); + data->type = htons((u_int16_t)type | ISAKMP_GEN_TLV); + data->lorv = htons((u_int16_t)len); + memcpy(data + 1, val, len); + + return buf; +} + +/* add a fixed data attribute to the buffer by reallocating it. */ +vchar_t * +isakmp_add_attr_l(buf0, type, val) + vchar_t *buf0; + int type; + u_int32_t val; +{ + vchar_t *buf = NULL; + struct isakmp_data *data; + int tlen; + int oldlen = 0; + + tlen = sizeof(*data); + + if (buf0) { + oldlen = buf0->l; + buf = vrealloc(buf0, oldlen + tlen); + } else + buf = vmalloc(tlen); + if (!buf) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a attribute buffer.\n"); + return NULL; + } + + data = (struct isakmp_data *)(buf->v + oldlen); + data->type = htons((u_int16_t)type | ISAKMP_GEN_TV); + data->lorv = htons((u_int16_t)val); + + return buf; +} + +/* + * calculate cookie and set. + */ +int +isakmp_newcookie(place, remote, local) + caddr_t place; + struct sockaddr *remote; + struct sockaddr *local; +{ + vchar_t *buf = NULL, *buf2 = NULL; + char *p; + int blen; + int alen; + caddr_t sa1, sa2; + time_t t; + int error = -1; + u_short port; + + + if (remote->sa_family != local->sa_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch, remote:%d local:%d\n", + remote->sa_family, local->sa_family); + goto end; + } + switch (remote->sa_family) { + case AF_INET: + alen = sizeof(struct in_addr); + sa1 = (caddr_t)&((struct sockaddr_in *)remote)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)local)->sin_addr; + break; +#ifdef INET6 + case AF_INET6: + alen = sizeof(struct in_addr); + sa1 = (caddr_t)&((struct sockaddr_in6 *)remote)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)local)->sin6_addr; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", remote->sa_family); + goto end; + } + blen = (alen + sizeof(u_short)) * 2 + + sizeof(time_t) + lcconf->secret_size; + buf = vmalloc(blen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a cookie.\n"); + goto end; + } + p = buf->v; + + /* copy my address */ + memcpy(p, sa1, alen); + p += alen; + port = ((struct sockaddr_in *)remote)->sin_port; + memcpy(p, &port, sizeof(u_short)); + p += sizeof(u_short); + + /* copy target address */ + memcpy(p, sa2, alen); + p += alen; + port = ((struct sockaddr_in *)local)->sin_port; + memcpy(p, &port, sizeof(u_short)); + p += sizeof(u_short); + + /* copy time */ + t = time(0); + memcpy(p, (caddr_t)&t, sizeof(t)); + p += sizeof(t); + + /* copy random value */ + buf2 = eay_set_random(lcconf->secret_size); + if (buf2 == NULL) + goto end; + memcpy(p, buf2->v, lcconf->secret_size); + p += lcconf->secret_size; + vfree(buf2); + + buf2 = eay_sha1_one(buf); + memcpy(place, buf2->v, sizeof(cookie_t)); + + sa1 = val2str(place, sizeof (cookie_t)); + plog(LLV_DEBUG, LOCATION, NULL, "new cookie:\n%s\n", sa1); + racoon_free(sa1); + + error = 0; +end: + if (buf != NULL) + vfree(buf); + if (buf2 != NULL) + vfree(buf2); + return error; +} + +/* + * save partner's(payload) data into phhandle. + */ +int +isakmp_p2ph(buf, gen) + vchar_t **buf; + struct isakmp_gen *gen; +{ + /* XXX to be checked in each functions for logging. */ + if (*buf) { + plog(LLV_WARNING, LOCATION, NULL, + "ignore this payload, same payload type exist.\n"); + return -1; + } + + *buf = vmalloc(ntohs(gen->len) - sizeof(*gen)); + if (*buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer.\n"); + return -1; + } + memcpy((*buf)->v, gen + 1, (*buf)->l); + + return 0; +} + +u_int32_t +isakmp_newmsgid2(iph1) + struct ph1handle *iph1; +{ + u_int32_t msgid2; + + do { + msgid2 = random(); + } while (getph2bymsgid(iph1, msgid2)); + + return msgid2; +} + +/* + * set values into allocated buffer of isakmp header for phase 1 + */ +caddr_t +set_isakmp_header(vbuf, iph1, nptype) + vchar_t *vbuf; + struct ph1handle *iph1; + int nptype; +{ + struct isakmp *isakmp; + + if (vbuf->l < sizeof(*isakmp)) + return NULL; + + isakmp = (struct isakmp *)vbuf->v; + memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t)); + memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t)); + isakmp->np = nptype; + isakmp->v = iph1->version; + isakmp->etype = iph1->etype; + isakmp->flags = iph1->flags; + isakmp->msgid = iph1->msgid; + isakmp->len = htonl(vbuf->l); + + return vbuf->v + sizeof(*isakmp); +} + +/* + * set values into allocated buffer of isakmp header for phase 2 + */ +caddr_t +set_isakmp_header2(vbuf, iph2, nptype) + vchar_t *vbuf; + struct ph2handle *iph2; + int nptype; +{ + struct isakmp *isakmp; + + if (vbuf->l < sizeof(*isakmp)) + return NULL; + + isakmp = (struct isakmp *)vbuf->v; + memcpy(&isakmp->i_ck, &iph2->ph1->index.i_ck, sizeof(cookie_t)); + memcpy(&isakmp->r_ck, &iph2->ph1->index.r_ck, sizeof(cookie_t)); + isakmp->np = nptype; + isakmp->v = iph2->ph1->version; + isakmp->etype = ISAKMP_ETYPE_QUICK; + isakmp->flags = iph2->flags; + memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid)); + isakmp->len = htonl(vbuf->l); + + return vbuf->v + sizeof(*isakmp); +} + +/* + * set values into allocated buffer of isakmp payload. + */ +caddr_t +set_isakmp_payload(buf, src, nptype) + caddr_t buf; + vchar_t *src; + int nptype; +{ + struct isakmp_gen *gen; + caddr_t p = buf; + + plog(LLV_DEBUG, LOCATION, NULL, "add payload of len %d, next type %d\n", + src->l, nptype); + + gen = (struct isakmp_gen *)p; + gen->np = nptype; + gen->len = htons(sizeof(*gen) + src->l); + p += sizeof(*gen); + memcpy(p, src->v, src->l); + p += src->l; + + return p; +} + +static int +etypesw1(etype) + int etype; +{ + switch (etype) { + case ISAKMP_ETYPE_IDENT: + return 1; + case ISAKMP_ETYPE_AGG: + return 2; + case ISAKMP_ETYPE_BASE: + return 3; + default: + return 0; + } + /*NOTREACHED*/ +} + +static int +etypesw2(etype) + int etype; +{ + switch (etype) { + case ISAKMP_ETYPE_QUICK: + return 1; + default: + return 0; + } + /*NOTREACHED*/ +} + +#ifdef HAVE_PRINT_ISAKMP_C +/* for print-isakmp.c */ +char *snapend; +extern void isakmp_print __P((const u_char *, u_int, const u_char *)); + +char *getname __P((const u_char *)); +#ifdef INET6 +char *getname6 __P((const u_char *)); +#endif +int safeputchar __P((int)); + +/* + * Return a name for the IP address pointed to by ap. This address + * is assumed to be in network byte order. + */ +char * +getname(ap) + const u_char *ap; +{ + struct sockaddr_in addr; + static char ntop_buf[NI_MAXHOST]; + + memset(&addr, 0, sizeof(addr)); + addr.sin_len = sizeof(struct sockaddr_in); + addr.sin_family = AF_INET; + memcpy(&addr.sin_addr, ap, sizeof(addr.sin_addr)); + if (getnameinfo((struct sockaddr *)&addr, addr.sin_len, + ntop_buf, sizeof(ntop_buf), NULL, 0, + NI_NUMERICHOST | niflags)) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + + return ntop_buf; +} + +#ifdef INET6 +/* + * Return a name for the IP6 address pointed to by ap. This address + * is assumed to be in network byte order. + */ +char * +getname6(ap) + const u_char *ap; +{ + struct sockaddr_in6 addr; + static char ntop_buf[NI_MAXHOST]; + + memset(&addr, 0, sizeof(addr)); + addr.sin6_len = sizeof(struct sockaddr_in6); + addr.sin6_family = AF_INET6; + memcpy(&addr.sin6_addr, ap, sizeof(addr.sin6_addr)); + if (getnameinfo((struct sockaddr *)&addr, addr.sin6_len, + ntop_buf, sizeof(ntop_buf), NULL, 0, + NI_NUMERICHOST | niflags)) + strncpy(ntop_buf, "?", sizeof(ntop_buf)); + + return ntop_buf; +} +#endif /* INET6 */ + +int +safeputchar(c) + int c; +{ + unsigned char ch; + + ch = (unsigned char)(c & 0xff); + if (c < 0x80 && isprint(c)) + return printf("%c", c & 0xff); + else + return printf("\\%03o", c & 0xff); +} + +void +isakmp_printpacket(msg, from, my, decoded) + vchar_t *msg; + struct sockaddr *from; + struct sockaddr *my; + int decoded; +{ +#ifdef YIPS_DEBUG + struct timeval tv; + int s; + char hostbuf[NI_MAXHOST]; + char portbuf[NI_MAXSERV]; + struct isakmp *isakmp; + vchar_t *buf; +#endif + + if (loglevel < LLV_DEBUG) + return; + +#ifdef YIPS_DEBUG + plog(LLV_DEBUG, LOCATION, NULL, "begin.\n"); + + gettimeofday(&tv, NULL); + s = tv.tv_sec % 3600; + printf("%02d:%02d.%06u ", s / 60, s % 60, (u_int32_t)tv.tv_usec); + + if (from) { + if (getnameinfo(from, from->sa_len, hostbuf, sizeof(hostbuf), + portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV | niflags)) { + strncpy(hostbuf, "?", sizeof(hostbuf)); + strncpy(portbuf, "?", sizeof(portbuf)); + } + printf("%s:%s", hostbuf, portbuf); + } else + printf("?"); + printf(" -> "); + if (my) { + if (getnameinfo(my, my->sa_len, hostbuf, sizeof(hostbuf), + portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV | niflags)) { + strncpy(hostbuf, "?", sizeof(hostbuf)); + strncpy(portbuf, "?", sizeof(portbuf)); + } + printf("%s:%s", hostbuf, portbuf); + } else + printf("?"); + printf(": "); + + buf = vdup(msg); + if (!buf) { + printf("(malloc fail)\n"); + return; + } + if (decoded) { + isakmp = (struct isakmp *)buf->v; + if (isakmp->flags & ISAKMP_FLAG_E) { +#if 0 + int pad; + pad = *(u_char *)(buf->v + buf->l - 1); + if (buf->l < pad && 2 < vflag) + printf("(wrong padding)"); +#endif + isakmp->flags &= ~ISAKMP_FLAG_E; + } + } + + snapend = buf->v + buf->l; + isakmp_print(buf->v, buf->l, NULL); + vfree(buf); + printf("\n"); + fflush(stdout); + + return; +#endif +} +#endif /*HAVE_PRINT_ISAKMP_C*/ + +int +copy_ph1addresses(iph1, rmconf, remote, local) + struct ph1handle *iph1; + struct remoteconf *rmconf; + struct sockaddr *remote, *local; +{ + u_short *port = NULL; + + /* address portion must be grabbed from real remote address "remote" */ + iph1->remote = dupsaddr(remote); + if (iph1->remote == NULL) { + delph1(iph1); + return -1; + } + + /* + * if remote has no port # (in case of initiator - from ACQUIRE msg) + * - if remote.conf specifies port #, use that + * - if remote.conf does not, use 500 + * if remote has port # (in case of responder - from recvfrom(2)) + * respect content of "remote". + */ + switch (iph1->remote->sa_family) { + case AF_INET: + port = &((struct sockaddr_in *)iph1->remote)->sin_port; + if (*port) + break; + *port = ((struct sockaddr_in *)rmconf->remote)->sin_port; + if (*port) + break; + *port = htons(PORT_ISAKMP); + break; +#ifdef INET6 + case AF_INET6: + port = &((struct sockaddr_in6 *)iph1->remote)->sin6_port; + if (*port) + break; + *port = ((struct sockaddr_in6 *)rmconf->remote)->sin6_port; + if (*port) + break; + *port = htons(PORT_ISAKMP); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph1->remote->sa_family); + return -1; + } + + if (local == NULL) + iph1->local = getlocaladdr(iph1->remote); + else + iph1->local = dupsaddr(local); + if (iph1->local == NULL) { + delph1(iph1); + return -1; + } + switch (iph1->local->sa_family) { + case AF_INET: + ((struct sockaddr_in *)iph1->local)->sin_port + = getmyaddrsport(iph1->local); + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)iph1->local)->sin6_port + = getmyaddrsport(iph1->local); + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph1->remote->sa_family); + delph1(iph1); + return -1; + } + + return 0; +} + +static int +nostate1(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + plog(LLV_ERROR, LOCATION, iph1->remote, "wrong state %u.\n", + iph1->status); + return -1; +} + +static int +nostate2(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; +{ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, "wrong state %u.\n", + iph2->status); + return -1; +} + +void +log_ph1established(iph1) + const struct ph1handle *iph1; +{ + char *src, *dst; + + src = strdup(saddr2str(iph1->local)); + dst = strdup(saddr2str(iph1->remote)); + plog(LLV_INFO, LOCATION, NULL, + "ISAKMP-SA established %s-%s spi:%s\n", + src, dst, + isakmp_pindex(&iph1->index, 0)); + racoon_free(src); + racoon_free(dst); + + return; +} + diff --git a/racoon.tproj/isakmp.h b/racoon.tproj/isakmp.h new file mode 100644 index 0000000..d4e3afb --- /dev/null +++ b/racoon.tproj/isakmp.h @@ -0,0 +1,348 @@ +/* $KAME: isakmp.h,v 1.18 2001/03/26 17:27:40 thorpej 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. 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. + */ + +/* refer to RFC 2408 */ + +/* must include first. */ +/* must include "isakmp_var.h" first. */ + +#define INITIATOR 0 /* synonym sender */ +#define RESPONDER 1 /* synonym receiver */ + +#define GENERATE 1 +#define VALIDATE 0 + +/* 3.1 ISAKMP Header Format + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +struct isakmp { + cookie_t i_ck; /* Initiator Cookie */ + cookie_t r_ck; /* Responder Cookie */ + u_int8_t np; /* Next Payload Type */ + u_int8_t v; + u_int8_t etype; /* Exchange Type */ + u_int8_t flags; /* Flags */ + u_int32_t msgid; + u_int32_t len; /* Length */ +} __attribute__((__packed__)); + +/* Next Payload Type */ +#define ISAKMP_NPTYPE_NONE 0 /* NONE*/ +#define ISAKMP_NPTYPE_SA 1 /* Security Association */ +#define ISAKMP_NPTYPE_P 2 /* Proposal */ +#define ISAKMP_NPTYPE_T 3 /* Transform */ +#define ISAKMP_NPTYPE_KE 4 /* Key Exchange */ +#define ISAKMP_NPTYPE_ID 5 /* Identification */ +#define ISAKMP_NPTYPE_CERT 6 /* Certificate */ +#define ISAKMP_NPTYPE_CR 7 /* Certificate Request */ +#define ISAKMP_NPTYPE_HASH 8 /* Hash */ +#define ISAKMP_NPTYPE_SIG 9 /* Signature */ +#define ISAKMP_NPTYPE_NONCE 10 /* Nonce */ +#define ISAKMP_NPTYPE_N 11 /* Notification */ +#define ISAKMP_NPTYPE_D 12 /* Delete */ +#define ISAKMP_NPTYPE_VID 13 /* Vendor ID */ +#define ISAKMP_NPTYPE_MAX 14 + /* 128 - 255 Private Use */ + +/* + * The following are valid when the Vendor ID is one of the + * following: + * + * MD5("A GSS-API Authentication Method for IKE") + * MD5("GSSAPI") (recognized by Windows 2000) + * MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000) + * + * See draft-ietf-ipsec-isakmp-gss-auth-06.txt. + */ +#define ISAKMP_NPTYPE_GSS 129 /* GSS token */ + +#define ISAKMP_MAJOR_VERSION 1 +#define ISAKMP_MINOR_VERSION 0 +#define ISAKMP_VERSION_NUMBER 0x10 +#define ISAKMP_GETMAJORV(v) (((v) & 0xf0) >> 4) +#define ISAKMP_SETMAJORV(v, m) ((v) = ((v) & 0x0f) | (((m) << 4) & 0xf0)) +#define ISAKMP_GETMINORV(v) ((v) & 0x0f) +#define ISAKMP_SETMINORV(v, m) ((v) = ((v) & 0xf0) | ((m) & 0x0f)) + +/* Exchange Type */ +#define ISAKMP_ETYPE_NONE 0 /* NONE */ +#define ISAKMP_ETYPE_BASE 1 /* Base */ +#define ISAKMP_ETYPE_IDENT 2 /* Identity Proteciton */ +#define ISAKMP_ETYPE_AUTH 3 /* Authentication Only */ +#define ISAKMP_ETYPE_AGG 4 /* Aggressive */ +#define ISAKMP_ETYPE_INFO 5 /* Informational */ +/* Additional Exchange Type */ +#define ISAKMP_ETYPE_QUICK 32 /* Quick Mode */ +#define ISAKMP_ETYPE_NEWGRP 33 /* New group Mode */ +#define ISAKMP_ETYPE_ACKINFO 34 /* Acknowledged Informational */ + +/* Flags */ +#define ISAKMP_FLAG_E 0x01 /* Encryption Bit */ +#define ISAKMP_FLAG_C 0x02 /* Commit Bit */ +#define ISAKMP_FLAG_A 0x04 /* Authentication Only Bit */ + +/* 3.2 Payload Generic Header + 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_gen { + u_int8_t np; /* Next Payload */ + u_int8_t reserved; /* RESERVED, unused, must set to 0 */ + u_int16_t len; /* Payload Length */ +} __attribute__((__packed__)); + +/* 3.3 Data Attributes + 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_data { + u_int16_t type; /* defined by DOI-spec, and Attribute Format */ + u_int16_t lorv; /* if f equal 1, Attribute Length */ + /* if f equal 0, Attribute Value */ + /* if f equal 1, Attribute Value */ +} __attribute__((__packed__)); +#define ISAKMP_GEN_TLV 0x0000 +#define ISAKMP_GEN_TV 0x8000 + /* mask for type of attribute format */ +#define ISAKMP_GEN_MASK 0x8000 + +#if 0 +/* MAY NOT be used, because of being defined in ipsec-doi. */ +/* 3.4 Security Association Payload */ +struct isakmp_pl_sa { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int32_t sit; /* Situation */ +} __attribute__((__packed__)); +#endif + +/* 3.5 Proposal Payload */ + /* + The value of the next payload field MUST only contain the value "2" + or "0". If there are additional Proposal payloads in the message, + then this field will be 2. If the current Proposal payload is the + last within the security association proposal, then this field will + be 0. + */ +struct isakmp_pl_p { + struct isakmp_gen h; + u_int8_t p_no; /* Proposal # */ + u_int8_t proto_id; /* Protocol */ + u_int8_t spi_size; /* SPI Size */ + u_int8_t num_t; /* Number of Transforms */ + /* SPI */ +} __attribute__((__packed__)); + +/* 3.6 Transform Payload */ + /* + The value of the next payload field MUST only contain the value "3" + or "0". If there are additional Transform payloads in the proposal, + then this field will be 3. If the current Transform payload is the + last within the proposal, then this field will be 0. + */ +struct isakmp_pl_t { + struct isakmp_gen h; + u_int8_t t_no; /* Transform # */ + u_int8_t t_id; /* Transform-Id */ + u_int16_t reserved; /* RESERVED2 */ + /* SA Attributes */ +} __attribute__((__packed__)); + +/* 3.7 Key Exchange Payload */ +struct isakmp_pl_ke { + struct isakmp_gen h; + /* Key Exchange Data */ +} __attribute__((__packed__)); + +#if 0 +/* NOTE: MUST NOT use because of being defined in ipsec-doi instead them. */ +/* 3.8 Identification Payload */ +struct isakmp_pl_id { + struct isakmp_gen h; + union { + u_int8_t id_type; /* ID Type */ + u_int32_t doi_data; /* DOI Specific ID Data */ + } d; + /* Identification Data */ +} __attribute__((__packed__)); +/* A.4 ISAKMP Identification Type Values */ +#define ISAKMP_ID_IPV4_ADDR 0 +#define ISAKMP_ID_IPV4_ADDR_SUBNET 1 +#define ISAKMP_ID_IPV6_ADDR 2 +#define ISAKMP_ID_IPV6_ADDR_SUBNET 3 +#endif + +/* 3.9 Certificate Payload */ +struct isakmp_pl_cert { + struct isakmp_gen h; + /* + * Encoding type of 1 octet follows immediately, + * variable length CERT data follows encoding type. + */ +} __attribute__((__packed__)); + +/* Certificate Type */ +#define ISAKMP_CERT_NONE 0 +#define ISAKMP_CERT_PKCS7 1 +#define ISAKMP_CERT_PGP 2 +#define ISAKMP_CERT_DNS 3 +#define ISAKMP_CERT_X509SIGN 4 +#define ISAKMP_CERT_X509KE 5 +#define ISAKMP_CERT_KERBEROS 6 +#define ISAKMP_CERT_CRL 7 +#define ISAKMP_CERT_ARL 8 +#define ISAKMP_CERT_SPKI 9 +#define ISAKMP_CERT_X509ATTR 10 + +/* the method to get peers certificate */ +#define ISAKMP_GETCERT_PAYLOAD 1 +#define ISAKMP_GETCERT_LOCALFILE 2 +#define ISAKMP_GETCERT_DNS 3 + +/* 3.10 Certificate Request Payload */ +struct isakmp_pl_cr { + struct isakmp_gen h; + u_int8_t num_cert; /* # Cert. Types */ + /* + Certificate Types (variable length) + -- Contains a list of the types of certificates requested, + sorted in order of preference. Each individual certificate + type is 1 octet. This field is NOT required. + */ + /* # Certificate Authorities (1 octet) */ + /* Certificate Authorities (variable length) */ +} __attribute__((__packed__)); + +/* 3.11 Hash Payload */ +struct isakmp_pl_hash { + struct isakmp_gen h; + /* Hash Data */ +} __attribute__((__packed__)); + +/* 3.12 Signature Payload */ +struct isakmp_pl_sig { + struct isakmp_gen h; + /* Signature Data */ +} __attribute__((__packed__)); + +/* 3.13 Nonce Payload */ +struct isakmp_pl_nonce { + struct isakmp_gen h; + /* Nonce Data */ +} __attribute__((__packed__)); + +/* 3.14 Notification Payload */ +struct isakmp_pl_n { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int8_t proto_id; /* Protocol-ID */ + u_int8_t spi_size; /* SPI Size */ + u_int16_t type; /* Notify Message Type */ + /* SPI */ + /* Notification Data */ +} __attribute__((__packed__)); + +/* 3.14.1 Notify Message Types */ +/* NOTIFY MESSAGES - ERROR TYPES */ +#define ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE 1 +#define ISAKMP_NTYPE_DOI_NOT_SUPPORTED 2 +#define ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED 3 +#define ISAKMP_NTYPE_INVALID_COOKIE 4 +#define ISAKMP_NTYPE_INVALID_MAJOR_VERSION 5 +#define ISAKMP_NTYPE_INVALID_MINOR_VERSION 6 +#define ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE 7 +#define ISAKMP_NTYPE_INVALID_FLAGS 8 +#define ISAKMP_NTYPE_INVALID_MESSAGE_ID 9 +#define ISAKMP_NTYPE_INVALID_PROTOCOL_ID 10 +#define ISAKMP_NTYPE_INVALID_SPI 11 +#define ISAKMP_NTYPE_INVALID_TRANSFORM_ID 12 +#define ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED 13 +#define ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN 14 +#define ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX 15 +#define ISAKMP_NTYPE_PAYLOAD_MALFORMED 16 +#define ISAKMP_NTYPE_INVALID_KEY_INFORMATION 17 +#define ISAKMP_NTYPE_INVALID_ID_INFORMATION 18 +#define ISAKMP_NTYPE_INVALID_CERT_ENCODING 19 +#define ISAKMP_NTYPE_INVALID_CERTIFICATE 20 +#define ISAKMP_NTYPE_BAD_CERT_REQUEST_SYNTAX 21 +#define ISAKMP_NTYPE_INVALID_CERT_AUTHORITY 22 +#define ISAKMP_NTYPE_INVALID_HASH_INFORMATION 23 +#define ISAKMP_NTYPE_AUTHENTICATION_FAILED 24 +#define ISAKMP_NTYPE_INVALID_SIGNATURE 25 +#define ISAKMP_NTYPE_ADDRESS_NOTIFICATION 26 +#define ISAKMP_NTYPE_NOTIFY_SA_LIFETIME 27 +#define ISAKMP_NTYPE_CERTIFICATE_UNAVAILABLE 28 +#define ISAKMP_NTYPE_UNSUPPORTED_EXCHANGE_TYPE 29 +#define ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS 30 +/* NOTIFY MESSAGES - STATUS TYPES */ +#define ISAKMP_NTYPE_CONNECTED 16384 +/* 4.6.3 IPSEC DOI Notify Message Types */ +#define ISAKMP_NTYPE_RESPONDER_LIFETIME 24576 +#define ISAKMP_NTYPE_REPLAY_STATUS 24577 +#define ISAKMP_NTYPE_INITIAL_CONTACT 24578 + +/* using only to log */ +#define ISAKMP_LOG_RETRY_LIMIT_REACHED 65530 + +/* XXX means internal error but it's not reserved by any drafts... */ +#define ISAKMP_INTERNAL_ERROR -1 + +/* 3.15 Delete Payload */ +struct isakmp_pl_d { + struct isakmp_gen h; + u_int32_t doi; /* Domain of Interpretation */ + u_int8_t proto_id; /* Protocol-Id */ + u_int8_t spi_size; /* SPI Size */ + u_int16_t num_spi; /* # of SPIs */ + /* SPI(es) */ +} __attribute__((__packed__)); + diff --git a/racoon.tproj/isakmp_agg.c b/racoon.tproj/isakmp_agg.c new file mode 100644 index 0000000..bc6e377 --- /dev/null +++ b/racoon.tproj/isakmp_agg.c @@ -0,0 +1,1215 @@ +/* $KAME: isakmp_agg.c,v 1.54 2001/12/11 20:33:41 sakane 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. 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. + */ + +/* Aggressive Exchange (Aggressive Mode) */ + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "localconf.h" +#include "remoteconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "pfkey.h" +#include "isakmp_agg.h" +#include "isakmp_inf.h" +#include "vendorid.h" +#include "strnames.h" + +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif + +/* + * begin Aggressive Mode as initiator. + */ +/* + * send to responder + * psk: HDR, SA, KE, Ni, IDi1 + * sig: HDR, SA, KE, Ni, IDi1 [, CR ] + * gssapi: HDR, SA, KE, Ni, IDi1, GSSi + * rsa: HDR, SA, [ HASH(1),] KE, Pubkey_r, Pubkey_r + * rev: HDR, SA, [ HASH(1),] Pubkey_r, Ke_i, + * Ke_i [, Ke_i ] + */ +int +agg_i1send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; /* must be null */ +{ + struct isakmp_gen *gen; + caddr_t p; + int tlen; + int need_cr = 0; + vchar_t *cr = NULL, *gsstoken = NULL; + int error = -1; + int nptype; +#ifdef HAVE_GSSAPI + int len; +#endif + + /* validity check */ + if (msg != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "msg has to be NULL in this function.\n"); + goto end; + } + if (iph1->status != PHASE1ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* create isakmp index */ + memset(&iph1->index, 0, sizeof(iph1->index)); + isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local); + + /* make ID payload into isakmp status */ + if (ipsecdoi_setid1(iph1) < 0) + goto end; + + /* create SA payload for my proposal */ + iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal); + if (iph1->sa == NULL) + goto end; + + /* consistency check of proposals */ + if (iph1->rmconf->dhgrp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "configuration failure about DH group.\n"); + goto end; + } + + /* generate DH public value */ + if (oakley_dh_generate(iph1->rmconf->dhgrp, + &iph1->dhpub, &iph1->dhpriv) < 0) + goto end; + + /* generate NONCE value */ + iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + if (iph1->nonce == NULL) + goto end; + +#ifdef HAVE_SIGNING_C + /* create CR if need */ + if (iph1->rmconf->send_cr + && oakley_needcr(iph1->rmconf->proposal->authmethod) + && iph1->rmconf->peerscertfile == NULL) { + need_cr = 1; + cr = oakley_getcr(iph1); + if (cr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer.\n"); + goto end; + } + } +#endif + plog(LLV_DEBUG, LOCATION, NULL, "authmethod is %s\n", + s_oakley_attr_method(iph1->rmconf->proposal->authmethod)); + /* create buffer to send isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(*gen) + iph1->sa->l + + sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->nonce->l + + sizeof(*gen) + iph1->id->l; + if (need_cr) + tlen += sizeof(*gen) + cr->l; +#ifdef HAVE_GSSAPI + if (iph1->rmconf->proposal->authmethod == + OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + gssapi_get_itoken(iph1, &len); + tlen += sizeof (*gen) + len; + } +#endif + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to propose */ + p = set_isakmp_payload(p, iph1->sa, ISAKMP_NPTYPE_KE); + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_NONCE); + + /* create isakmp NONCE payload */ + p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_ID); + + /* create isakmp ID payload */ +#ifdef HAVE_GSSAPI + if (iph1->rmconf->proposal->authmethod == + OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + nptype = ISAKMP_NPTYPE_GSS; + else +#endif + if (need_cr) + nptype = ISAKMP_NPTYPE_CR; + else + nptype = ISAKMP_NPTYPE_NONE; + + p = set_isakmp_payload(p, iph1->id, nptype); + +#ifdef HAVE_GSSAPI + if (iph1->rmconf->proposal->authmethod == + OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + gssapi_get_token_to_send(iph1, &gsstoken); + p = set_isakmp_payload(p, gsstoken, ISAKMP_NPTYPE_NONE); + } else +#endif + if (need_cr) + /* create isakmp CR payload */ + p = set_isakmp_payload(p, cr, ISAKMP_NPTYPE_NONE); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + iph1->status = PHASE1ST_MSG1SENT; + + error = 0; + +end: + if (cr) + vfree(cr); + if (gsstoken) + vfree(gsstoken); + + return error; +} + +/* + * receive from responder + * psk: HDR, SA, KE, Nr, IDr1, HASH_R + * sig: HDR, SA, KE, Nr, IDr1, [ CR, ] [ CERT, ] SIG_R + * gssapi: HDR, SA, KE, Nr, IDr1, GSSr, HASH_R + * rsa: HDR, SA, KE, PubKey_i, PubKey_i, HASH_R + * rev: HDR, SA, PubKey_i, Ke_r, Ke_r, HASH_R + */ +int +agg_i2recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + vchar_t *satmp = NULL; + int error = -1; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + iph1->pl_hash = NULL; + + /* SA payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_SA); + goto end; + } + if (isakmp_p2ph(&satmp, pa->ptr) < 0) + goto end; + pa++; + + for (/*nothing*/; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_ID: + if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_HASH: + iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CR: + if (oakley_savecr(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_CERT: + if (oakley_savecert(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_SIG: + if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) + goto end; + break; +#endif + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph1); + break; +#ifdef HAVE_GSSAPI + case ISAKMP_NPTYPE_GSS: + if (isakmp_p2ph(&gsstoken, pa->ptr) < 0) + goto end; + gssapi_save_received_token(iph1, gsstoken); + break; +#endif + default: + /* don't send information, see isakmp_ident_r1() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + /* XXX to be checked each authentication method. */ + + /* verify identifier */ + if (ipsecdoi_checkid1(iph1) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid ID payload.\n"); + goto end; + } + + /* check SA payload and set approval SA for use */ + if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to get valid proposal.\n"); + /* XXX send information */ + goto end; + } + if (iph1->sa_ret) { + vfree(iph1->sa_ret); + iph1->sa_ret = NULL; + } + + /* fix isakmp index */ + memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck, + sizeof(cookie_t)); + + /* compute sharing secret of DH */ + if (oakley_dh_compute(iph1->rmconf->dhgrp, iph1->dhpub, + iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) + goto end; + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid(iph1) < 0) + goto end; + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + + /* validate authentication value */ + { + int type; + type = oakley_validate_auth(iph1); + if (type != 0) { + if (type == -1) { + /* message printed inner oakley_validate_auth() */ + goto end; + } + isakmp_info_send_n1(iph1, type, NULL); + goto end; + } + } + +#ifdef HAVE_SIGNING_C + if (oakley_checkcr(iph1) < 0) { + /* Ignore this error in order to be interoperability. */ + ; + } +#endif + + /* change status of isakmp status entry */ + iph1->status = PHASE1ST_MSG2RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (satmp) + vfree(satmp); + if (error) { + VPTRINIT(iph1->dhpub_p); + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->id_p); + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + VPTRINIT(iph1->sig_p); + oakley_delcert(iph1->cr_p); + iph1->cr_p = NULL; + } + + return error; +} + +/* + * send to responder + * psk: HDR, HASH_I + * gssapi: HDR, HASH_I + * sig: HDR, [ CERT, ] SIG_I + * rsa: HDR, HASH_I + * rev: HDR, HASH_I + */ +int +agg_i2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_gen *gen; + char *p; + int tlen; + int need_cert = 0; + int error = -1; + vchar_t *gsshash = NULL; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* generate HASH to send */ + plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n"); + iph1->hash = oakley_ph1hash_common(iph1, GENERATE); + if (iph1->hash == NULL) { +#ifdef HAVE_GSSAPI + if (gssapi_more_tokens(iph1)) + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL); +#endif + goto end; + } + + tlen = sizeof(struct isakmp); + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + tlen += sizeof(*gen) + iph1->hash->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + + /* set HASH payload */ + p = set_isakmp_payload(p, iph1->hash, ISAKMP_NPTYPE_NONE); + break; +#ifdef HAVE_SIGNING_C + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + /* XXX if there is CR or not ? */ + + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + if (iph1->cert != NULL && iph1->rmconf->send_cert) + need_cert = 1; + + tlen += sizeof(*gen) + iph1->sig->l; + if (need_cert) + tlen += sizeof(*gen) + iph1->cert->pl->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, need_cert + ? ISAKMP_NPTYPE_CERT + : ISAKMP_NPTYPE_SIG); + if (p == NULL) + goto end; + + /* add CERT payload if there */ + if (need_cert) + p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG); + /* add SIG payload */ + p = set_isakmp_payload(p, iph1->sig, ISAKMP_NPTYPE_NONE); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + tlen += sizeof(*gen) + iph1->hash->l; + break; +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + gsshash = gssapi_wraphash(iph1); + if (gsshash == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to wrap hash\n"); + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL); + goto end; + } + tlen += sizeof(*gen) + gsshash->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + p = set_isakmp_payload(p, gsshash, ISAKMP_NPTYPE_NONE); + break; +#endif + } + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send to responder */ + if (isakmp_send(iph1, iph1->sendbuf) < 0) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + if (gsshash) + vfree(gsshash); + return error; +} + +/* + * receive from initiator + * psk: HDR, SA, KE, Ni, IDi1 + * sig: HDR, SA, KE, Ni, IDi1 [, CR ] + * gssapi: HDR, SA, KE, Ni, IDi1 , GSSi + * rsa: HDR, SA, [ HASH(1),] KE, Pubkey_r, Pubkey_r + * rev: HDR, SA, [ HASH(1),] Pubkey_r, Ke_i, + * Ke_i [, Ke_i ] + */ +int +agg_r1recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* SA payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_SA); + goto end; + } + if (isakmp_p2ph(&iph1->sa, pa->ptr) < 0) + goto end; + pa++; + + for (/*nothing*/; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + plog(LLV_DEBUG, LOCATION, NULL, + "received payload of type %s\n", + s_isakmp_nptype(pa->type)); + + switch (pa->type) { + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_ID: + if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CR: + if (oakley_savecr(iph1, pa->ptr) < 0) + goto end; + break; +#endif +#ifdef HAVE_GSSAPI + case ISAKMP_NPTYPE_GSS: + if (isakmp_p2ph(&gsstoken, pa->ptr) < 0) + goto end; + gssapi_save_received_token(iph1, gsstoken); + break; +#endif + default: + /* don't send information, see isakmp_ident_r1() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + /* XXX to be checked each authentication method. */ + + /* verify identifier */ + if (ipsecdoi_checkid1(iph1) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid ID payload.\n"); + goto end; + } + + /* check SA payload and set approval SA for use */ + if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to get valid proposal.\n"); + /* XXX send information */ + goto end; + } + +#ifdef HAVE_SIGNING_C + if (oakley_checkcr(iph1) < 0) { + /* Ignore this error in order to be interoperability. */ + ; + } +#endif + + iph1->status = PHASE1ST_MSG1RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (error) { + VPTRINIT(iph1->sa); + VPTRINIT(iph1->dhpub_p); + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->id_p); + oakley_delcert(iph1->cr_p); + iph1->cr_p = NULL; + } + + return error; +} + +/* + * send to initiator + * psk: HDR, SA, KE, Nr, IDr1, HASH_R + * sig: HDR, SA, KE, Nr, IDr1, [ CR, ] [ CERT, ] SIG_R + * gssapi: HDR, SA, KE, Nr, IDr1, GSSr, HASH_R + * rsa: HDR, SA, KE, PubKey_i, PubKey_i, HASH_R + * rev: HDR, SA, PubKey_i, Ke_r, Ke_r, HASH_R + */ +int +agg_r1send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_gen *gen; + char *p; + int tlen; + int need_cr = 0; + int need_cert = 0; + vchar_t *cr = NULL; + vchar_t *vid = NULL; + int error = -1; +#ifdef HAVE_GSSAPI + int gsslen; + vchar_t *gsstoken = NULL, *gsshash = NULL; + vchar_t *gss_sa = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* set responder's cookie */ + isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local); + + /* make ID payload into isakmp status */ + if (ipsecdoi_setid1(iph1) < 0) + goto end; + + /* generate DH public value */ + if (oakley_dh_generate(iph1->rmconf->dhgrp, + &iph1->dhpub, &iph1->dhpriv) < 0) + goto end; + + /* generate NONCE value */ + iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + if (iph1->nonce == NULL) + goto end; + + /* compute sharing secret of DH */ + if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, + iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) + goto end; + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid(iph1) < 0) + goto end; + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + +#ifdef HAVE_GSSAPI + if (iph1->rmconf->proposal->authmethod == + OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + gssapi_get_rtoken(iph1, &gsslen); +#endif + + /* generate HASH to send */ + plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_R\n"); + iph1->hash = oakley_ph1hash_common(iph1, GENERATE); + if (iph1->hash == NULL) { +#ifdef HAVE_GSSAPI + if (gssapi_more_tokens(iph1)) + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL); +#endif + goto end; + } + +#ifdef HAVE_SIGNING_C + /* create CR if need */ + if (iph1->rmconf->send_cr + && oakley_needcr(iph1->approval->authmethod) + && iph1->rmconf->peerscertfile == NULL) { + need_cr = 1; + cr = oakley_getcr(iph1); + if (cr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer.\n"); + goto end; + } + } +#endif + + tlen = sizeof(struct isakmp); + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + /* create buffer to send isakmp payload */ + tlen += sizeof(*gen) + iph1->sa_ret->l + + sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->nonce->l + + sizeof(*gen) + iph1->id->l + + sizeof(*gen) + iph1->hash->l; + if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) + tlen += sizeof(*gen) + vid->l; + if (need_cr) + tlen += sizeof(*gen) + cr->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to reply */ + p = set_isakmp_payload(p, iph1->sa_ret, ISAKMP_NPTYPE_KE); + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_NONCE); + + /* create isakmp NONCE payload */ + p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_ID); + + /* create isakmp ID payload */ + p = set_isakmp_payload(p, iph1->id, ISAKMP_NPTYPE_HASH); + + /* create isakmp HASH payload */ + p = set_isakmp_payload(p, iph1->hash, + vid ? ISAKMP_NPTYPE_VID + : (need_cr ? ISAKMP_NPTYPE_CR + : ISAKMP_NPTYPE_NONE)); + + /* append vendor id, if needed */ + if (vid) + p = set_isakmp_payload(p, vid, + need_cr ? ISAKMP_NPTYPE_CR + : ISAKMP_NPTYPE_NONE); + + /* create isakmp CR payload if needed */ + if (need_cr) + p = set_isakmp_payload(p, cr, ISAKMP_NPTYPE_NONE); + break; +#ifdef HAVE_SIGNING_C + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + /* XXX if there is CR or not ? */ + + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + if (iph1->cert != NULL && iph1->rmconf->send_cert) + need_cert = 1; + + tlen += sizeof(*gen) + iph1->sa_ret->l + + sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->nonce->l + + sizeof(*gen) + iph1->id->l + + sizeof(*gen) + iph1->sig->l; + if (need_cert) + tlen += sizeof(*gen) + iph1->cert->pl->l; + if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) + tlen += sizeof(*gen) + vid->l; + if (need_cr) + tlen += sizeof(*gen) + cr->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to reply */ + p = set_isakmp_payload(p, iph1->sa_ret, ISAKMP_NPTYPE_KE); + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_NONCE); + + /* create isakmp NONCE payload */ + p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_ID); + + /* add ID payload */ + p = set_isakmp_payload(p, iph1->id, need_cert + ? ISAKMP_NPTYPE_CERT + : ISAKMP_NPTYPE_SIG); + + /* add CERT payload if there */ + if (need_cert) + p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG); + /* add SIG payload */ + p = set_isakmp_payload(p, iph1->sig, + vid ? ISAKMP_NPTYPE_VID + : (need_cr ? ISAKMP_NPTYPE_CR + : ISAKMP_NPTYPE_NONE)); + + /* append vendor id, if needed */ + if (vid) + p = set_isakmp_payload(p, vid, + need_cr ? ISAKMP_NPTYPE_CR + : ISAKMP_NPTYPE_NONE); + + /* create isakmp CR payload if needed */ + if (need_cr) + p = set_isakmp_payload(p, cr, ISAKMP_NPTYPE_NONE); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + tlen += sizeof(*gen) + iph1->hash->l; + break; +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + /* create buffer to send isakmp payload */ + gsshash = gssapi_wraphash(iph1); + if (gsshash == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to wrap hash\n"); + /* + * This is probably due to the GSS roundtrips not + * being finished yet. Return this error in + * the hope that a fallback to main mode will + * be done. + */ + isakmp_info_send_n1(iph1, + ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, NULL); + goto end; + } + if (iph1->approval->gssid != NULL) + gss_sa = ipsecdoi_setph1proposal(iph1->approval); + else + gss_sa = iph1->sa_ret; + + tlen += sizeof(*gen) + gss_sa->l + + sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->nonce->l + + sizeof(*gen) + iph1->id->l + + sizeof(*gen) + gsslen + + sizeof(*gen) + gsshash->l; + if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) + tlen += sizeof(*gen) + vid->l; + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to reply */ + p = set_isakmp_payload(p, gss_sa, ISAKMP_NPTYPE_KE); + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_NONCE); + + /* create isakmp NONCE payload */ + p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_ID); + + /* create isakmp ID payload */ + p = set_isakmp_payload(p, iph1->id, ISAKMP_NPTYPE_GSS); + + /* create GSS payload */ + gssapi_get_token_to_send(iph1, &gsstoken); + p = set_isakmp_payload(p, gsstoken, ISAKMP_NPTYPE_HASH); + + /* create isakmp HASH payload */ + p = set_isakmp_payload(p, gsshash, + vid != NULL ? ISAKMP_NPTYPE_VID + : ISAKMP_NPTYPE_NONE); + + /* append vendor id, if needed */ + if (vid) + p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE); + break; +#endif + } + + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 1); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph1->status = PHASE1ST_MSG1SENT; + + error = 0; + +end: + if (cr) + vfree(cr); + if (vid) + vfree(vid); +#ifdef HAVE_GSSAPI + if (gsstoken) + vfree(gsstoken); + if (gsshash) + vfree(gsshash); + if (gss_sa != iph1->sa_ret) + vfree(gss_sa); +#endif + + return error; +} + +/* + * receive from initiator + * psk: HDR, HASH_I + * gssapi: HDR, HASH_I + * sig: HDR, [ CERT, ] SIG_I + * rsa: HDR, HASH_I + * rev: HDR, HASH_I + */ +int +agg_r2recv(iph1, msg0) + struct ph1handle *iph1; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* decrypting if need. */ + /* XXX configurable ? */ + if (ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + msg = oakley_do_decrypt(iph1, msg0, + iph1->ivm->iv, iph1->ivm->ive); + if (msg == NULL) + goto end; + } else + msg = vdup(msg0); + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + iph1->pl_hash = NULL; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CERT: + if (oakley_savecert(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_SIG: + if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) + goto end; + break; +#endif + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph1); + break; + default: + /* don't send information, see isakmp_ident_r1() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* validate authentication value */ + { + int type; + type = oakley_validate_auth(iph1); + if (type != 0) { + if (type == -1) { + /* message printed inner oakley_validate_auth() */ + goto end; + } + isakmp_info_send_n1(iph1, type, NULL); + goto end; + } + } + + iph1->status = PHASE1ST_MSG2RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (msg) + vfree(msg); + if (error) { + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + VPTRINIT(iph1->sig_p); + } + + return error; +} + +/* + * status update and establish isakmp sa. + */ +int +agg_r2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* IV synchronized when packet encrypted. */ + /* see handler.h about IV synchronization. */ + if (ISSET(((struct isakmp *)msg->v)->flags, ISAKMP_FLAG_E)) + memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l); + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + return error; +} diff --git a/racoon.tproj/isakmp_agg.h b/racoon.tproj/isakmp_agg.h new file mode 100644 index 0000000..f79ee1b --- /dev/null +++ b/racoon.tproj/isakmp_agg.h @@ -0,0 +1,39 @@ +/* $KAME: isakmp_agg.h,v 1.3 2000/09/13 04:50:25 itojun 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. 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. + */ + +extern int agg_i1send __P((struct ph1handle *, vchar_t *)); +extern int agg_i2recv __P((struct ph1handle *, vchar_t *)); +extern int agg_i2send __P((struct ph1handle *, vchar_t *)); + +extern int agg_r1recv __P((struct ph1handle *, vchar_t *)); +extern int agg_r1send __P((struct ph1handle *, vchar_t *)); +extern int agg_r2recv __P((struct ph1handle *, vchar_t *)); +extern int agg_r2send __P((struct ph1handle *, vchar_t *)); diff --git a/racoon.tproj/isakmp_base.c b/racoon.tproj/isakmp_base.c new file mode 100644 index 0000000..5878d94 --- /dev/null +++ b/racoon.tproj/isakmp_base.c @@ -0,0 +1,1068 @@ +/* $KAME: isakmp_base.c,v 1.47 2001/12/11 20:33:41 sakane 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. 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. + */ + +/* Base Exchange (Base Mode) */ + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "localconf.h" +#include "remoteconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "pfkey.h" +#include "isakmp_base.h" +#include "isakmp_inf.h" +#include "vendorid.h" + +/* %%% + * begin Identity Protection Mode as initiator. + */ +/* + * send to responder + * psk: HDR, SA, Idii, Ni_b + * sig: HDR, SA, Idii, Ni_b + * rsa: HDR, SA, [HASH(1),] Pubkey_r, Pubkey_r + * rev: HDR, SA, [HASH(1),] Pubkey_r, Ke_i + */ +int +base_i1send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; /* must be null */ +{ + struct isakmp_gen *gen; + caddr_t p; + int tlen; + int error = -1; + + /* validity check */ + if (msg != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "msg has to be NULL in this function.\n"); + goto end; + } + if (iph1->status != PHASE1ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* create isakmp index */ + memset(&iph1->index, 0, sizeof(iph1->index)); + isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local); + + /* make ID payload into isakmp status */ + if (ipsecdoi_setid1(iph1) < 0) + goto end; + + /* create SA payload for my proposal */ + iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal); + if (iph1->sa == NULL) + goto end; + + /* generate NONCE value */ + iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + if (iph1->nonce == NULL) + goto end; + + /* create buffer to send isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(*gen) + iph1->sa->l + + sizeof(*gen) + iph1->id->l + + sizeof(*gen) + iph1->nonce->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to propose */ + p = set_isakmp_payload(p, iph1->sa, ISAKMP_NPTYPE_ID); + + /* create isakmp ID payload */ + p = set_isakmp_payload(p, iph1->id, ISAKMP_NPTYPE_NONCE); + + /* create isakmp NONCE payload */ + p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_NONE); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + iph1->status = PHASE1ST_MSG1SENT; + + error = 0; + +end: + + return error; +} + +/* + * receive from responder + * psk: HDR, SA, Idir, Nr_b + * sig: HDR, SA, Idir, Nr_b, [ CR ] + * rsa: HDR, SA, PubKey_i, PubKey_i + * rev: HDR, SA, PubKey_i, Ke_r + */ +int +base_i2recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + vchar_t *satmp = NULL; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* SA payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_SA); + goto end; + } + if (isakmp_p2ph(&satmp, pa->ptr) < 0) + goto end; + pa++; + + for (/*nothing*/; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_ID: + if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + if (iph1->nonce_p == NULL || iph1->id_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* verify identifier */ + if (ipsecdoi_checkid1(iph1) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid ID payload.\n"); + goto end; + } + + /* check SA payload and set approval SA for use */ + if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to get valid proposal.\n"); + /* XXX send information */ + goto end; + } + if (iph1->sa_ret) { + vfree(iph1->sa_ret); + iph1->sa_ret = NULL; + } + + iph1->status = PHASE1ST_MSG2RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (satmp) + vfree(satmp); + + if (error) { + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->id_p); + } + + return error; +} + +/* + * send to responder + * psk: HDR, KE, HASH_I + * sig: HDR, KE, [ CR, ] [CERT,] SIG_I + * rsa: HDR, KE, HASH_I + * rev: HDR, Ke_i, HASH_I + */ +int +base_i2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_gen *gen; + caddr_t p; + vchar_t *vid = NULL; + int tlen; + int need_cert = 0; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* fix isakmp index */ + memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck, + sizeof(cookie_t)); + + /* generate DH public value */ + if (oakley_dh_generate(iph1->approval->dhgrp, + &iph1->dhpub, &iph1->dhpriv) < 0) + goto end; + + /* generate SKEYID to compute hash if not signature mode */ + if (iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG + && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_DSSSIG) { + if (oakley_skeyid(iph1) < 0) + goto end; + } + + /* generate HASH to send */ + plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n"); + iph1->hash = oakley_ph1hash_base_i(iph1, GENERATE); + if (iph1->hash == NULL) + goto end; + + /* create buffer to send isakmp payload */ + tlen = sizeof(struct isakmp); + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + tlen += sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->hash->l; + if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) + tlen += sizeof(*gen) + vid->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); + if (p == NULL) + goto end; + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_HASH); + + /* create isakmp HASH payload */ + p = set_isakmp_payload(p, iph1->hash, + vid ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE); + + /* append vendor id, if needed */ + if (vid) + p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE); + break; +#ifdef HAVE_SIGNING_C + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + /* XXX if there is CR or not ? */ + + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + if (iph1->cert && iph1->rmconf->send_cert) + need_cert = 1; + + tlen += sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->sig->l; + if (need_cert) + tlen += sizeof(*gen) + iph1->cert->pl->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); + if (p == NULL) + goto end; + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, need_cert + ? ISAKMP_NPTYPE_CERT + : ISAKMP_NPTYPE_SIG); + + /* add CERT payload if there */ + if (need_cert) + p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG); + /* add SIG payload */ + p = set_isakmp_payload(p, iph1->sig, ISAKMP_NPTYPE_NONE); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + /* ... */ + break; + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + tlen += sizeof(*gen) + iph1->hash->l; + break; + } + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph1->status = PHASE1ST_MSG2SENT; + + error = 0; + +end: + if (vid) + vfree(vid); + return error; +} + +/* + * receive from responder + * psk: HDR, KE, HASH_R + * sig: HDR, KE, [CERT,] SIG_R + * rsa: HDR, KE, HASH_R + * rev: HDR, _Ke_r, HASH_R + */ +int +base_i3recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_HASH: + iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CERT: + if (oakley_savecert(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_SIG: + if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) + goto end; + break; +#endif + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + /* validate authentication value */ + { + int type; + type = oakley_validate_auth(iph1); + if (type != 0) { + if (type == -1) { + /* message printed inner oakley_validate_auth() */ + goto end; + } + isakmp_info_send_n1(iph1, type, NULL); + goto end; + } + } + + /* compute sharing secret of DH */ + if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, + iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) + goto end; + + /* generate SKEYID to compute hash if signature mode */ + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_RSASIG + || iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_DSSSIG) { + if (oakley_skeyid(iph1) < 0) + goto end; + } + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + + /* see handler.h about IV synchronization. */ + memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l); + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + iph1->status = PHASE1ST_MSG3RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + + if (error) { + VPTRINIT(iph1->dhpub_p); + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + VPTRINIT(iph1->sig_p); + } + + return error; +} + +/* + * status update and establish isakmp sa. + */ +int +base_i3send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG3RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + return error; +} + +/* + * receive from initiator + * psk: HDR, SA, Idii, Ni_b + * sig: HDR, SA, Idii, Ni_b + * rsa: HDR, SA, [HASH(1),] Pubkey_r, Pubkey_r + * rev: HDR, SA, [HASH(1),] Pubkey_r, Ke_i + */ +int +base_r1recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + /* + * NOTE: XXX even if multiple VID, we'll silently ignore those. + */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* check the position of SA payload */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_SA); + goto end; + } + if (isakmp_p2ph(&iph1->sa, pa->ptr) < 0) + goto end; + pa++; + + for (/*nothing*/; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_ID: + if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + if (iph1->nonce_p == NULL || iph1->id_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* verify identifier */ + if (ipsecdoi_checkid1(iph1) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid ID payload.\n"); + goto end; + } + + /* check SA payload and set approval SA for use */ + if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to get valid proposal.\n"); + /* XXX send information */ + goto end; + } + + iph1->status = PHASE1ST_MSG1RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + + if (error) { + VPTRINIT(iph1->sa); + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->id_p); + } + + return error; +} + +/* + * send to initiator + * psk: HDR, SA, Idir, Nr_b + * sig: HDR, SA, Idir, Nr_b, [ CR ] + * rsa: HDR, SA, PubKey_i, PubKey_i + * rev: HDR, SA, PubKey_i, Ke_r + */ +int +base_r1send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_gen *gen; + caddr_t p; + int tlen; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* set responder's cookie */ + isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local); + + /* make ID payload into isakmp status */ + if (ipsecdoi_setid1(iph1) < 0) + goto end; + + /* generate NONCE value */ + iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + if (iph1->nonce == NULL) + goto end; + + /* create buffer to send isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(*gen) + iph1->sa_ret->l + + sizeof(*gen) + iph1->id->l + + sizeof(*gen) + iph1->nonce->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to reply */ + p = set_isakmp_payload(p, iph1->sa_ret, ISAKMP_NPTYPE_ID); + + /* create isakmp ID payload */ + p = set_isakmp_payload(p, iph1->id, ISAKMP_NPTYPE_NONCE); + + /* create isakmp NONCE payload */ + p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_NONE); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph1->status = PHASE1ST_MSG1SENT; + + error = 0; + +end: + if (iph1->sa_ret) { + vfree(iph1->sa_ret); + iph1->sa_ret = NULL; + } + + return error; +} + +/* + * receive from initiator + * psk: HDR, KE, HASH_I + * sig: HDR, KE, [ CR, ] [CERT,] SIG_I + * rsa: HDR, KE, HASH_I + * rev: HDR, Ke_i, HASH_I + */ +int +base_r2recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + iph1->pl_hash = NULL; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_HASH: + iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CERT: + if (oakley_savecert(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_SIG: + if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) + goto end; + break; +#endif + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* generate DH public value */ + if (oakley_dh_generate(iph1->approval->dhgrp, + &iph1->dhpub, &iph1->dhpriv) < 0) + goto end; + + /* compute sharing secret of DH */ + if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, + iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) + goto end; + + /* generate SKEYID */ + if (oakley_skeyid(iph1) < 0) + goto end; + + /* payload existency check */ + /* validate authentication value */ + { + int type; + type = oakley_validate_auth(iph1); + if (type != 0) { + if (type == -1) { + /* message printed inner oakley_validate_auth() */ + goto end; + } + isakmp_info_send_n1(iph1, type, NULL); + goto end; + } + } + + iph1->status = PHASE1ST_MSG2RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + + if (error) { + VPTRINIT(iph1->dhpub_p); + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + VPTRINIT(iph1->sig_p); + } + + return error; +} + +/* + * send to initiator + * psk: HDR, KE, HASH_R + * sig: HDR, KE, [CERT,] SIG_R + * rsa: HDR, KE, HASH_R + * rev: HDR, _Ke_r, HASH_R + */ +int +base_r2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_gen *gen; + char *p; + vchar_t *vid = NULL; + int tlen; + int need_cert = 0; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* generate HASH to send */ + plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n"); + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + iph1->hash = oakley_ph1hash_common(iph1, GENERATE); + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + iph1->hash = oakley_ph1hash_base_r(iph1, GENERATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication method %d\n", + iph1->approval->authmethod); + goto end; + } + if (iph1->hash == NULL) + goto end; + + /* create HDR;KE;NONCE payload */ + tlen = sizeof(struct isakmp); + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + tlen += sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->hash->l; + if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) + tlen += sizeof(*gen) + vid->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iph1->sendbuf to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); + if (p == NULL) + goto end; + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_HASH); + + /* create isakmp HASH payload */ + p = set_isakmp_payload(p, iph1->hash, + vid ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE); + + /* append vendor id, if needed */ + if (vid) + p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE); + break; +#ifdef HAVE_SIGNING_C + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + /* XXX if there is CR or not ? */ + + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + if (iph1->cert && iph1->rmconf->send_cert) + need_cert = 1; + + tlen += sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->sig->l; + if (need_cert) + tlen += sizeof(*gen) + iph1->cert->pl->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); + if (p == NULL) + goto end; + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, need_cert + ? ISAKMP_NPTYPE_CERT + : ISAKMP_NPTYPE_SIG); + + /* add CERT payload if there */ + if (need_cert) + p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG); + /* add SIG payload */ + p = set_isakmp_payload(p, iph1->sig, ISAKMP_NPTYPE_NONE); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + /* ... */ + break; + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + tlen += sizeof(*gen) + iph1->hash->l; + break; + } + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send HDR;KE;NONCE to responder */ + if (isakmp_send(iph1, iph1->sendbuf) < 0) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + if (vid) + vfree(vid); + return error; +} diff --git a/racoon.tproj/isakmp_base.h b/racoon.tproj/isakmp_base.h new file mode 100644 index 0000000..72efde1 --- /dev/null +++ b/racoon.tproj/isakmp_base.h @@ -0,0 +1,41 @@ +/* $KAME: isakmp_base.h,v 1.5 2000/09/21 15:18:25 sakane 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. 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. + */ + +extern int base_i1send __P((struct ph1handle *, vchar_t *)); +extern int base_i2recv __P((struct ph1handle *, vchar_t *)); +extern int base_i2send __P((struct ph1handle *, vchar_t *)); +extern int base_i3recv __P((struct ph1handle *, vchar_t *)); +extern int base_i3send __P((struct ph1handle *, vchar_t *)); + +extern int base_r1recv __P((struct ph1handle *, vchar_t *)); +extern int base_r1send __P((struct ph1handle *, vchar_t *)); +extern int base_r2recv __P((struct ph1handle *, vchar_t *)); +extern int base_r2send __P((struct ph1handle *, vchar_t *)); diff --git a/racoon.tproj/isakmp_ident.c b/racoon.tproj/isakmp_ident.c new file mode 100644 index 0000000..4e15a47 --- /dev/null +++ b/racoon.tproj/isakmp_ident.c @@ -0,0 +1,1699 @@ +/* $KAME: isakmp_ident.c,v 1.62 2001/12/12 15:29:13 sakane 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. 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. + */ + +/* Identity Protecion Exchange (Main Mode) */ + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "schedule.h" +#include "debug.h" + +#include "localconf.h" +#include "remoteconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "pfkey.h" +#include "isakmp_ident.h" +#include "isakmp_inf.h" +#include "vendorid.h" + +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif + +static vchar_t *ident_ir2mx __P((struct ph1handle *)); +static vchar_t *ident_ir3mx __P((struct ph1handle *)); + +/* %%% + * begin Identity Protection Mode as initiator. + */ +/* + * send to responder + * psk: HDR, SA + * sig: HDR, SA + * rsa: HDR, SA + * rev: HDR, SA + */ +int +ident_i1send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; /* must be null */ +{ + struct isakmp_gen *gen; + caddr_t p; + int tlen; + int error = -1; + + /* validity check */ + if (msg != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "msg has to be NULL in this function.\n"); + goto end; + } + if (iph1->status != PHASE1ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* create isakmp index */ + memset(&iph1->index, 0, sizeof(iph1->index)); + isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local); + + /* create SA payload for my proposal */ + iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal); + if (iph1->sa == NULL) + goto end; + + /* create buffer to send isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(*gen) + iph1->sa->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to propose */ + p = set_isakmp_payload(p, iph1->sa, ISAKMP_NPTYPE_NONE); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + iph1->status = PHASE1ST_MSG1SENT; + + error = 0; + +end: + + return error; +} + +/* + * receive from responder + * psk: HDR, SA + * sig: HDR, SA + * rsa: HDR, SA + * rev: HDR, SA + */ +int +ident_i2recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + vchar_t *satmp = NULL; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + /* + * NOTE: RedCreek(as responder) attaches N[responder-lifetime] here, + * if proposal-lifetime > lifetime-redcreek-wants. + * (see doi-08 4.5.4) + * => According to the seciton 4.6.3 in RFC 2407, This is illegal. + * NOTE: we do not really care about ordering of VID and N. + * does it matters? + * NOTE: even if there's multiple VID/N, we'll ignore them. + */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* SA payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_SA); + goto end; + } + if (isakmp_p2ph(&satmp, pa->ptr) < 0) + goto end; + pa++; + + for (/*nothing*/; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* check SA payload and set approval SA for use */ + if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to get valid proposal.\n"); + /* XXX send information */ + goto end; + } + if (iph1->sa_ret) { + vfree(iph1->sa_ret); + iph1->sa_ret = NULL; + } + + iph1->status = PHASE1ST_MSG2RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (satmp) + vfree(satmp); + return error; +} + +/* + * send to responder + * psk: HDR, KE, Ni + * sig: HDR, KE, Ni + * gssapi: HDR, KE, Ni, GSSi + * rsa: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r + * rev: HDR, [ HASH(1), ] Pubkey_r, Ke_i, + * Ke_i, [<Ke_i] + */ +int +ident_i2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* fix isakmp index */ + memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck, + sizeof(cookie_t)); + + /* generate DH public value */ + if (oakley_dh_generate(iph1->approval->dhgrp, + &iph1->dhpub, &iph1->dhpriv) < 0) + goto end; + + /* generate NONCE value */ + iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + if (iph1->nonce == NULL) + goto end; + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + gssapi_get_itoken(iph1, NULL) < 0) + goto end; +#endif + + /* create buffer to send isakmp payload */ + iph1->sendbuf = ident_ir2mx(iph1); + if (iph1->sendbuf == NULL) + goto end; + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph1->status = PHASE1ST_MSG2SENT; + + error = 0; + +end: + return error; +} + +/* + * receive from responder + * psk: HDR, KE, Nr + * sig: HDR, KE, Nr [, CR ] + * gssapi: HDR, KE, Nr, GSSr + * rsa: HDR, KE, PubKey_i, PubKey_i + * rev: HDR, PubKey_i, Ke_r, Ke_r, + */ +int +ident_i3recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CR: + if (oakley_savecr(iph1, pa->ptr) < 0) + goto end; + break; +#endif +#ifdef HAVE_GSSAPI + case ISAKMP_NPTYPE_GSS: + if (isakmp_p2ph(&gsstoken, pa->ptr) < 0) + goto end; + gssapi_save_received_token(iph1, gsstoken); + break; +#endif + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + goto end; + } + +#ifdef HAVE_SIGNING_C + if (oakley_checkcr(iph1) < 0) { + /* Ignore this error in order to be interoperability. */ + ; + } +#endif + + iph1->status = PHASE1ST_MSG3RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (error) { + VPTRINIT(iph1->dhpub_p); + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->id_p); + oakley_delcert(iph1->cr_p); + iph1->cr_p = NULL; + } + + return error; +} + +/* + * send to responder + * psk: HDR*, IDi1, HASH_I + * sig: HDR*, IDi1, [ CR, ] [ CERT, ] SIG_I + * gssapi: HDR*, IDi1, < Gssi(n) | HASH_I > + * rsa: HDR*, HASH_I + * rev: HDR*, HASH_I + */ +int +ident_i3send(iph1, msg0) + struct ph1handle *iph1; + vchar_t *msg0; +{ + int error = -1; + int dohash = 1; +#ifdef HAVE_GSSAPI + int len; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG3RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* compute sharing secret of DH */ + if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, + iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) + goto end; + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid(iph1) < 0) + goto end; + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + + /* make ID payload into isakmp status */ + if (ipsecdoi_setid1(iph1) < 0) + goto end; + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + gssapi_more_tokens(iph1)) { + plog(LLV_DEBUG, LOCATION, NULL, "calling get_itoken\n"); + if (gssapi_get_itoken(iph1, &len) < 0) + goto end; + if (len != 0) + dohash = 0; + } +#endif + + /* generate HASH to send */ + if (dohash) { + iph1->hash = oakley_ph1hash_common(iph1, GENERATE); + if (iph1->hash == NULL) + goto end; + } else + iph1->hash = NULL; + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + /* create HDR;ID;HASH payload */ + iph1->sendbuf = ident_ir3mx(iph1); + if (iph1->sendbuf == NULL) + goto end; + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg0) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* see handler.h about IV synchronization. */ + memcpy(iph1->ivm->ive->v, iph1->ivm->iv->v, iph1->ivm->iv->l); + + iph1->status = PHASE1ST_MSG3SENT; + + error = 0; + +end: + return error; +} + +/* + * receive from responder + * psk: HDR*, IDr1, HASH_R + * sig: HDR*, IDr1, [ CERT, ] SIG_R + * gssapi: HDR*, IDr1, < GSSr(n) | HASH_R > + * rsa: HDR*, HASH_R + * rev: HDR*, HASH_R + */ +int +ident_i4recv(iph1, msg0) + struct ph1handle *iph1; + vchar_t *msg0; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + vchar_t *msg = NULL; + int error = -1; + int type; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG3SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* decrypting */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "expecting the packet encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph1, msg0, iph1->ivm->iv, iph1->ivm->ive); + if (msg == NULL) + goto end; + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + iph1->pl_hash = NULL; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_ID: + if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_HASH: + iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CERT: + if (oakley_savecert(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_SIG: + if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) + goto end; + break; +#endif +#ifdef HAVE_GSSAPI + case ISAKMP_NPTYPE_GSS: + if (isakmp_p2ph(&gsstoken, pa->ptr) < 0) + goto end; + gssapi_save_received_token(iph1, gsstoken); + break; +#endif + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph1); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + + /* see handler.h about IV synchronization. */ + memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->ive->l); + + /* verify identifier */ + if (ipsecdoi_checkid1(iph1) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid ID payload.\n"); + goto end; + } + + /* validate authentication value */ +#ifdef HAVE_GSSAPI + if (gsstoken == NULL) { +#endif + type = oakley_validate_auth(iph1); + if (type != 0) { + if (type == -1) { + /* msg printed inner oakley_validate_auth() */ + goto end; + } + isakmp_info_send_n1(iph1, type, NULL); + goto end; + } +#ifdef HAVE_GSSAPI + } +#endif + + /* + * XXX: Should we do compare two addresses, ph1handle's and ID + * payload's. + */ + + plog(LLV_DEBUG, LOCATION, iph1->remote, "peer's ID:"); + plogdump(LLV_DEBUG, iph1->id_p->v, iph1->id_p->l); + + /* + * If we got a GSS token, we need to this roundtrip again. + */ +#ifdef HAVE_GSSAPI + iph1->status = gsstoken != 0 ? PHASE1ST_MSG3RECEIVED : + PHASE1ST_MSG4RECEIVED; +#else + iph1->status = PHASE1ST_MSG4RECEIVED; +#endif + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (msg) + vfree(msg); +#ifdef HAVE_GSSAPI + if (gsstoken) + vfree(gsstoken); +#endif + + if (error) { + VPTRINIT(iph1->id_p); + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + VPTRINIT(iph1->sig_p); + } + + return error; +} + +/* + * status update and establish isakmp sa. + */ +int +ident_i4send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG4RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* see handler.h about IV synchronization. */ + memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l); + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + return error; +} + +/* + * receive from initiator + * psk: HDR, SA + * sig: HDR, SA + * rsa: HDR, SA + * rev: HDR, SA + */ +int +ident_r1recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + /* + * NOTE: XXX even if multiple VID, we'll silently ignore those. + */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* check the position of SA payload */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_SA); + goto end; + } + if (isakmp_p2ph(&iph1->sa, pa->ptr) < 0) + goto end; + pa++; + + for (/*nothing*/; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + /* + * We don't send information to the peer even + * if we received malformed packet. Because we + * can't distinguish the malformed packet and + * the re-sent packet. And we do same behavior + * when we expect encrypted packet. + */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* check SA payload and set approval SA for use */ + if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "failed to get valid proposal.\n"); + /* XXX send information */ + goto end; + } + + iph1->status = PHASE1ST_MSG1RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (error) { + VPTRINIT(iph1->sa); + } + + return error; +} + +/* + * send to initiator + * psk: HDR, SA + * sig: HDR, SA + * rsa: HDR, SA + * rev: HDR, SA + */ +int +ident_r1send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_gen *gen; + caddr_t p; + int tlen; + int error = -1; + vchar_t *gss_sa = NULL; + vchar_t *vid = NULL; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* set responder's cookie */ + isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local); + +#ifdef HAVE_GSSAPI + if (iph1->approval->gssid != NULL) + gss_sa = ipsecdoi_setph1proposal(iph1->approval); + else +#endif + gss_sa = iph1->sa_ret; + + /* create buffer to send isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(*gen) + gss_sa->l; + + if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) + tlen += sizeof(*gen) + vid->l; + + iph1->sendbuf = vmalloc(tlen); + if (iph1->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); + if (p == NULL) + goto end; + + /* set SA payload to reply */ + p = set_isakmp_payload(p, gss_sa, + vid ? ISAKMP_NPTYPE_VID + : ISAKMP_NPTYPE_NONE); + + /* Set Vendor ID, if necessary. */ + if (vid) + p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph1->status = PHASE1ST_MSG1SENT; + + error = 0; + +end: +#ifdef HAVE_GSSAPI + if (gss_sa != iph1->sa_ret) + vfree(gss_sa); +#endif + if (vid) + vfree(vid); + return error; +} + +/* + * receive from initiator + * psk: HDR, KE, Ni + * sig: HDR, KE, Ni + * gssapi: HDR, KE, Ni, GSSi + * rsa: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r + * rev: HDR, [ HASH(1), ] Pubkey_r, Ke_i, + * Ke_i, [<Ke_i] + */ +int +ident_r2recv(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + case ISAKMP_NPTYPE_CR: + plog(LLV_WARNING, LOCATION, iph1->remote, + "CR received, ignore it. " + "It should be in other exchange.\n"); + break; +#ifdef HAVE_GSSAPI + case ISAKMP_NPTYPE_GSS: + if (isakmp_p2ph(&gsstoken, pa->ptr) < 0) + goto end; + gssapi_save_received_token(iph1, gsstoken); + break; +#endif + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + if (iph1->dhpub_p == NULL || iph1->nonce_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + goto end; + } + + iph1->status = PHASE1ST_MSG2RECEIVED; + + error = 0; + +end: + if (pbuf) + vfree(pbuf); +#ifdef HAVE_GSSAPI + if (gsstoken) + vfree(gsstoken); +#endif + + if (error) { + VPTRINIT(iph1->dhpub_p); + VPTRINIT(iph1->nonce_p); + VPTRINIT(iph1->id_p); + } + + return error; +} + +/* + * send to initiator + * psk: HDR, KE, Nr + * sig: HDR, KE, Nr [, CR ] + * gssapi: HDR, KE, Nr, GSSr + * rsa: HDR, KE, PubKey_i, PubKey_i + * rev: HDR, PubKey_i, Ke_r, Ke_r, + */ +int +ident_r2send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* generate DH public value */ + if (oakley_dh_generate(iph1->approval->dhgrp, + &iph1->dhpub, &iph1->dhpriv) < 0) + goto end; + + /* generate NONCE value */ + iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); + if (iph1->nonce == NULL) + goto end; + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + gssapi_get_rtoken(iph1, NULL); +#endif + + /* create HDR;KE;NONCE payload */ + iph1->sendbuf = ident_ir2mx(iph1); + if (iph1->sendbuf == NULL) + goto end; + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); +#endif + + /* send the packet, add to the schedule to resend */ + iph1->retry_counter = iph1->rmconf->retry_counter; + if (isakmp_ph1resend(iph1) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* compute sharing secret of DH */ + if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, + iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) + goto end; + + /* generate SKEYIDs & IV & final cipher key */ + if (oakley_skeyid(iph1) < 0) + goto end; + if (oakley_skeyid_dae(iph1) < 0) + goto end; + if (oakley_compute_enckey(iph1) < 0) + goto end; + if (oakley_newiv(iph1) < 0) + goto end; + + iph1->status = PHASE1ST_MSG2SENT; + + error = 0; + +end: + return error; +} + +/* + * receive from initiator + * psk: HDR*, IDi1, HASH_I + * sig: HDR*, IDi1, [ CR, ] [ CERT, ] SIG_I + * gssapi: HDR*, [ IDi1, ] < GSSi(n) | HASH_I > + * rsa: HDR*, HASH_I + * rev: HDR*, HASH_I + */ +int +ident_r3recv(iph1, msg0) + struct ph1handle *iph1; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + int error = -1; + int type; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG2SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* decrypting */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "reject the packet, " + "expecting the packet encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph1, msg0, iph1->ivm->iv, iph1->ivm->ive); + if (msg == NULL) + goto end; + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + iph1->pl_hash = NULL; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_ID: + if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_HASH: + iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; + break; +#ifdef HAVE_SIGNING_C + case ISAKMP_NPTYPE_CR: + if (oakley_savecr(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_CERT: + if (oakley_savecert(iph1, pa->ptr) < 0) + goto end; + break; + case ISAKMP_NPTYPE_SIG: + if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) + goto end; + break; +#endif +#ifdef HAVE_GSSAPI + case ISAKMP_NPTYPE_GSS: + if (isakmp_p2ph(&gsstoken, pa->ptr) < 0) + goto end; + gssapi_save_received_token(iph1, gsstoken); + break; +#endif + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph1); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + /* XXX same as ident_i4recv(), should be merged. */ + { + int ng = 0; + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + if (iph1->id_p == NULL || iph1->pl_hash == NULL) + ng++; + break; + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + if (iph1->id_p == NULL || iph1->sig_p == NULL) + ng++; + break; + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + if (iph1->pl_hash == NULL) + ng++; + break; +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + if (gsstoken == NULL && iph1->pl_hash == NULL) + ng++; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid authmethod %d why ?\n", + iph1->approval->authmethod); + goto end; + } + if (ng) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + goto end; + } + } + + /* see handler.h about IV synchronization. */ + memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->ive->l); + + /* verify identifier */ + if (ipsecdoi_checkid1(iph1) != 0) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid ID payload.\n"); + goto end; + } + + /* validate authentication value */ +#ifdef HAVE_GSSAPI + if (gsstoken == NULL) { +#endif + type = oakley_validate_auth(iph1); + if (type != 0) { + if (type == -1) { + /* msg printed inner oakley_validate_auth() */ + goto end; + } + isakmp_info_send_n1(iph1, type, NULL); + goto end; + } +#ifdef HAVE_GSSAPI + } +#endif + +#ifdef HAVE_SIGNING_C + if (oakley_checkcr(iph1) < 0) { + /* Ignore this error in order to be interoperability. */ + ; + } +#endif + + /* + * XXX: Should we do compare two addresses, ph1handle's and ID + * payload's. + */ + + plog(LLV_DEBUG, LOCATION, iph1->remote, "peer's ID\n"); + plogdump(LLV_DEBUG, iph1->id_p->v, iph1->id_p->l); + +#ifdef HAVE_GSSAPI + iph1->status = gsstoken != NULL ? PHASE1ST_MSG2RECEIVED : + PHASE1ST_MSG3RECEIVED; +#else + iph1->status = PHASE1ST_MSG3RECEIVED; +#endif + + error = 0; + +end: + if (pbuf) + vfree(pbuf); + if (msg) + vfree(msg); +#ifdef HAVE_GSSAPI + if (gsstoken) + vfree(gsstoken); +#endif + + if (error) { + VPTRINIT(iph1->id_p); + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + oakley_delcert(iph1->crl_p); + iph1->crl_p = NULL; + VPTRINIT(iph1->sig_p); + oakley_delcert(iph1->cr_p); + iph1->cr_p = NULL; + } + + return error; +} + +/* + * send to initiator + * psk: HDR*, IDr1, HASH_R + * sig: HDR*, IDr1, [ CERT, ] SIG_R + * gssapi: HDR*, IDr1, < GSSr(n) | HASH_R > + * rsa: HDR*, HASH_R + * rev: HDR*, HASH_R + */ +int +ident_r3send(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + int error = -1; + int dohash = 1; +#ifdef HAVE_GSSAPI + int len; +#endif + + /* validity check */ + if (iph1->status != PHASE1ST_MSG3RECEIVED) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph1->status); + goto end; + } + + /* make ID payload into isakmp status */ + if (ipsecdoi_setid1(iph1) < 0) + goto end; + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB && + gssapi_more_tokens(iph1)) { + gssapi_get_rtoken(iph1, &len); + if (len != 0) + dohash = 0; + } +#endif + + if (dohash) { + /* generate HASH to send */ + plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_R\n"); + iph1->hash = oakley_ph1hash_common(iph1, GENERATE); + if (iph1->hash == NULL) + goto end; + } else + iph1->hash = NULL; + + /* set encryption flag */ + iph1->flags |= ISAKMP_FLAG_E; + + /* create HDR;ID;HASH payload */ + iph1->sendbuf = ident_ir3mx(iph1); + if (iph1->sendbuf == NULL) + goto end; + + /* send HDR;ID;HASH to responder */ + if (isakmp_send(iph1, iph1->sendbuf) < 0) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* see handler.h about IV synchronization. */ + memcpy(iph1->ivm->ive->v, iph1->ivm->iv->v, iph1->ivm->iv->l); + + iph1->status = PHASE1ST_ESTABLISHED; + + error = 0; + +end: + + return error; +} + +/* + * This is used in main mode for: + * initiator's 3rd exchange send to responder + * psk: HDR, KE, Ni + * sig: HDR, KE, Ni + * rsa: HDR, KE, [ HASH(1), ] PubKey_r, PubKey_r + * rev: HDR, [ HASH(1), ] Pubkey_r, Ke_i, + * Ke_i, [<Ke_i] + * responders 2nd exchnage send to initiator + * psk: HDR, KE, Nr + * sig: HDR, KE, Nr [, CR ] + * rsa: HDR, KE, PubKey_i, PubKey_i + * rev: HDR, PubKey_i, Ke_r, Ke_r, + */ +static vchar_t * +ident_ir2mx(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = 0; + struct isakmp_gen *gen; + char *p; + int tlen; + int need_cr = 0; + vchar_t *cr = NULL; + vchar_t *vid = NULL; + int error = -1; + int nptype; +#ifdef HAVE_GSSAPI + vchar_t *gsstoken = NULL; +#endif + +#ifdef HAVE_SIGNING_C + /* create CR if need */ + if (iph1->side == RESPONDER + && iph1->rmconf->send_cr + && oakley_needcr(iph1->approval->authmethod) + && iph1->rmconf->peerscertfile == NULL) { + need_cr = 1; + cr = oakley_getcr(iph1); + if (cr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer.\n"); + goto end; + } + } +#endif + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + gssapi_get_token_to_send(iph1, &gsstoken); +#endif + + /* create buffer */ + tlen = sizeof(struct isakmp) + + sizeof(*gen) + iph1->dhpub->l + + sizeof(*gen) + iph1->nonce->l; + if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) + tlen += sizeof(*gen) + vid->l; + if (need_cr) + tlen += sizeof(*gen) + cr->l; +#ifdef HAVE_GSSAPI + if (gsstoken) + tlen += sizeof(*gen) + gsstoken->l; +#endif + + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(buf, iph1, ISAKMP_NPTYPE_KE); + if (p == NULL) + goto end; + + /* create isakmp KE payload */ + p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_NONCE); + + /* create isakmp NONCE payload */ +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) + nptype = ISAKMP_NPTYPE_GSS; + else +#endif + nptype = vid ? ISAKMP_NPTYPE_VID : + (need_cr ? ISAKMP_NPTYPE_CR : ISAKMP_NPTYPE_NONE); + p = set_isakmp_payload(p, iph1->nonce, nptype); + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + p = set_isakmp_payload(p, gsstoken, + vid ? ISAKMP_NPTYPE_VID + : (need_cr ? ISAKMP_NPTYPE_CR + : ISAKMP_NPTYPE_NONE)); + } +#endif + + /* append vendor id, if needed */ + if (vid) + p = set_isakmp_payload(p, vid, + need_cr ? ISAKMP_NPTYPE_CR + : ISAKMP_NPTYPE_NONE); + + /* create isakmp CR payload if needed */ + if (need_cr) + p = set_isakmp_payload(p, cr, ISAKMP_NPTYPE_NONE); + + error = 0; + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + if (cr) + vfree(cr); +#ifdef HAVE_GSSAPI + if (gsstoken) + vfree(gsstoken); +#endif + if (vid) + vfree(vid); + + return buf; +} + +/* + * This is used in main mode for: + * initiator's 4th exchange send to responder + * psk: HDR*, IDi1, HASH_I + * sig: HDR*, IDi1, [ CR, ] [ CERT, ] SIG_I + * gssapi: HDR*, [ IDi1, ] < GSSi(n) | HASH_I > + * rsa: HDR*, HASH_I + * rev: HDR*, HASH_I + * responders 3rd exchnage send to initiator + * psk: HDR*, IDr1, HASH_R + * sig: HDR*, IDr1, [ CERT, ] SIG_R + * gssapi: HDR*, [ IDr1, ] < GSSr(n) | HASH_R > + * rsa: HDR*, HASH_R + * rev: HDR*, HASH_R + */ +static vchar_t * +ident_ir3mx(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL, *new = NULL; + char *p; + int tlen; + struct isakmp_gen *gen; + int need_cr = 0; + int need_cert = 0; + vchar_t *cr = NULL; + int error = -1; +#ifdef HAVE_GSSAPI + int nptype; + vchar_t *gsstoken = NULL; + vchar_t *gsshash = NULL; +#endif + + tlen = sizeof(struct isakmp); + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + tlen += sizeof(*gen) + iph1->id->l + + sizeof(*gen) + iph1->hash->l; + + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(buf, iph1, ISAKMP_NPTYPE_ID); + if (p == NULL) + goto end; + + /* create isakmp ID payload */ + p = set_isakmp_payload(p, iph1->id, ISAKMP_NPTYPE_HASH); + + /* create isakmp HASH payload */ + p = set_isakmp_payload(p, iph1->hash, ISAKMP_NPTYPE_NONE); + break; +#ifdef HAVE_SIGNING_C + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + if (oakley_getmycert(iph1) < 0) + goto end; + + if (oakley_getsign(iph1) < 0) + goto end; + + /* create CR if need */ + if (iph1->side == INITIATOR + && iph1->rmconf->send_cr + && oakley_needcr(iph1->approval->authmethod) + && iph1->rmconf->peerscertfile == NULL) { + need_cr = 1; + cr = oakley_getcr(iph1); + if (cr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer.\n"); + goto end; + } + } + + if (iph1->cert != NULL && iph1->rmconf->send_cert) + need_cert = 1; + + tlen += sizeof(*gen) + iph1->id->l + + sizeof(*gen) + iph1->sig->l; + if (need_cert) + tlen += sizeof(*gen) + iph1->cert->pl->l; + if (need_cr) + tlen += sizeof(*gen) + cr->l; + + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + p = set_isakmp_header(buf, iph1, ISAKMP_NPTYPE_ID); + if (p == NULL) + goto end; + + /* add ID payload */ + p = set_isakmp_payload(p, iph1->id, need_cert + ? ISAKMP_NPTYPE_CERT + : ISAKMP_NPTYPE_SIG); + + /* add CERT payload if there */ + if (need_cert) + p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG); + /* add SIG payload */ + p = set_isakmp_payload(p, iph1->sig, + need_cr ? ISAKMP_NPTYPE_CR : ISAKMP_NPTYPE_NONE); + + /* create isakmp CR payload */ + if (need_cr) + p = set_isakmp_payload(p, cr, ISAKMP_NPTYPE_NONE); + break; +#endif +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + if (!gssapi_id_sent(iph1)) + tlen += sizeof (*gen) + iph1->id->l; + if (iph1->hash != NULL) { + gsshash = gssapi_wraphash(iph1); + if (gsshash == NULL) + goto end; + tlen += sizeof (*gen) + gsshash->l; + } else { + gssapi_get_token_to_send(iph1, &gsstoken); + tlen += sizeof (*gen) + gsstoken->l; + } + + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* set isakmp header */ + if (!gssapi_id_sent(iph1)) + nptype = ISAKMP_NPTYPE_ID; + else + nptype = iph1->hash != NULL ? ISAKMP_NPTYPE_HASH : + ISAKMP_NPTYPE_GSS; + p = set_isakmp_header(buf, iph1, nptype); + if (p == NULL) + goto end; + + if (!gssapi_id_sent(iph1)) { + /* create isakmp ID payload */ + nptype = iph1->hash != NULL ? ISAKMP_NPTYPE_HASH : + ISAKMP_NPTYPE_GSS; + p = set_isakmp_payload(p, iph1->id, nptype); + if (p == NULL) + goto end; + gssapi_set_id_sent(iph1); + } + + if (iph1->hash != NULL) + /* create isakmp HASH payload */ + p = set_isakmp_payload(p, gsshash, + ISAKMP_NPTYPE_NONE); + else + p = set_isakmp_payload(p, gsstoken, ISAKMP_NPTYPE_NONE); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + plog(LLV_ERROR, LOCATION, NULL, + "not supported authentication type %d\n", + iph1->approval->authmethod); + goto end; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication type %d\n", + iph1->approval->authmethod); + goto end; + } + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph1->local, iph1->remote, 1); +#endif + + /* encoding */ + new = oakley_do_encrypt(iph1, buf, iph1->ivm->ive, iph1->ivm->iv); + if (new == NULL) + goto end; + + vfree(buf); + + buf = new; + + error = 0; + +end: + if (cr) + vfree(cr); + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + + return buf; +} diff --git a/racoon.tproj/isakmp_ident.h b/racoon.tproj/isakmp_ident.h new file mode 100644 index 0000000..a167f12 --- /dev/null +++ b/racoon.tproj/isakmp_ident.h @@ -0,0 +1,45 @@ +/* $KAME: isakmp_ident.h,v 1.3 2000/09/13 04:50:26 itojun 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. 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. + */ + +extern int ident_i1send __P((struct ph1handle *, vchar_t *)); +extern int ident_i2recv __P((struct ph1handle *, vchar_t *)); +extern int ident_i2send __P((struct ph1handle *, vchar_t *)); +extern int ident_i3recv __P((struct ph1handle *, vchar_t *)); +extern int ident_i3send __P((struct ph1handle *, vchar_t *)); +extern int ident_i4recv __P((struct ph1handle *, vchar_t *)); +extern int ident_i4send __P((struct ph1handle *, vchar_t *)); + +extern int ident_r1recv __P((struct ph1handle *, vchar_t *)); +extern int ident_r1send __P((struct ph1handle *, vchar_t *)); +extern int ident_r2recv __P((struct ph1handle *, vchar_t *)); +extern int ident_r2send __P((struct ph1handle *, vchar_t *)); +extern int ident_r3recv __P((struct ph1handle *, vchar_t *)); +extern int ident_r3send __P((struct ph1handle *, vchar_t *)); diff --git a/racoon.tproj/isakmp_inf.c b/racoon.tproj/isakmp_inf.c new file mode 100644 index 0000000..0bf9a2f --- /dev/null +++ b/racoon.tproj/isakmp_inf.c @@ -0,0 +1,1291 @@ +/* $KAME: isakmp_inf.c,v 1.78 2001/12/19 18:29:39 sakane 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. 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. + */ + +#include +#include +#include + +#include +#include +#include +#include +#ifdef IPV6_INRIA_VERSION +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "libpfkey.h" + +#include "var.h" +#include "vmbuf.h" +#include "schedule.h" +#include "str2val.h" +#include "misc.h" +#include "plog.h" +#include "debug.h" + +#include "localconf.h" +#include "remoteconf.h" +#include "sockmisc.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_inf.h" +#include "oakley.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "pfkey.h" +#include "policy.h" +#include "algorithm.h" +#include "proposal.h" +#include "admin.h" +#include "strnames.h" + +/* information exchange */ +static int isakmp_info_recv_n __P((struct ph1handle *, vchar_t *)); +static int isakmp_info_recv_d __P((struct ph1handle *, vchar_t *)); + +static void purge_isakmp_spi __P((int, isakmp_index *, size_t)); +static void purge_ipsec_spi __P((struct sockaddr *, int, u_int32_t *, size_t)); +static void info_recv_initialcontact __P((struct ph1handle *)); + +/* %%% + * Information Exchange + */ +/* + * receive Information + */ +int +isakmp_info_recv(iph1, msg0) + struct ph1handle *iph1; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + int error = -1; + struct isakmp *isakmp; + struct isakmp_gen *gen; + u_int8_t np; + int encrypted; + + plog(LLV_DEBUG, LOCATION, NULL, "receive Information.\n"); + + encrypted = ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E); + + /* Use new IV to decrypt Informational message. */ + if (encrypted) { + + struct isakmp_ivm *ivm; + + /* compute IV */ + ivm = oakley_newiv2(iph1, ((struct isakmp *)msg0->v)->msgid); + if (ivm == NULL) + return -1; + + msg = oakley_do_decrypt(iph1, msg0, ivm->iv, ivm->ive); + oakley_delivm(ivm); + if (msg == NULL) + return -1; + + } else + msg = vdup(msg0); + + isakmp = (struct isakmp *)msg->v; + gen = (struct isakmp_gen *)((caddr_t)isakmp + sizeof(struct isakmp)); + if (isakmp->np == ISAKMP_NPTYPE_HASH) + np = gen->np; + else + np = isakmp->np; + + /* make sure the packet were encrypted. */ + if (!encrypted) { + switch (iph1->etype) { + case ISAKMP_ETYPE_AGG: + case ISAKMP_ETYPE_BASE: + case ISAKMP_ETYPE_IDENT: + if ((iph1->side == INITIATOR && iph1->status < PHASE1ST_MSG3SENT) + || (iph1->side == RESPONDER && iph1->status < PHASE1ST_MSG2SENT)) { + break; + } + /*FALLTHRU*/ + default: + plog(LLV_ERROR, LOCATION, iph1->remote, + "%s message must be encrypted\n", + s_isakmp_nptype(np)); + goto end; + } + } + + switch (np) { + case ISAKMP_NPTYPE_N: + if (isakmp_info_recv_n(iph1, msg) < 0) + goto end; + break; + case ISAKMP_NPTYPE_D: + if (isakmp_info_recv_d(iph1, msg) < 0) + goto end; + break; + case ISAKMP_NPTYPE_NONCE: + /* XXX to be 6.4.2 ike-01.txt */ + /* XXX IV is to be synchronized. */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore Acknowledged Informational\n"); + break; + default: + /* don't send information, see isakmp_ident_r1() */ + error = 0; + plog(LLV_ERROR, LOCATION, iph1->remote, + "reject the packet, " + "received unexpecting payload type %d.\n", + gen->np); + goto end; + } + + end: + if (msg != NULL) + vfree(msg); + + return 0; +} + +/* + * send Delete payload (for ISAKMP SA) in Informational exchange. + */ +int +isakmp_info_send_d1(iph1) + struct ph1handle *iph1; +{ + struct isakmp_pl_d *d; + vchar_t *payload = NULL; + int tlen; + int error = 0; + + if (iph1->status != PHASE2ST_ESTABLISHED) + return 0; + + /* create delete payload */ + + /* send SPIs of inbound SAs. */ + /* XXX should send outbound SAs's ? */ + tlen = sizeof(*d) + sizeof(isakmp_index); + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer for payload.\n"); + return errno; + } + + d = (struct isakmp_pl_d *)payload->v; + d->h.np = ISAKMP_NPTYPE_NONE; + d->h.len = htons(tlen); + d->doi = htonl(IPSEC_DOI); + d->proto_id = IPSECDOI_PROTO_ISAKMP; + d->spi_size = sizeof(isakmp_index); + d->num_spi = htons(1); + memcpy(d + 1, &iph1->index, sizeof(isakmp_index)); + + error = isakmp_info_send_common(iph1, payload, + ISAKMP_NPTYPE_D, 0); + vfree(payload); + + return error; +} + +/* + * send Delete payload (for IPsec SA) in Informational exchange, based on + * pfkey msg. It sends always single SPI. + */ +int +isakmp_info_send_d2(iph2) + struct ph2handle *iph2; +{ + struct ph1handle *iph1; + struct saproto *pr; + struct isakmp_pl_d *d; + vchar_t *payload = NULL; + int tlen; + int error = 0; + u_int8_t *spi; + + if (iph2->status != PHASE2ST_ESTABLISHED) + return 0; + + /* + * don't send delete information if there is no phase 1 handler. + * It's nonsensical to negotiate phase 1 to send the information. + */ + iph1 = getph1byaddr(iph2->src, iph2->dst); + if (iph1 == NULL) + return 0; + + /* create delete payload */ + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + + /* send SPIs of inbound SAs. */ + /* + * XXX should I send outbound SAs's ? + * I send inbound SAs's SPI only at the moment because I can't + * decode any more if peer send encoded packet without aware of + * deletion of SA. Outbound SAs don't come under the situation. + */ + tlen = sizeof(*d) + pr->spisize; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer for payload.\n"); + return errno; + } + + d = (struct isakmp_pl_d *)payload->v; + d->h.np = ISAKMP_NPTYPE_NONE; + d->h.len = htons(tlen); + d->doi = htonl(IPSEC_DOI); + d->proto_id = pr->proto_id; + d->spi_size = pr->spisize; + d->num_spi = htons(1); + /* + * XXX SPI bits are left-filled, for use with IPComp. + * we should be switching to variable-length spi field... + */ + spi = (u_int8_t *)&pr->spi; + spi += sizeof(pr->spi); + spi -= pr->spisize; + memcpy(d + 1, spi, pr->spisize); + + error = isakmp_info_send_common(iph1, payload, + ISAKMP_NPTYPE_D, 0); + vfree(payload); + } + + return error; +} + +/* + * send Notification payload (for without ISAKMP SA) in Informational exchange + */ +int +isakmp_info_send_nx(isakmp, remote, local, type, data) + struct isakmp *isakmp; + struct sockaddr *remote, *local; + int type; + vchar_t *data; +{ + struct ph1handle *iph1 = NULL; + struct remoteconf *rmconf; + vchar_t *payload = NULL; + int tlen; + int error = -1; + struct isakmp_pl_n *n; + int spisiz = 0; /* see below */ + + /* search appropreate configuration */ + rmconf = getrmconf(remote); + if (rmconf == NULL) { + plog(LLV_ERROR, LOCATION, remote, + "no configuration found for peer address.\n"); + goto end; + } + + /* add new entry to isakmp status table. */ + iph1 = newph1(); + if (iph1 == NULL) + return -1; + + memcpy(&iph1->index.i_ck, &isakmp->i_ck, sizeof(cookie_t)); + isakmp_newcookie((char *)&iph1->index.r_ck, remote, local); + iph1->status = PHASE1ST_START; + iph1->rmconf = rmconf; + iph1->side = INITIATOR; + iph1->version = isakmp->v; + iph1->flags = 0; + iph1->msgid = 0; /* XXX */ + + /* copy remote address */ + if (copy_ph1addresses(iph1, rmconf, remote, local) < 0) + return -1; + + tlen = sizeof(*n) + spisiz; + if (data) + tlen += data->l; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + n = (struct isakmp_pl_n *)payload->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(IPSEC_DOI); + n->proto_id = IPSECDOI_KEY_IKE; + n->spi_size = spisiz; + n->type = htons(type); + if (spisiz) + memset(n + 1, 0, spisiz); /*XXX*/ + if (data) + memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); + + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, 0); + vfree(payload); + + end: + if (iph1 != NULL) + delph1(iph1); + + return error; +} + +/* + * send Notification payload (for ISAKMP SA) in Informational exchange + */ +int +isakmp_info_send_n1(iph1, type, data) + struct ph1handle *iph1; + int type; + vchar_t *data; +{ + vchar_t *payload = NULL; + int tlen; + int error = 0; + struct isakmp_pl_n *n; + int spisiz; + + /* + * note on SPI size: which description is correct? I have chosen + * this to be 0. + * + * RFC2408 3.1, 2nd paragraph says: ISAKMP SA is identified by + * Initiator/Responder cookie and SPI has no meaning, SPI size = 0. + * RFC2408 3.1, first paragraph on page 40: ISAKMP SA is identified + * by cookie and SPI has no meaning, 0 <= SPI size <= 16. + * RFC2407 4.6.3.3, INITIAL-CONTACT is required to set to 16. + */ + if (type == ISAKMP_NTYPE_INITIAL_CONTACT) + spisiz = sizeof(isakmp_index); + else + spisiz = 0; + + tlen = sizeof(*n) + spisiz; + if (data) + tlen += data->l; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + return errno; + } + + n = (struct isakmp_pl_n *)payload->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(iph1->rmconf->doitype); + n->proto_id = IPSECDOI_PROTO_ISAKMP; /* XXX to be configurable ? */ + n->spi_size = spisiz; + n->type = htons(type); + if (spisiz) + memcpy(n + 1, &iph1->index, sizeof(isakmp_index)); + if (data) + memcpy((caddr_t)(n + 1) + spisiz, data->v, data->l); + + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph1->flags); + vfree(payload); + + return error; +} + +/* + * send Notification payload (for IPsec SA) in Informational exchange + */ +int +isakmp_info_send_n2(iph2, type, data) + struct ph2handle *iph2; + int type; + vchar_t *data; +{ + struct ph1handle *iph1 = iph2->ph1; + vchar_t *payload = NULL; + int tlen; + int error = 0; + struct isakmp_pl_n *n; + struct saproto *pr; + + if (!iph2->approval) + return EINVAL; + + pr = iph2->approval->head; + + /* XXX must be get proper spi */ + tlen = sizeof(*n) + pr->spisize; + if (data) + tlen += data->l; + payload = vmalloc(tlen); + if (payload == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + return errno; + } + + n = (struct isakmp_pl_n *)payload->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ + n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ + n->spi_size = pr->spisize; + n->type = htons(type); + *(u_int32_t *)(n + 1) = pr->spi; + if (data) + memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); + + iph2->flags |= ISAKMP_FLAG_E; /* XXX Should we do FLAG_A ? */ + error = isakmp_info_send_common(iph1, payload, ISAKMP_NPTYPE_N, iph2->flags); + vfree(payload); + + return error; +} + +/* + * send Information + * When ph1->skeyid_a == NULL, send message without encoding. + */ +int +isakmp_info_send_common(iph1, payload, np, flags) + struct ph1handle *iph1; + vchar_t *payload; + u_int32_t np; + int flags; +{ + struct ph2handle *iph2 = NULL; + vchar_t *hash = NULL; + struct isakmp *isakmp; + struct isakmp_gen *gen; + char *p; + int tlen; + int error = -1; + + /* add new entry to isakmp status table */ + iph2 = newph2(); + if (iph2 == NULL) + goto end; + + iph2->dst = dupsaddr(iph1->remote); + iph2->src = dupsaddr(iph1->local); + switch (iph1->remote->sa_family) { + case AF_INET: + ((struct sockaddr_in *)iph2->dst)->sin_port = 0; + ((struct sockaddr_in *)iph2->src)->sin_port = 0; + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)iph2->dst)->sin6_port = 0; + ((struct sockaddr_in6 *)iph2->src)->sin6_port = 0; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph1->remote->sa_family); + delph2(iph2); + goto end; + } + iph2->ph1 = iph1; + iph2->side = INITIATOR; + iph2->status = PHASE2ST_START; + iph2->msgid = isakmp_newmsgid2(iph1); + + /* get IV and HASH(1) if skeyid_a was generated. */ + if (iph1->skeyid_a != NULL) { + iph2->ivm = oakley_newiv2(iph1, iph2->msgid); + if (iph2->ivm == NULL) { + delph2(iph2); + goto end; + } + + /* generate HASH(1) */ + hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, payload); + if (hash == NULL) { + delph2(iph2); + goto end; + } + + /* initialized total buffer length */ + tlen = hash->l; + tlen += sizeof(*gen); + } else { + /* IKE-SA is not established */ + hash = NULL; + + /* initialized total buffer length */ + tlen = 0; + } + if ((flags & ISAKMP_FLAG_A) == 0) + iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_E); + else + iph2->flags = (hash == NULL ? 0 : ISAKMP_FLAG_A); + + insph2(iph2); + bindph12(iph1, iph2); + + tlen += sizeof(*isakmp) + payload->l; + + /* create buffer for isakmp payload */ + iph2->sendbuf = vmalloc(tlen); + if (iph2->sendbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto err; + } + + /* create isakmp header */ + isakmp = (struct isakmp *)iph2->sendbuf->v; + memcpy(&isakmp->i_ck, &iph1->index.i_ck, sizeof(cookie_t)); + memcpy(&isakmp->r_ck, &iph1->index.r_ck, sizeof(cookie_t)); + isakmp->np = hash == NULL ? (np & 0xff) : ISAKMP_NPTYPE_HASH; + isakmp->v = iph1->version; + isakmp->etype = ISAKMP_ETYPE_INFO; + isakmp->flags = iph2->flags; + memcpy(&isakmp->msgid, &iph2->msgid, sizeof(isakmp->msgid)); + isakmp->len = htonl(tlen); + p = (char *)(isakmp + 1); + + /* create HASH payload */ + if (hash != NULL) { + gen = (struct isakmp_gen *)p; + gen->np = np & 0xff; + gen->len = htons(sizeof(*gen) + hash->l); + p += sizeof(*gen); + memcpy(p, hash->v, hash->l); + p += hash->l; + } + + /* add payload */ + memcpy(p, payload->v, payload->l); + p += payload->l; + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(iph2->sendbuf, iph1->local, iph1->remote, 1); +#endif + + /* encoding */ + if (ISSET(isakmp->flags, ISAKMP_FLAG_E)) { + vchar_t *tmp; + + tmp = oakley_do_encrypt(iph2->ph1, iph2->sendbuf, iph2->ivm->ive, + iph2->ivm->iv); + if (tmp == NULL) { + vfree(iph2->sendbuf); + iph2->sendbuf = NULL; + goto err; + } + vfree(iph2->sendbuf); + iph2->sendbuf = tmp; + } + + /* HDR*, HASH(1), N */ + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) { + vfree(iph2->sendbuf); + iph2->sendbuf = NULL; + goto err; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "sendto Information %s.\n", s_isakmp_nptype(np)); + + /* + * don't resend notify message because peer can use Acknowledged + * Informational if peer requires the reply of the notify message. + */ + + /* XXX If Acknowledged Informational required, don't delete ph2handle */ + error = 0; + vfree(iph2->sendbuf); + iph2->sendbuf = NULL; + goto err; /* XXX */ + +end: + if (hash) + vfree(hash); + return error; + +err: + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + goto end; +} + +/* + * add a notify payload to buffer by reallocating buffer. + * If buf == NULL, the function only create a notify payload. + * + * XXX Which is SPI to be included, inbound or outbound ? + */ +vchar_t * +isakmp_add_pl_n(buf0, np_p, type, pr, data) + vchar_t *buf0; + u_int8_t **np_p; + int type; + struct saproto *pr; + vchar_t *data; +{ + vchar_t *buf = NULL; + struct isakmp_pl_n *n; + int tlen; + int oldlen = 0; + + if (*np_p) + **np_p = ISAKMP_NPTYPE_N; + + tlen = sizeof(*n) + pr->spisize; + + if (data) + tlen += data->l; + if (buf0) { + oldlen = buf0->l; + buf = vrealloc(buf0, buf0->l + tlen); + } else + buf = vmalloc(tlen); + if (!buf) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get a payload buffer.\n"); + return NULL; + } + + n = (struct isakmp_pl_n *)(buf->v + oldlen); + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = htonl(IPSEC_DOI); /* IPSEC DOI (1) */ + n->proto_id = pr->proto_id; /* IPSEC AH/ESP/whatever*/ + n->spi_size = pr->spisize; + n->type = htons(type); + *(u_int32_t *)(n + 1) = pr->spi; /* XXX */ + if (data) + memcpy((caddr_t)(n + 1) + pr->spisize, data->v, data->l); + + /* save the pointer of next payload type */ + *np_p = &n->h.np; + + return buf; +} + +/* + * handling to receive Notification payload + */ +static int +isakmp_info_recv_n(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_pl_n *n = NULL; + u_int type; + vchar_t *pbuf; + struct isakmp_parse_t *pa, *pap; + char *spi; + + if (!(pbuf = isakmp_parse(msg))) + return -1; + pa = (struct isakmp_parse_t *)pbuf->v; + for (pap = pa; pap->type; pap++) { + switch (pap->type) { + case ISAKMP_NPTYPE_HASH: + /* do something here */ + break; + case ISAKMP_NPTYPE_NONCE: + /* send to ack */ + break; + case ISAKMP_NPTYPE_N: + n = (struct isakmp_pl_n *)pap->ptr; + break; + default: + vfree(pbuf); + return -1; + } + } + vfree(pbuf); + if (!n) + return -1; + + type = ntohs(n->type); + + switch (type) { + case ISAKMP_NTYPE_CONNECTED: + case ISAKMP_NTYPE_RESPONDER_LIFETIME: + case ISAKMP_NTYPE_REPLAY_STATUS: + /* do something */ + break; + case ISAKMP_NTYPE_INITIAL_CONTACT: + info_recv_initialcontact(iph1); + break; + default: + { + u_int32_t msgid = ((struct isakmp *)msg->v)->msgid; + struct ph2handle *iph2; + + /* XXX there is a potential of dos attack. */ + if (msgid == 0) { + /* delete ph1 */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete phase1 handle.\n"); + return -1; + } else { + iph2 = getph2bymsgid(iph1, msgid); + if (iph2 == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "unknown notify message, " + "no phase2 handle found.\n"); + } else { + /* delete ph2 */ + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } + } + } + break; + } + + /* get spi and allocate */ + if (ntohs(n->h.len) < sizeof(*n) + n->spi_size) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid spi_size in notification payload.\n"); + return -1; + } + spi = val2str((u_char *)(n + 1), n->spi_size); + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "notification message %d:%s, " + "doi=%d proto_id=%d spi=%s(size=%d).\n", + type, s_isakmp_notify_msg(type), + ntohl(n->doi), n->proto_id, spi, n->spi_size); + + racoon_free(spi); + + return(0); +} + +static void +purge_isakmp_spi(proto, spi, n) + int proto; + isakmp_index *spi; /*network byteorder*/ + size_t n; +{ + struct ph1handle *iph1; + size_t i; + + for (i = 0; i < n; i++) { + iph1 = getph1byindex(&spi[i]); + if (!iph1) + continue; + + plog(LLV_INFO, LOCATION, NULL, + "purged ISAKMP-SA proto_id=%s spi=%s.\n", + s_ipsecdoi_proto(proto), + isakmp_pindex(&spi[i], 0)); + + if (iph1->sce) + SCHED_KILL(iph1->sce); + iph1->status = PHASE1ST_EXPIRED; + iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1); + } +} + +static void +purge_ipsec_spi(dst0, proto, spi, n) + struct sockaddr *dst0; + int proto; + u_int32_t *spi; /*network byteorder*/ + size_t n; +{ + vchar_t *buf = NULL; + struct sadb_msg *msg, *next, *end; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + size_t i; + caddr_t mhp[SADB_EXT_MAX + 1]; + + buf = pfkey_dump_sadb(ipsecdoi2pfkey_proto(proto)); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey_dump_sadb returned nothing.\n"); + return; + } + + msg = (struct sadb_msg *)buf->v; + end = (struct sadb_msg *)(buf->v + buf->l); + + while (msg < end) { + if ((msg->sadb_msg_len << 3) < sizeof(*msg)) + break; + next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); + if (msg->sadb_msg_type != SADB_DUMP) { + msg = next; + continue; + } + + if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey_check (%s)\n", ipsec_strerror()); + msg = next; + continue; + } + + sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); + if (!sa + || !mhp[SADB_EXT_ADDRESS_SRC] + || !mhp[SADB_EXT_ADDRESS_DST]) { + msg = next; + continue; + } + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + if (sa->sadb_sa_state != SADB_SASTATE_MATURE + && sa->sadb_sa_state != SADB_SASTATE_DYING) { + msg = next; + continue; + } + + /* XXX n^2 algorithm, inefficient */ + + /* don't delete inbound SAs at the moment */ + /* XXX should we remove SAs with opposite direction as well? */ + if (cmpsaddrwop(dst0, dst)) { + msg = next; + continue; + } + + for (i = 0; i < n; i++) { + plog(LLV_DEBUG, LOCATION, NULL, + "check spi(packet)=%u spi(db)=%u.\n", + ntohl(spi[i]), ntohl(sa->sadb_sa_spi)); + if (spi[i] != sa->sadb_sa_spi) + continue; + + pfkey_send_delete(lcconf->sock_pfkey, + msg->sadb_msg_satype, + IPSEC_MODE_ANY, + src, dst, sa->sadb_sa_spi); + + /* + * delete a relative phase 2 handler. + * continue to process if no relative phase 2 handler + * exists. + */ + iph2 = getph2bysaidx(src, dst, proto, spi[i]); + if (iph2) { + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } + + plog(LLV_INFO, LOCATION, NULL, + "purged IPsec-SA proto_id=%s spi=%u.\n", + s_ipsecdoi_proto(proto), + ntohl(spi[i])); + } + + msg = next; + } + + if (buf) + vfree(buf); +} + +/* + * delete all phase2 sa relatived to the destination address. + * Don't delete Phase 1 handlers on INITIAL-CONTACT, and don't ignore + * an INITIAL-CONTACT if we have contacted the peer. This matches the + * Sun IKE behavior, and makes rekeying work much better when the peer + * restarts. + */ +static void +info_recv_initialcontact(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL; + struct sadb_msg *msg, *next, *end; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + caddr_t mhp[SADB_EXT_MAX + 1]; + int proto_id, i; + struct ph2handle *iph2; +#if 0 + char *loc, *rem; +#endif + + if (f_local) + return; + +#if 0 + loc = strdup(saddrwop2str(iph1->local)); + rem = strdup(saddrwop2str(iph1->remote)); + + /* + * Purge all IPSEC-SAs for the peer. We can do this + * the easy way (using a PF_KEY SADB_DELETE extension) + * or we can do it the hard way. + */ + for (i = 0; i < pfkey_nsatypes; i++) { + proto_id = pfkey2ipsecdoi_proto(pfkey_satypes[i].ps_satype); + + plog(LLV_INFO, LOCATION, NULL, + "purging %s SAs for %s -> %s\n", + pfkey_satypes[i].ps_name, loc, rem); + if (pfkey_send_delete_all(lcconf->sock_pfkey, + pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, + iph1->local, iph1->remote) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "delete_all %s -> %s failed for %s (%s)\n", + loc, rem, + pfkey_satypes[i].ps_name, ipsec_strerror()); + goto the_hard_way; + } + + deleteallph2(iph1->local, iph1->remote, proto_id); + + plog(LLV_INFO, LOCATION, NULL, + "purging %s SAs for %s -> %s\n", + pfkey_satypes[i].ps_name, rem, loc); + if (pfkey_send_delete_all(lcconf->sock_pfkey, + pfkey_satypes[i].ps_satype, IPSEC_MODE_ANY, + iph1->remote, iph1->local) == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "delete_all %s -> %s failed for %s (%s)\n", + rem, loc, + pfkey_satypes[i].ps_name, ipsec_strerror()); + goto the_hard_way; + } + + deleteallph2(iph1->remote, iph1->local, proto_id); + } + + racoon_free(loc); + racoon_free(rem); + return; + + the_hard_way: + racoon_free(loc); + racoon_free(rem); +#endif + + buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey_dump_sadb returned nothing.\n"); + return; + } + + msg = (struct sadb_msg *)buf->v; + end = (struct sadb_msg *)(buf->v + buf->l); + + while (msg < end) { + if ((msg->sadb_msg_len << 3) < sizeof(*msg)) + break; + next = (struct sadb_msg *)((caddr_t)msg + (msg->sadb_msg_len << 3)); + if (msg->sadb_msg_type != SADB_DUMP) { + msg = next; + continue; + } + + if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey_check (%s)\n", ipsec_strerror()); + msg = next; + continue; + } + + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + msg = next; + continue; + } + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + if (sa->sadb_sa_state != SADB_SASTATE_MATURE + && sa->sadb_sa_state != SADB_SASTATE_DYING) { + msg = next; + continue; + } + + /* + * RFC2407 4.6.3.3 INITIAL-CONTACT is the message that + * announces the sender of the message was rebooted. + * it is interpreted to delete all SAs which source address + * is the sender of the message. + * racoon only deletes SA which is matched both the + * source address and the destination accress. + */ + if ((cmpsaddrwop(iph1->local, src) && + cmpsaddrwop(iph1->remote, dst)) || + (cmpsaddrwop(iph1->remote, src) && + cmpsaddrwop(iph1->local, dst))) { + msg = next; + continue; + } + + /* + * Make sure this is an SATYPE that we manage. + * This is gross; too bad we couldn't do it the + * easy way. + */ + for (i = 0; i < pfkey_nsatypes; i++) { + if (pfkey_satypes[i].ps_satype == + msg->sadb_msg_satype) + break; + } + if (i == pfkey_nsatypes) { + msg = next; + continue; + } + + plog(LLV_INFO, LOCATION, NULL, + "purging spi=%u.\n", ntohl(sa->sadb_sa_spi)); + pfkey_send_delete(lcconf->sock_pfkey, + msg->sadb_msg_satype, + IPSEC_MODE_ANY, src, dst, sa->sadb_sa_spi); + + /* + * delete a relative phase 2 handler. + * continue to process if no relative phase 2 handler + * exists. + */ + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + if (iph2) { + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + } + + msg = next; + } + + vfree(buf); +} + +/* + * handling to receive Deletion payload + */ +static int +isakmp_info_recv_d(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ + struct isakmp_pl_d *d; + int tlen, num_spi; + vchar_t *pbuf; + struct isakmp_parse_t *pa, *pap; + int protected = 0; + union { + u_int32_t spi32; + u_int16_t spi16[2]; + } spi; + + /* validate the type of next payload */ + if (!(pbuf = isakmp_parse(msg))) + return -1; + pa = (struct isakmp_parse_t *)pbuf->v; + for (pap = pa; pap->type; pap++) { + switch (pap->type) { + case ISAKMP_NPTYPE_D: + break; + case ISAKMP_NPTYPE_HASH: + if (pap == pa) { + protected++; + break; + } + plog(LLV_ERROR, LOCATION, iph1->remote, + "received next payload type %d " + "in wrong place (must be the first payload).\n", + pap->type); + vfree(pbuf); + return -1; + default: + /* don't send information, see isakmp_ident_r1() */ + plog(LLV_ERROR, LOCATION, iph1->remote, + "reject the packet, " + "received unexpecting payload type %d.\n", + pap->type); + vfree(pbuf); + return 0; + } + } + + if (!protected) { + plog(LLV_ERROR, LOCATION, NULL, + "delete payload is not proteted, " + "ignored.\n"); + vfree(pbuf); + return -1; + } + + /* process a delete payload */ + for (pap = pa; pap->type; pap++) { + if (pap->type != ISAKMP_NPTYPE_D) + continue; + + d = (struct isakmp_pl_d *)pap->ptr; + + if (ntohl(d->doi) != IPSEC_DOI) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with invalid doi:%d.\n", + ntohl(d->doi)); + continue; + } + + num_spi = ntohs(d->num_spi); + tlen = ntohs(d->h.len) - sizeof(struct isakmp_pl_d); + + if (tlen != num_spi * d->spi_size) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "deletion payload with invalid length.\n"); + vfree(pbuf); + return -1; + } + + switch (d->proto_id) { + case IPSECDOI_PROTO_ISAKMP: + if (d->spi_size != sizeof(isakmp_index)) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with strange spi " + "size %d(proto_id:%d)\n", + d->spi_size, d->proto_id); + continue; + } + purge_isakmp_spi(d->proto_id, + (isakmp_index *)(d + 1), num_spi); + break; + + case IPSECDOI_PROTO_IPSEC_AH: + case IPSECDOI_PROTO_IPSEC_ESP: + if (d->spi_size != sizeof(u_int32_t)) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with strange spi " + "size %d(proto_id:%d)\n", + d->spi_size, d->proto_id); + continue; + } + purge_ipsec_spi(iph1->remote, d->proto_id, + (u_int32_t *)(d + 1), num_spi); + break; + + case IPSECDOI_PROTO_IPCOMP: + /* need to handle both 16bit/32bit SPI */ + memset(&spi, 0, sizeof(spi)); + if (d->spi_size == sizeof(spi.spi16[1])) { + memcpy(&spi.spi16[1], d + 1, + sizeof(spi.spi16[1])); + } else if (d->spi_size == sizeof(spi.spi32)) + memcpy(&spi.spi32, d + 1, sizeof(spi.spi32)); + else { + plog(LLV_ERROR, LOCATION, iph1->remote, + "delete payload with strange spi " + "size %d(proto_id:%d)\n", + d->spi_size, d->proto_id); + continue; + } + purge_ipsec_spi(iph1->remote, d->proto_id, + &spi.spi32, num_spi); + break; + + default: + plog(LLV_ERROR, LOCATION, iph1->remote, + "deletion message received, " + "invalid proto_id: %d\n", + d->proto_id); + continue; + } + + plog(LLV_DEBUG, LOCATION, NULL, "purged SAs.\n"); + } + + vfree(pbuf); + + return 0; +} + +void +isakmp_check_notify(gen, iph1) + struct isakmp_gen *gen; /* points to Notify payload */ + struct ph1handle *iph1; +{ + struct isakmp_pl_n *notify = (struct isakmp_pl_n *)gen; + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "Notify Message received\n"); + + switch (ntohs(notify->type)) { + case ISAKMP_NTYPE_CONNECTED: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore CONNECTED notification.\n"); + break; + case ISAKMP_NTYPE_RESPONDER_LIFETIME: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore RESPONDER-LIFETIME notification.\n"); + break; + case ISAKMP_NTYPE_REPLAY_STATUS: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore REPLAY-STATUS notification.\n"); + break; + case ISAKMP_NTYPE_INITIAL_CONTACT: + plog(LLV_WARNING, LOCATION, iph1->remote, + "ignore INITIAL-CONTACT notification, " + "because it is only accepted after phase1.\n"); + break; + default: + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "received unknown notification type %u.\n", + ntohs(notify->type)); + } + + return; +} + diff --git a/racoon.tproj/isakmp_inf.h b/racoon.tproj/isakmp_inf.h new file mode 100644 index 0000000..e6dbf51 --- /dev/null +++ b/racoon.tproj/isakmp_inf.h @@ -0,0 +1,46 @@ +/* $KAME: isakmp_inf.h,v 1.12 2000/09/13 04:50:26 itojun 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. 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. + */ + +struct saproto; +extern int isakmp_info_recv __P((struct ph1handle *, vchar_t *)); +extern int isakmp_info_send_d1 __P((struct ph1handle *)); +extern int isakmp_info_send_d2 __P((struct ph2handle *)); +extern int isakmp_info_send_nx __P((struct isakmp *, + struct sockaddr *, struct sockaddr *, int, vchar_t *)); +extern int isakmp_info_send_n1 __P((struct ph1handle *, int, vchar_t *)); +extern int isakmp_info_send_n2 __P((struct ph2handle *, int, vchar_t *)); +extern int isakmp_info_send_common __P((struct ph1handle *, + vchar_t *, u_int32_t, int)); + +extern vchar_t * isakmp_add_pl_n __P((vchar_t *, u_int8_t **, int, + struct saproto *, vchar_t *)); + +extern void isakmp_check_notify __P((struct isakmp_gen *, struct ph1handle *)); diff --git a/racoon.tproj/isakmp_newg.c b/racoon.tproj/isakmp_newg.c new file mode 100644 index 0000000..5d6b9db --- /dev/null +++ b/racoon.tproj/isakmp_newg.c @@ -0,0 +1,228 @@ +/* $KAME: isakmp_newg.c,v 1.8 2000/12/15 13:43:55 sakane 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. 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. + */ + +#include +#include + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "cfparse.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_newg.h" +#include "oakley.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "handler.h" +#include "pfkey.h" +#include "admin.h" +#include "str2val.h" +#include "vendorid.h" + +/* + * New group mode as responder + */ +int +isakmp_newgroup_r(iph1, msg) + struct ph1handle *iph1; + vchar_t *msg; +{ +#if 0 + struct isakmp *isakmp = (struct isakmp *)msg->v; + struct isakmp_pl_hash *hash = NULL; + struct isakmp_pl_sa *sa = NULL; + int error = -1; + vchar_t *buf; + struct oakley_sa *osa; + int len; + + /* validate the type of next payload */ + /* + * ISAKMP_ETYPE_NEWGRP, + * ISAKMP_NPTYPE_HASH, (ISAKMP_NPTYPE_VID), ISAKMP_NPTYPE_SA, + * ISAKMP_NPTYPE_NONE + */ + { + vchar_t *pbuf = NULL; + struct isakmp_parse_t *pa; + + if ((pbuf = isakmp_parse(msg)) == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + if (hash) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "received multiple payload type %d.\n", + pa->type); + vfree(pbuf); + goto end; + } + hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_SA: + if (sa) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "received multiple payload type %d.\n", + pa->type); + vfree(pbuf); + goto end; + } + sa = (struct isakmp_pl_sa *)pa->ptr; + break; + case ISAKMP_NPTYPE_VID: + (void)check_vendorid(pa->ptr); + break; + default: + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + vfree(pbuf); + goto end; + } + } + vfree(pbuf); + + if (!hash || !sa) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, NULL); + plog(LLV_ERROR, LOCATION, iph1->remote, + "no HASH, or no SA payload.\n"); + goto end; + } + } + + /* validate HASH */ + { + char *r_hash; + vchar_t *my_hash = NULL; + int result; + + plog(LLV_DEBUG, LOCATION, NULL, "validate HASH\n"); + + len = sizeof(isakmp->msgid) + ntohs(sa->h.len); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + memcpy(buf->v, &isakmp->msgid, sizeof(isakmp->msgid)); + memcpy(buf->v + sizeof(isakmp->msgid), sa, ntohs(sa->h.len)); + + plog(LLV_DEBUG, LOCATION, NULL, "hash source\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + my_hash = isakmp_prf(iph1->skeyid_a, buf, iph1); + vfree(buf); + if (my_hash == NULL) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "hash result\n"); + plogdump(LLV_DEBUG, my_hash->v, my_hash->l); + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "original hash\n")); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash))); + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "HASH mismatch.\n"); + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_INVALID_HASH_INFORMATION, NULL); + goto end; + } + } + + /* check SA payload and get new one for use */ + buf = ipsecdoi_get_proposal((struct ipsecdoi_sa *)sa, + OAKLEY_NEWGROUP_MODE); + if (buf == NULL) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL); + goto end; + } + + /* save sa parameters */ + osa = ipsecdoi_get_oakley(buf); + if (osa == NULL) { + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL); + goto end; + } + vfree(buf); + + switch (osa->dhgrp) { + case OAKLEY_ATTR_GRP_DESC_MODP768: + case OAKLEY_ATTR_GRP_DESC_MODP1024: + case OAKLEY_ATTR_GRP_DESC_MODP1536: + /*XXX*/ + default: + isakmp_info_send_n1(iph1, ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, NULL); + plog(LLV_ERROR, LOCATION, NULL, + "dh group %d isn't supported.\n", osa->dhgrp); + goto end; + } + + plog(LLV_INFO, LOCATION, iph1->remote, + "got new dh group %s.\n", isakmp_pindex(&iph1->index, 0)); + + error = 0; + +end: + if (error) { + if (iph1 != NULL) + (void)isakmp_free_ph1(iph1); + } + return error; +#endif + return 0; +} + diff --git a/racoon.tproj/isakmp_newg.h b/racoon.tproj/isakmp_newg.h new file mode 100644 index 0000000..680f6ca --- /dev/null +++ b/racoon.tproj/isakmp_newg.h @@ -0,0 +1,32 @@ +/* $KAME: isakmp_newg.h,v 1.3 2000/09/13 04:50:26 itojun 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. 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. + */ + +extern int isakmp_newgroup_r __P((struct ph1handle *, vchar_t *)); diff --git a/racoon.tproj/isakmp_quick.c b/racoon.tproj/isakmp_quick.c new file mode 100644 index 0000000..c0d8004 --- /dev/null +++ b/racoon.tproj/isakmp_quick.c @@ -0,0 +1,2110 @@ +/* $KAME: isakmp_quick.c,v 1.91 2001/12/31 20:13:41 thorpej 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. 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. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifdef IPV6_INRIA_VERSION +#include +#else +#include +#endif + +#include "var.h" +#include "vmbuf.h" +#include "schedule.h" +#include "misc.h" +#include "plog.h" +#include "debug.h" + +#include "localconf.h" +#include "remoteconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_inf.h" +#include "isakmp_quick.h" +#include "oakley.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "crypto_openssl.h" +#include "pfkey.h" +#include "policy.h" +#include "algorithm.h" +#include "sockmisc.h" +#include "proposal.h" +#include "sainfo.h" +#include "admin.h" +#include "strnames.h" + +/* quick mode */ +static vchar_t *quick_ir1mx __P((struct ph2handle *, vchar_t *, vchar_t *)); +static int get_sainfo_r __P((struct ph2handle *)); +static int get_proposal_r __P((struct ph2handle *)); +static u_int32_t setscopeid __P((struct sockaddr *, struct sockaddr *)); + +/* %%% + * Quick Mode + */ +/* + * begin Quick Mode as initiator. send pfkey getspi message to kernel. + */ +int +quick_i1prep(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; /* must be null pointer */ +{ + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS2) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + iph2->msgid = isakmp_newmsgid2(iph2->ph1); + iph2->ivm = oakley_newiv2(iph2->ph1, iph2->msgid); + if (iph2->ivm == NULL) + return NULL; + + iph2->status = PHASE2ST_GETSPISENT; + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* send getspi message */ + if (pk_sendgetspi(iph2) < 0) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); + + iph2->sce = sched_new(lcconf->wait_ph2complete, + pfkey_timeover_stub, iph2); + + error = 0; + +end: + return error; +} + +/* + * send to responder + * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] + */ +int +quick_i1send(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; /* must be null pointer */ +{ + vchar_t *body = NULL; + vchar_t *hash = NULL; + struct isakmp_gen *gen; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + int pfsgroup, idci, idcr; + int np; + struct ipsecdoi_id_b *id, *id_p; + + /* validity check */ + if (msg != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "msg has to be NULL in this function.\n"); + goto end; + } + if (iph2->status != PHASE2ST_GETSPIDONE) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* create SA payload for my proposal */ + if (ipsecdoi_setph2proposal(iph2) < 0) + goto end; + + /* generate NONCE value */ + iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size); + if (iph2->nonce == NULL) + goto end; + + /* + * DH value calculation is kicked out into cfparse.y. + * because pfs group can not be negotiated, it's only to be checked + * acceptable. + */ + /* generate KE value if need */ + pfsgroup = iph2->proposal->pfs_group; + if (pfsgroup) { + /* DH group settting if PFS is required. */ + if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set DH value.\n"); + goto end; + } + if (oakley_dh_generate(iph2->pfsgrp, + &iph2->dhpub, &iph2->dhpriv) < 0) { + goto end; + } + } + + /* generate ID value */ + if (ipsecdoi_setid2(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "IDci:"); + plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l); + plog(LLV_DEBUG, LOCATION, NULL, "IDcr:"); + plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l); + + /* + * we do not attach IDci nor IDcr, under the following condition: + * - all proposals are transport mode + * - no MIP6 + * - id payload suggests to encrypt all the traffic (no specific + * protocol type) + */ + id = (struct ipsecdoi_id_b *)iph2->id->v; + id_p = (struct ipsecdoi_id_b *)iph2->id_p->v; + if (id->proto_id == 0 + && id_p->proto_id == 0 + && iph2->ph1->rmconf->support_mip6 == 0 + && ipsecdoi_transportmode(iph2)) { + idci = idcr = 0; + } else + idci = idcr = 1; + + /* create SA;NONCE payload, and KE if need, and IDii, IDir. */ + tlen = + sizeof(*gen) + iph2->sa->l + + sizeof(*gen) + iph2->nonce->l; + if (pfsgroup) + tlen += (sizeof(*gen) + iph2->dhpub->l); + if (idci) + tlen += sizeof(*gen) + iph2->id->l; + if (idcr) + tlen += sizeof(*gen) + iph2->id_p->l; + + body = vmalloc(tlen); + if (body == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + p = body->v; + + /* add SA payload */ + p = set_isakmp_payload(p, iph2->sa, ISAKMP_NPTYPE_NONCE); + + /* add NONCE payload */ + if (pfsgroup) + np = ISAKMP_NPTYPE_KE; + else if (idci || idcr) + np = ISAKMP_NPTYPE_ID; + else + np = ISAKMP_NPTYPE_NONE; + p = set_isakmp_payload(p, iph2->nonce, np); + + /* add KE payload if need. */ + np = (idci || idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; + if (pfsgroup) + p = set_isakmp_payload(p, iph2->dhpub, np); + + /* IDci */ + np = (idcr) ? ISAKMP_NPTYPE_ID : ISAKMP_NPTYPE_NONE; + if (idci) + p = set_isakmp_payload(p, iph2->id, np); + + /* IDcr */ + if (idcr) + p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_NONE); + + /* generate HASH(1) */ + hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, body); + if (hash == NULL) + goto end; + + /* send isakmp payload */ + iph2->sendbuf = quick_ir1mx(iph2, body, hash); + if (iph2->sendbuf == NULL) + goto end; + + /* send the packet, add to the schedule to resend */ + iph2->retry_counter = iph2->ph1->rmconf->retry_counter; + if (isakmp_ph2resend(iph2) == -1) + goto end; + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_MSG1SENT; + + error = 0; + +end: + if (body != NULL) + vfree(body); + if (hash != NULL) + vfree(hash); + + return error; +} + +/* + * receive from responder + * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] + */ +int +quick_i2recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *hbuf = NULL; /* for hash computing. */ + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp *isakmp = (struct isakmp *)msg0->v; + struct isakmp_pl_hash *hash = NULL; + int f_id; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypt packet */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* create buffer for validating HASH(2) */ + /* + * ordering rule: + * 1. the first one must be HASH + * 2. the second one must be SA (added in isakmp-oakley-05!) + * 3. two IDs must be considered as IDci, then IDcr + */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_HASH) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_HASH); + goto end; + } + hash = (struct isakmp_pl_hash *)pa->ptr; + pa++; + + /* + * this restriction was introduced in isakmp-oakley-05. + * we do not check this for backward compatibility. + * TODO: command line/config file option to enable/disable this code + */ + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_WARNING, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_HASH); + } + + /* allocate buffer for computing HASH(2) */ + tlen = iph2->nonce->l + + ntohl(isakmp->len) - sizeof(*isakmp); + hbuf = vmalloc(tlen); + if (hbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + p = hbuf->v + iph2->nonce->l; /* retain the space for Ni_b */ + + /* + * parse the payloads. + * copy non-HASH payloads into hbuf, so that we can validate HASH. + */ + iph2->sa_ret = NULL; + f_id = 0; /* flag to use checking ID */ + tlen = 0; /* count payload length except of HASH payload. */ + for (; pa->type; pa++) { + + /* copy to buffer for HASH */ + /* Don't modify the payload */ + memcpy(p, pa->ptr, pa->len); + + switch (pa->type) { + case ISAKMP_NPTYPE_SA: + if (iph2->sa_ret != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Ignored, multiple SA " + "isn't supported.\n"); + break; + } + if (isakmp_p2ph(&iph2->sa_ret, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_ID: + { + vchar_t *vp; + + /* check ID value */ + if (f_id == 0) { + /* for IDci */ + f_id = 1; + vp = iph2->id; + } else { + /* for IDcr */ + vp = iph2->id_p; + } + + if (memcmp(vp->v, (caddr_t)pa->ptr + sizeof(struct isakmp_gen), vp->l)) { + + plog(LLV_ERROR, LOCATION, NULL, + "mismatched ID was returned.\n"); + error = ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED; + goto end; + } + } + break; + + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + break; + + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + + p += pa->len; + + /* compute true length of payload. */ + tlen += pa->len; + } + + /* payload existency check */ + if (hash == NULL || iph2->sa_ret == NULL || iph2->nonce_p == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* Fixed buffer for calculating HASH */ + memcpy(hbuf->v, iph2->nonce->v, iph2->nonce->l); + plog(LLV_DEBUG, LOCATION, NULL, + "HASH allocated:hbuf->l=%d actual:tlen=%d\n", + hbuf->l, tlen + iph2->nonce->l); + /* adjust buffer length for HASH */ + hbuf->l = iph2->nonce->l + tlen; + + /* validate HASH(2) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + int result; + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(2) received:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, + "HASH(2) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + /* validity check SA payload sent from responder */ + if (ipsecdoi_checkph2proposal(iph2) < 0) { + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_STATUS6; + + error = 0; + +end: + if (hbuf) + vfree(hbuf); + if (pbuf) + vfree(pbuf); + if (msg) + vfree(msg); + + if (error) { + VPTRINIT(iph2->sa_ret); + VPTRINIT(iph2->nonce_p); + VPTRINIT(iph2->dhpub_p); + VPTRINIT(iph2->id); + VPTRINIT(iph2->id_p); + } + + return error; +} + +/* + * send to responder + * HDR*, HASH(3) + */ +int +quick_i2send(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *buf = NULL; + vchar_t *hash = NULL; + char *p = NULL; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS6) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* generate HASH(3) */ + { + vchar_t *tmp = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) generate\n"); + + tmp = vmalloc(iph2->nonce->l + iph2->nonce_p->l); + if (tmp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + memcpy(tmp->v, iph2->nonce->v, iph2->nonce->l); + memcpy(tmp->v + iph2->nonce->l, iph2->nonce_p->v, iph2->nonce_p->l); + + hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp); + vfree(tmp); + + if (hash == NULL) + goto end; + } + + /* create buffer for isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(struct isakmp_gen) + hash->l; + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* create isakmp header */ + p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + + /* add HASH(3) payload */ + p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_NONE); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); +#endif + + /* encoding */ + iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); + if (iph2->sendbuf == NULL) + goto end; + + /* if there is commit bit, need resending */ + if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { + /* send the packet, add to the schedule to resend */ + iph2->retry_counter = iph2->ph1->rmconf->retry_counter; + if (isakmp_ph2resend(iph2) == -1) + goto end; + } else { + /* send the packet */ + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) + goto end; + } + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, + iph2->sendbuf, msg0) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* compute both of KEYMATs */ + if (oakley_compute_keymat(iph2, INITIATOR) < 0) + goto end; + + iph2->status = PHASE2ST_ADDSA; + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* if there is commit bit don't set up SA now. */ + if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { + iph2->status = PHASE2ST_COMMIT; + error = 0; + goto end; + } + + /* Do UPDATE for initiator */ + plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); + if (pk_sendupdate(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); + + /* Do ADD for responder */ + if (pk_sendadd(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + if (msg != NULL) + vfree(msg); + if (hash != NULL) + vfree(hash); + + return error; +} + +/* + * receive from responder + * HDR#*, HASH(4), notify + */ +int +quick_i3recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp_pl_hash *hash = NULL; + vchar_t *notify = NULL; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_COMMIT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypt packet */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + notify = vmalloc(pa->len); + if (notify == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get notify buffer.\n"); + goto end; + } + memcpy(notify->v, pa->ptr, notify->l); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + if (hash == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* validate HASH(4) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + vchar_t *tmp = NULL; + int result; + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) validate:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify); + vfree(tmp); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, + "HASH(4) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + iph2->status = PHASE2ST_ADDSA; + iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */ + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* Do UPDATE for initiator */ + plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); + if (pk_sendupdate(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); + + /* Do ADD for responder */ + if (pk_sendadd(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); + + error = 0; + +end: + if (msg != NULL) + vfree(msg); + if (pbuf != NULL) + vfree(pbuf); + if (notify != NULL) + vfree(notify); + + return error; +} + +/* + * receive from initiator + * HDR*, HASH(1), SA, Ni [, KE ] [, IDi2, IDr2 ] + */ +int +quick_r1recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *hbuf = NULL; /* for hash computing. */ + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp *isakmp = (struct isakmp *)msg0->v; + struct isakmp_pl_hash *hash = NULL; + char *p; + int tlen; + int f_id_order; /* for ID payload detection */ + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_START) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypting */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; + goto end; + } + /* decrypt packet */ + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* create buffer for using to validate HASH(1) */ + /* + * ordering rule: + * 1. the first one must be HASH + * 2. the second one must be SA (added in isakmp-oakley-05!) + * 3. two IDs must be considered as IDci, then IDcr + */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + pa = (struct isakmp_parse_t *)pbuf->v; + + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_HASH) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_HASH); + error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX; + goto end; + } + hash = (struct isakmp_pl_hash *)pa->ptr; + pa++; + + /* + * this restriction was introduced in isakmp-oakley-05. + * we do not check this for backward compatibility. + * TODO: command line/config file option to enable/disable this code + */ + /* HASH payload is fixed postion */ + if (pa->type != ISAKMP_NPTYPE_SA) { + plog(LLV_WARNING, LOCATION, iph2->ph1->remote, + "received invalid next payload type %d, " + "expecting %d.\n", + pa->type, ISAKMP_NPTYPE_HASH); + error = ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX; + } + + /* allocate buffer for computing HASH(1) */ + tlen = ntohl(isakmp->len) - sizeof(*isakmp); + hbuf = vmalloc(tlen); + if (hbuf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + p = hbuf->v; + + /* + * parse the payloads. + * copy non-HASH payloads into hbuf, so that we can validate HASH. + */ + iph2->sa = NULL; /* we don't support multi SAs. */ + iph2->nonce_p = NULL; + iph2->dhpub_p = NULL; + iph2->id_p = NULL; + iph2->id = NULL; + tlen = 0; /* count payload length except of HASH payload. */ + + /* + * IDi2 MUST be immediatelly followed by IDr2. We allowed the + * illegal case, but logged. First ID payload is to be IDi2. + * And next ID payload is to be IDr2. + */ + f_id_order = 0; + + for (; pa->type; pa++) { + + /* copy to buffer for HASH */ + /* Don't modify the payload */ + memcpy(p, pa->ptr, pa->len); + + if (pa->type != ISAKMP_NPTYPE_ID) + f_id_order = 0; + + switch (pa->type) { + case ISAKMP_NPTYPE_SA: + if (iph2->sa != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Multi SAs isn't supported.\n"); + goto end; + } + if (isakmp_p2ph(&iph2->sa, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_NONCE: + if (isakmp_p2ph(&iph2->nonce_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_KE: + if (isakmp_p2ph(&iph2->dhpub_p, pa->ptr) < 0) + goto end; + break; + + case ISAKMP_NPTYPE_ID: + if (iph2->id_p == NULL) { + /* for IDci */ + f_id_order++; + + if (isakmp_p2ph(&iph2->id_p, pa->ptr) < 0) + goto end; + + } else if (iph2->id == NULL) { + /* for IDcr */ + if (f_id_order == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "IDr2 payload is not " + "immediatelly followed " + "by IDi2. We allowed.\n"); + /* XXX we allowed in this case. */ + } + + if (isakmp_p2ph(&iph2->id, pa->ptr) < 0) + goto end; + } else { + plog(LLV_ERROR, LOCATION, NULL, + "received too many ID payloads.\n"); + plogdump(LLV_ERROR, iph2->id->v, iph2->id->l); + error = ISAKMP_NTYPE_INVALID_ID_INFORMATION; + goto end; + } + break; + + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + break; + + default: + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; + goto end; + } + + p += pa->len; + + /* compute true length of payload. */ + tlen += pa->len; + } + + /* payload existency check */ + if (hash == NULL || iph2->sa == NULL || iph2->nonce_p == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "few isakmp message received.\n"); + error = ISAKMP_NTYPE_PAYLOAD_MALFORMED; + goto end; + } + + if (iph2->id_p) { + plog(LLV_DEBUG, LOCATION, NULL, "received IDci2:"); + plogdump(LLV_DEBUG, iph2->id_p->v, iph2->id_p->l); + } + if (iph2->id) { + plog(LLV_DEBUG, LOCATION, NULL, "received IDcr2:"); + plogdump(LLV_DEBUG, iph2->id->v, iph2->id->l); + } + + /* adjust buffer length for HASH */ + hbuf->l = tlen; + + /* validate HASH(1) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + int result; + + r_hash = (caddr_t)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(1) validate:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + my_hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, hbuf); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_DEBUG, LOCATION, iph2->ph1->remote, + "HASH(1) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + /* get sainfo */ + error = get_sainfo_r(iph2); + if (error) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get sainfo.\n"); + goto end; + } + + /* check the existence of ID payload and create responder's proposal */ + error = get_proposal_r(iph2); + switch (error) { + case -2: + /* generate a policy template from peer's proposal */ + if (set_proposal_from_proposal(iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to generate a proposal template " + "from client's proposal.\n"); + return ISAKMP_INTERNAL_ERROR; + } + /*FALLTHROUGH*/ + case 0: + /* select single proposal or reject it. */ + if (ipsecdoi_selectph2proposal(iph2) < 0) { + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "failed to get proposal for responder.\n"); + goto end; + } + + /* check KE and attribute of PFS */ + if (iph2->dhpub_p != NULL && iph2->approval->pfs_group == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no PFS is specified, but peer sends KE.\n"); + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + if (iph2->dhpub_p == NULL && iph2->approval->pfs_group != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "PFS is specified, but peer doesn't sends KE.\n"); + error = ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN; + goto end; + } + + /* + * save the packet from the initiator in order to resend the + * responder's first packet against this packet. + */ + iph2->msg1 = vdup(msg0); + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_STATUS2; + + error = 0; + +end: + if (hbuf) + vfree(hbuf); + if (msg) + vfree(msg); + if (pbuf) + vfree(pbuf); + + if (error) { + VPTRINIT(iph2->sa); + VPTRINIT(iph2->nonce_p); + VPTRINIT(iph2->dhpub_p); + VPTRINIT(iph2->id); + VPTRINIT(iph2->id_p); + } + + return error; +} + +/* + * call pfkey_getspi. + */ +int +quick_r1prep(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; +{ + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS2) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + iph2->status = PHASE2ST_GETSPISENT; + + /* send getspi message */ + if (pk_sendgetspi(iph2) < 0) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "pfkey getspi sent.\n"); + + iph2->sce = sched_new(lcconf->wait_ph2complete, + pfkey_timeover_stub, iph2); + + error = 0; + +end: + return error; +} + +/* + * send to initiator + * HDR*, HASH(2), SA, Nr [, KE ] [, IDi2, IDr2 ] + */ +int +quick_r2send(iph2, msg) + struct ph2handle *iph2; + vchar_t *msg; +{ + vchar_t *body = NULL; + vchar_t *hash = NULL; + struct isakmp_gen *gen; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + int pfsgroup; + u_int8_t *np_p = NULL; + + /* validity check */ + if (msg != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "msg has to be NULL in this function.\n"); + goto end; + } + if (iph2->status != PHASE2ST_GETSPIDONE) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* update responders SPI */ + if (ipsecdoi_updatespi(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "failed to update spi.\n"); + goto end; + } + + /* generate NONCE value */ + iph2->nonce = eay_set_random(iph2->ph1->rmconf->nonce_size); + if (iph2->nonce == NULL) + goto end; + + /* generate KE value if need */ + pfsgroup = iph2->approval->pfs_group; + if (iph2->dhpub_p != NULL && pfsgroup != 0) { + /* DH group settting if PFS is required. */ + if (oakley_setdhgroup(pfsgroup, &iph2->pfsgrp) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set DH value.\n"); + goto end; + } + /* generate DH public value */ + if (oakley_dh_generate(iph2->pfsgrp, + &iph2->dhpub, &iph2->dhpriv) < 0) { + goto end; + } + } + + /* create SA;NONCE payload, and KE and ID if need */ + tlen = sizeof(*gen) + iph2->sa_ret->l + + sizeof(*gen) + iph2->nonce->l; + if (iph2->dhpub_p != NULL && pfsgroup != 0) + tlen += (sizeof(*gen) + iph2->dhpub->l); + if (iph2->id_p != NULL) + tlen += (sizeof(*gen) + iph2->id_p->l + + sizeof(*gen) + iph2->id->l); + + body = vmalloc(tlen); + if (body == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + p = body->v; + + /* make SA payload */ + p = set_isakmp_payload(body->v, iph2->sa_ret, ISAKMP_NPTYPE_NONCE); + + /* add NONCE payload */ + np_p = &((struct isakmp_gen *)p)->np; /* XXX */ + p = set_isakmp_payload(p, iph2->nonce, + (iph2->dhpub_p != NULL && pfsgroup != 0) + ? ISAKMP_NPTYPE_KE + : (iph2->id_p != NULL + ? ISAKMP_NPTYPE_ID + : ISAKMP_NPTYPE_NONE)); + + /* add KE payload if need. */ + if (iph2->dhpub_p != NULL && pfsgroup != 0) { + np_p = &((struct isakmp_gen *)p)->np; /* XXX */ + p = set_isakmp_payload(p, iph2->dhpub, + (iph2->id_p == NULL) + ? ISAKMP_NPTYPE_NONE + : ISAKMP_NPTYPE_ID); + } + + /* add ID payloads received. */ + if (iph2->id_p != NULL) { + /* IDci */ + p = set_isakmp_payload(p, iph2->id_p, ISAKMP_NPTYPE_ID); + /* IDcr */ + np_p = &((struct isakmp_gen *)p)->np; /* XXX */ + p = set_isakmp_payload(p, iph2->id, ISAKMP_NPTYPE_NONE); + } + + /* add a RESPONDER-LIFETIME notify payload if needed */ + { + vchar_t *data = NULL; + struct saprop *pp = iph2->approval; + struct saproto *pr; + + if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_SEC) { + u_int32_t v = htonl((u_int32_t)pp->lifetime); + data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_SEC); + if (!data) + goto end; + data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + if (!data) + goto end; + } + if (pp->claim & IPSECDOI_ATTR_SA_LD_TYPE_KB) { + u_int32_t v = htonl((u_int32_t)pp->lifebyte); + data = isakmp_add_attr_l(data, IPSECDOI_ATTR_SA_LD_TYPE, + IPSECDOI_ATTR_SA_LD_TYPE_KB); + if (!data) + goto end; + data = isakmp_add_attr_v(data, IPSECDOI_ATTR_SA_LD, + (caddr_t)&v, sizeof(v)); + if (!data) + goto end; + } + + /* + * XXX Is there only single RESPONDER-LIFETIME payload in a IKE message + * in the case of SA bundle ? + */ + if (data) { + for (pr = pp->head; pr; pr = pr->next) { + body = isakmp_add_pl_n(body, &np_p, + ISAKMP_NTYPE_RESPONDER_LIFETIME, pr, data); + if (!body) { + vfree(data); + return error; /* XXX */ + } + } + vfree(data); + } + } + + /* generate HASH(2) */ + { + vchar_t *tmp; + + tmp = vmalloc(iph2->nonce_p->l + body->l); + if (tmp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l); + memcpy(tmp->v + iph2->nonce_p->l, body->v, body->l); + + hash = oakley_compute_hash1(iph2->ph1, iph2->msgid, tmp); + vfree(tmp); + + if (hash == NULL) + goto end; + } + + /* send isakmp payload */ + iph2->sendbuf = quick_ir1mx(iph2, body, hash); + if (iph2->sendbuf == NULL) + goto end; + + /* send the packet, add to the schedule to resend */ + iph2->retry_counter = iph2->ph1->rmconf->retry_counter; + if (isakmp_ph2resend(iph2) == -1) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, iph2->msg1) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + /* change status of isakmp status entry */ + iph2->status = PHASE2ST_MSG1SENT; + + error = 0; + +end: + if (body != NULL) + vfree(body); + if (hash != NULL) + vfree(hash); + + return error; +} + +/* + * receive from initiator + * HDR*, HASH(3) + */ +int +quick_r3recv(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + vchar_t *pbuf = NULL; /* for payload parsing */ + struct isakmp_parse_t *pa; + struct isakmp_pl_hash *hash = NULL; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_MSG1SENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* decrypt packet */ + if (!ISSET(((struct isakmp *)msg0->v)->flags, ISAKMP_FLAG_E)) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "Packet wasn't encrypted.\n"); + goto end; + } + msg = oakley_do_decrypt(iph2->ph1, msg0, iph2->ivm->iv, iph2->ivm->ive); + if (msg == NULL) + goto end; + + /* validate the type of next payload */ + pbuf = isakmp_parse(msg); + if (pbuf == NULL) + goto end; + + for (pa = (struct isakmp_parse_t *)pbuf->v; + pa->type != ISAKMP_NPTYPE_NONE; + pa++) { + + switch (pa->type) { + case ISAKMP_NPTYPE_HASH: + hash = (struct isakmp_pl_hash *)pa->ptr; + break; + case ISAKMP_NPTYPE_N: + isakmp_check_notify(pa->ptr, iph2->ph1); + break; + default: + /* don't send information, see ident_r1recv() */ + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "ignore the packet, " + "received unexpecting payload type %d.\n", + pa->type); + goto end; + } + } + + /* payload existency check */ + if (hash == NULL) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "few isakmp message received.\n"); + goto end; + } + + /* validate HASH(3) */ + /* HASH(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */ + { + char *r_hash; + vchar_t *my_hash = NULL; + vchar_t *tmp = NULL; + int result; + + r_hash = (char *)hash + sizeof(*hash); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH(3) validate:"); + plogdump(LLV_DEBUG, r_hash, ntohs(hash->h.len) - sizeof(*hash)); + + tmp = vmalloc(iph2->nonce_p->l + iph2->nonce->l); + if (tmp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer.\n"); + goto end; + } + memcpy(tmp->v, iph2->nonce_p->v, iph2->nonce_p->l); + memcpy(tmp->v + iph2->nonce_p->l, iph2->nonce->v, iph2->nonce->l); + + my_hash = oakley_compute_hash3(iph2->ph1, iph2->msgid, tmp); + vfree(tmp); + if (my_hash == NULL) + goto end; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_ERROR, LOCATION, iph2->ph1->remote, + "HASH(3) mismatch.\n"); + error = ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + goto end; + } + } + + /* if there is commit bit, don't set up SA now. */ + if (ISSET(iph2->flags, ISAKMP_FLAG_C)) { + iph2->status = PHASE2ST_COMMIT; + } else + iph2->status = PHASE2ST_STATUS6; + + error = 0; + +end: + if (pbuf != NULL) + vfree(pbuf); + if (msg != NULL) + vfree(msg); + + return error; +} + +/* + * send to initiator + * HDR#*, HASH(4), notify + */ +int +quick_r3send(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *buf = NULL; + vchar_t *myhash = NULL; + struct isakmp_pl_n *n; + vchar_t *notify = NULL; + char *p; + int tlen; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_COMMIT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* generate HASH(4) */ + /* XXX What can I do in the case of multiple different SA */ + plog(LLV_DEBUG, LOCATION, NULL, "HASH(4) generate\n"); + + /* XXX What should I do if there are multiple SAs ? */ + tlen = sizeof(struct isakmp_pl_n) + iph2->approval->head->spisize; + notify = vmalloc(tlen); + if (notify == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get notify buffer.\n"); + goto end; + } + n = (struct isakmp_pl_n *)notify->v; + n->h.np = ISAKMP_NPTYPE_NONE; + n->h.len = htons(tlen); + n->doi = IPSEC_DOI; + n->proto_id = iph2->approval->head->proto_id; + n->spi_size = sizeof(iph2->approval->head->spisize); + n->type = htons(ISAKMP_NTYPE_CONNECTED); + memcpy(n + 1, &iph2->approval->head->spi, iph2->approval->head->spisize); + + myhash = oakley_compute_hash1(iph2->ph1, iph2->msgid, notify); + if (myhash == NULL) + goto end; + + /* create buffer for isakmp payload */ + tlen = sizeof(struct isakmp) + + sizeof(struct isakmp_gen) + myhash->l + + notify->l; + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* create isakmp header */ + p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + + /* add HASH(4) payload */ + p = set_isakmp_payload(p, myhash, ISAKMP_NPTYPE_N); + + /* add notify payload */ + memcpy(p, notify->v, notify->l); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); +#endif + + /* encoding */ + iph2->sendbuf = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); + if (iph2->sendbuf == NULL) + goto end; + + /* send the packet */ + if (isakmp_send(iph2->ph1, iph2->sendbuf) < 0) + goto end; + + /* the sending message is added to the received-list. */ + if (add_recvdpkt(iph2->ph1->remote, iph2->ph1->local, iph2->sendbuf, msg0) == -1) { + plog(LLV_ERROR , LOCATION, NULL, + "failed to add a response packet to the tree.\n"); + goto end; + } + + iph2->status = PHASE2ST_COMMIT; + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + if (myhash != NULL) + vfree(myhash); + if (notify != NULL) + vfree(notify); + + return error; +} + +/* + * set SA to kernel. + */ +int +quick_r3prep(iph2, msg0) + struct ph2handle *iph2; + vchar_t *msg0; +{ + vchar_t *msg = NULL; + int error = ISAKMP_INTERNAL_ERROR; + + /* validity check */ + if (iph2->status != PHASE2ST_STATUS6) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatched %d.\n", iph2->status); + goto end; + } + + /* compute both of KEYMATs */ + if (oakley_compute_keymat(iph2, RESPONDER) < 0) + goto end; + + iph2->status = PHASE2ST_ADDSA; + iph2->flags ^= ISAKMP_FLAG_C; /* reset bit */ + + /* don't anything if local test mode. */ + if (f_local) { + error = 0; + goto end; + } + + /* Do UPDATE as responder */ + plog(LLV_DEBUG, LOCATION, NULL, "call pk_sendupdate\n"); + if (pk_sendupdate(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey update failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey update sent.\n"); + + /* Do ADD for responder */ + if (pk_sendadd(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, "pfkey add failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "pfkey add sent.\n"); + + /* + * set policies into SPD if the policy is generated + * from peer's policy. + */ + if (iph2->spidx_gen) { + + struct policyindex *spidx; + struct sockaddr_storage addr; + u_int8_t pref; + struct sockaddr *src = iph2->src; + struct sockaddr *dst = iph2->dst; + + /* make inbound policy */ + iph2->src = dst; + iph2->dst = src; + if (pk_sendspdupdate2(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spdupdate2(inbound) failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spdupdate2(inbound) sent.\n"); + + /* make outbound policy */ + iph2->src = src; + iph2->dst = dst; + spidx = (struct policyindex *)iph2->spidx_gen; + spidx->dir = IPSEC_DIR_OUTBOUND; + addr = spidx->src; + spidx->src = spidx->dst; + spidx->dst = addr; + pref = spidx->prefs; + spidx->prefs = spidx->prefd; + spidx->prefd = pref; + + if (pk_sendspdupdate2(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey spdupdate2(outbound) failed.\n"); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey spdupdate2(outbound) sent.\n"); + + /* spidx_gen is unnecessary any more */ + delsp_bothdir((struct policyindex *)iph2->spidx_gen); + racoon_free(iph2->spidx_gen); + iph2->spidx_gen = NULL; + } + + error = 0; + +end: + if (msg != NULL) + vfree(msg); + + return error; +} + +/* + * create HASH, body (SA, NONCE) payload with isakmp header. + */ +static vchar_t * +quick_ir1mx(iph2, body, hash) + struct ph2handle *iph2; + vchar_t *body, *hash; +{ + struct isakmp *isakmp; + vchar_t *buf = NULL, *new = NULL; + char *p; + int tlen; + struct isakmp_gen *gen; + int error = ISAKMP_INTERNAL_ERROR; + + /* create buffer for isakmp payload */ + tlen = sizeof(*isakmp) + + sizeof(*gen) + hash->l + + body->l; + buf = vmalloc(tlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send.\n"); + goto end; + } + + /* re-set encryption flag, for serurity. */ + iph2->flags |= ISAKMP_FLAG_E; + + /* set isakmp header */ + p = set_isakmp_header2(buf, iph2, ISAKMP_NPTYPE_HASH); + if (p == NULL) + goto end; + + /* add HASH payload */ + /* XXX is next type always SA ? */ + p = set_isakmp_payload(p, hash, ISAKMP_NPTYPE_SA); + + /* add body payload */ + memcpy(p, body->v, body->l); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph2->ph1->local, iph2->ph1->remote, 1); +#endif + + /* encoding */ + new = oakley_do_encrypt(iph2->ph1, buf, iph2->ivm->ive, iph2->ivm->iv); + if (new == NULL) + goto end; + + vfree(buf); + + buf = new; + + error = 0; + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + + return buf; +} + +/* + * get remote's sainfo. + * NOTE: this function is for responder. + */ +static int +get_sainfo_r(iph2) + struct ph2handle *iph2; +{ + vchar_t *idsrc = NULL, *iddst = NULL; + int prefixlen; + int error = ISAKMP_INTERNAL_ERROR; + + if (iph2->id_p == NULL) { + switch (iph2->src->sa_family) { + case AF_INET: + prefixlen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + prefixlen = sizeof(struct in6_addr) << 3; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph2->src->sa_family); + goto end; + } + idsrc = ipsecdoi_sockaddr2id(iph2->src, prefixlen, + IPSEC_ULPROTO_ANY); + } else { + idsrc = vdup(iph2->id); + } + if (idsrc == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set ID for source.\n"); + goto end; + } + + if (iph2->id == NULL) { + switch (iph2->dst->sa_family) { + case AF_INET: + prefixlen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + prefixlen = sizeof(struct in6_addr) << 3; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", iph2->dst->sa_family); + goto end; + } + iddst = ipsecdoi_sockaddr2id(iph2->dst, prefixlen, + IPSEC_ULPROTO_ANY); + } else { + iddst = vdup(iph2->id_p); + } + if (iddst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set ID for destination.\n"); + goto end; + } + + iph2->sainfo = getsainfo(idsrc, iddst); + if (iph2->sainfo == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get sainfo.\n"); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "get sa info: %s\n", sainfo2str(iph2->sainfo)); + + error = 0; +end: + if (idsrc) + vfree(idsrc); + if (iddst) + vfree(iddst); + + return error; +} + +/* + * Copy both IP addresses in ID payloads into [src,dst]_id if both ID types + * are IP address and same address family. + * Then get remote's policy from SPD copied from kernel. + * If the type of ID payload is address or subnet type, then the index is + * made from the payload. If there is no ID payload, or the type of ID + * payload is NOT address type, then the index is made from the address + * pair of phase 1. + * NOTE: This function is only for responder. + */ +static int +get_proposal_r(iph2) + struct ph2handle *iph2; +{ + struct policyindex spidx; + struct secpolicy *sp_in, *sp_out; + int idi2type = 0; /* switch whether copy IDs into id[src,dst]. */ + int error = ISAKMP_INTERNAL_ERROR; + + /* check the existence of ID payload */ + if ((iph2->id_p != NULL && iph2->id == NULL) + || (iph2->id_p == NULL && iph2->id != NULL)) { + plog(LLV_ERROR, LOCATION, NULL, + "Both IDs wasn't found in payload.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + /* make sure if id[src,dst] is null. */ + if (iph2->src_id || iph2->dst_id) { + plog(LLV_ERROR, LOCATION, NULL, + "Why do ID[src,dst] exist already.\n"); + return ISAKMP_INTERNAL_ERROR; + } + + memset(&spidx, 0, sizeof(spidx)); + +#define _XIDT(d) ((struct ipsecdoi_id_b *)(d)->v)->type + + /* make a spidx; a key to search SPD */ + spidx.dir = IPSEC_DIR_INBOUND; + spidx.ul_proto = 0; + + /* + * make destination address in spidx from either ID payload + * or phase 1 address into a address in spidx. + */ + if (iph2->id != NULL + && (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR_SUBNET + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { + /* get a destination address of a policy */ + error = ipsecdoi_id2sockaddr(iph2->id, + (struct sockaddr *)&spidx.dst, + &spidx.prefd, &spidx.ul_proto); + if (error) + return error; + +#ifdef INET6 + /* + * get scopeid from the SA address. + * note that the phase 1 source address is used as + * a destination address to search for a inbound policy entry + * because rcoon is responder. + */ + if (_XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) { + error = setscopeid((struct sockaddr *)&spidx.dst, + iph2->src); + if (error) + return error; + } +#endif + + if (_XIDT(iph2->id) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id) == IPSECDOI_ID_IPV6_ADDR) + idi2type = _XIDT(iph2->id); + + } else { + + plog(LLV_DEBUG, LOCATION, NULL, + "get a destination address of SP index " + "from phase1 address " + "due to no ID payloads found " + "OR because ID type is not address.\n"); + + /* + * copy the SOURCE address of IKE into the DESTINATION address + * of the key to search the SPD because the direction of policy + * is inbound. + */ + memcpy(&spidx.dst, iph2->src, iph2->src->sa_len); + switch (spidx.dst.ss_family) { + case AF_INET: + spidx.prefd = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + spidx.prefd = sizeof(struct in6_addr) << 3; + break; +#endif + default: + spidx.prefd = 0; + break; + } + } + + /* make source address in spidx */ + if (iph2->id_p != NULL + && (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV4_ADDR_SUBNET + || _XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR_SUBNET)) { + /* get a source address of inbound SA */ + error = ipsecdoi_id2sockaddr(iph2->id_p, + (struct sockaddr *)&spidx.src, + &spidx.prefs, &spidx.ul_proto); + if (error) + return error; + +#ifdef INET6 + /* + * get scopeid from the SA address. + * for more detail, see above of this function. + */ + if (_XIDT(iph2->id_p) == IPSECDOI_ID_IPV6_ADDR) { + error = setscopeid((struct sockaddr *)&spidx.src, + iph2->dst); + if (error) + return error; + } +#endif + + /* make id[src,dst] if both ID types are IP address and same */ + if (_XIDT(iph2->id_p) == idi2type + && spidx.dst.ss_family == spidx.src.ss_family) { + iph2->src_id = dupsaddr((struct sockaddr *)&spidx.dst); + iph2->dst_id = dupsaddr((struct sockaddr *)&spidx.src); + } + + } else { + plog(LLV_DEBUG, LOCATION, NULL, + "get a source address of SP index " + "from phase1 address " + "due to no ID payloads found " + "OR because ID type is not address.\n"); + + /* see above comment. */ + memcpy(&spidx.src, iph2->dst, iph2->dst->sa_len); + switch (spidx.src.ss_family) { + case AF_INET: + spidx.prefs = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + spidx.prefs = sizeof(struct in6_addr) << 3; + break; +#endif + default: + spidx.prefs = 0; + break; + } + } + +#undef _XIDT + + plog(LLV_DEBUG, LOCATION, NULL, + "get a src address from ID payload " + "%s prefixlen=%u ul_proto=%u\n", + saddr2str((struct sockaddr *)&spidx.src), + spidx.prefs, spidx.ul_proto); + plog(LLV_DEBUG, LOCATION, NULL, + "get dst address from ID payload " + "%s prefixlen=%u ul_proto=%u\n", + saddr2str((struct sockaddr *)&spidx.dst), + spidx.prefd, spidx.ul_proto); + + /* + * convert the ul_proto if it is 0 + * because 0 in ID payload means a wild card. + */ + if (spidx.ul_proto == 0) + spidx.ul_proto = IPSEC_ULPROTO_ANY; + + /* get inbound policy */ + sp_in = getsp_r(&spidx); + if (sp_in == NULL) { + if (iph2->ph1->rmconf->gen_policy) { + plog(LLV_INFO, LOCATION, NULL, + "no policy found, " + "try to generate the policy : %s\n", + spidx2str(&spidx)); + iph2->spidx_gen = racoon_malloc(sizeof(spidx)); + if (!iph2->spidx_gen) { + plog(LLV_ERROR, LOCATION, NULL, + "buffer allocation failed.\n"); + return ISAKMP_INTERNAL_ERROR; + } + memcpy(iph2->spidx_gen, &spidx, sizeof(spidx)); + return -2; /* special value */ + } + plog(LLV_ERROR, LOCATION, NULL, + "no policy found: %s\n", spidx2str(&spidx)); + return ISAKMP_INTERNAL_ERROR; + } + + /* get outbound policy */ + { + struct sockaddr_storage addr; + u_int8_t pref; + + spidx.dir = IPSEC_DIR_OUTBOUND; + addr = spidx.src; + spidx.src = spidx.dst; + spidx.dst = addr; + pref = spidx.prefs; + spidx.prefs = spidx.prefd; + spidx.prefd = pref; + + sp_out = getsp_r(&spidx); + if (!sp_out) { + plog(LLV_WARNING, LOCATION, NULL, + "no outbound policy found: %s\n", + spidx2str(&spidx)); + } + } + + plog(LLV_DEBUG, LOCATION, NULL, + "suitable SP found:%s\n", spidx2str(&spidx)); + + /* + * In the responder side, the inbound policy should be using IPsec. + * outbound policy is not checked currently. + */ + if (sp_in->policy != IPSEC_POLICY_IPSEC) { + plog(LLV_ERROR, LOCATION, NULL, + "policy found, but no IPsec required: %s\n", + spidx2str(&spidx)); + return ISAKMP_INTERNAL_ERROR; + } + + /* set new proposal derived from a policy into the iph2->proposal. */ + if (set_proposal_from_policy(iph2, sp_in, sp_out) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to create saprop.\n"); + return ISAKMP_INTERNAL_ERROR; + } + + return 0; +} + +#ifdef INET6 +static u_int32_t +setscopeid(sp_addr0, sa_addr0) + struct sockaddr *sp_addr0, *sa_addr0; +{ + struct sockaddr_in6 *sp_addr, *sa_addr; + + sp_addr = (struct sockaddr_in6 *)sp_addr0; + sa_addr = (struct sockaddr_in6 *)sa_addr0; + + if (!IN6_IS_ADDR_LINKLOCAL(&sp_addr->sin6_addr) + && !IN6_IS_ADDR_SITELOCAL(&sp_addr->sin6_addr) + && !IN6_IS_ADDR_MULTICAST(&sp_addr->sin6_addr)) + return 0; + + /* this check should not be here ? */ + if (sa_addr->sin6_family != AF_INET6) { + plog(LLV_ERROR, LOCATION, NULL, + "can't get scope ID: family mismatch\n"); + return -1; + } + + if (!IN6_IS_ADDR_LINKLOCAL(&sa_addr->sin6_addr)) { + plog(LLV_ERROR, LOCATION, NULL, + "scope ID is not supported except of lladdr.\n"); + return -1; + } + + sp_addr->sin6_scope_id = sa_addr->sin6_scope_id; + + return 0; +} +#endif diff --git a/racoon.tproj/isakmp_quick.h b/racoon.tproj/isakmp_quick.h new file mode 100644 index 0000000..edb4d56 --- /dev/null +++ b/racoon.tproj/isakmp_quick.h @@ -0,0 +1,43 @@ +/* $KAME: isakmp_quick.h,v 1.4 2000/09/13 04:50:26 itojun 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. 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. + */ + +extern int quick_i1prep __P((struct ph2handle *, vchar_t *)); +extern int quick_i1send __P((struct ph2handle *, vchar_t *)); +extern int quick_i2recv __P((struct ph2handle *, vchar_t *)); +extern int quick_i2send __P((struct ph2handle *, vchar_t *)); +extern int quick_i3recv __P((struct ph2handle *, vchar_t *)); + +extern int quick_r1recv __P((struct ph2handle *, vchar_t *)); +extern int quick_r1prep __P((struct ph2handle *, vchar_t *)); +extern int quick_r2send __P((struct ph2handle *, vchar_t *)); +extern int quick_r3recv __P((struct ph2handle *, vchar_t *)); +extern int quick_r3send __P((struct ph2handle *, vchar_t *)); +extern int quick_r3prep __P((struct ph2handle *, vchar_t *)); diff --git a/racoon.tproj/isakmp_var.h b/racoon.tproj/isakmp_var.h new file mode 100644 index 0000000..01d410c --- /dev/null +++ b/racoon.tproj/isakmp_var.h @@ -0,0 +1,107 @@ +/* $KAME: isakmp_var.h,v 1.19 2000/10/04 17:41:01 itojun 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. 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. + */ + +#define PORT_ISAKMP 500 + +#define DEFAULT_NONCE_SIZE 16 + +typedef u_char cookie_t[8]; +typedef u_char msgid_t[4]; + +typedef struct { /* i_cookie + r_cookie */ + cookie_t i_ck; + cookie_t r_ck; +} isakmp_index; + +struct isakmp_gen; +struct sched; + +struct sockaddr; +struct ph1handle; +struct ph2handle; +struct remoteconf; +struct isakmp_gen; +struct ipsecdoi_pl_id; /* XXX */ +struct isakmp_pl_ke; /* XXX */ +struct isakmp_pl_nonce; /* XXX */ + +extern int isakmp_handler __P((int)); +extern int isakmp_ph1begin_i __P((struct remoteconf *, struct sockaddr *)); + +extern vchar_t *isakmp_parsewoh __P((int, struct isakmp_gen *, int)); +extern vchar_t *isakmp_parse __P((vchar_t *)); + +extern int isakmp_init __P((void)); +extern const char *isakmp_pindex __P((const isakmp_index *, const u_int32_t)); +extern int isakmp_open __P((void)); +extern void isakmp_close __P((void)); +extern int isakmp_send __P((struct ph1handle *, vchar_t *)); + +extern void isakmp_ph1resend_stub __P((void *)); +extern int isakmp_ph1resend __P((struct ph1handle *)); +extern void isakmp_ph2resend_stub __P((void *)); +extern int isakmp_ph2resend __P((struct ph2handle *)); +extern void isakmp_ph1expire_stub __P((void *)); +extern void isakmp_ph1expire __P((struct ph1handle *)); +extern void isakmp_ph1delete_stub __P((void *)); +extern void isakmp_ph1delete __P((struct ph1handle *)); +extern void isakmp_ph2expire_stub __P((void *)); +extern void isakmp_ph2expire __P((struct ph2handle *)); +extern void isakmp_ph2delete_stub __P((void *)); +extern void isakmp_ph2delete __P((struct ph2handle *)); + +extern int isakmp_post_acquire __P((struct ph2handle *)); +extern int isakmp_post_getspi __P((struct ph2handle *)); +extern void isakmp_chkph1there_stub __P((void *)); +extern void isakmp_chkph1there __P((struct ph2handle *)); + +extern caddr_t isakmp_set_attr_v __P((caddr_t, int, caddr_t, int)); +extern caddr_t isakmp_set_attr_l __P((caddr_t, int, u_int32_t)); +extern vchar_t *isakmp_add_attr_v __P((vchar_t *, int, caddr_t, int)); +extern vchar_t *isakmp_add_attr_l __P((vchar_t *, int, u_int32_t)); + +extern int isakmp_newcookie __P((caddr_t, struct sockaddr *, struct sockaddr *)); + +extern int isakmp_p2ph __P((vchar_t **, struct isakmp_gen *)); + +extern u_int32_t isakmp_newmsgid2 __P((struct ph1handle *)); +extern caddr_t set_isakmp_header __P((vchar_t *, struct ph1handle *, int)); +extern caddr_t set_isakmp_header2 __P((vchar_t *, struct ph2handle *, int)); +extern caddr_t set_isakmp_payload __P((caddr_t, vchar_t *, int)); + +#ifdef HAVE_PRINT_ISAKMP_C +extern void isakmp_printpacket __P((vchar_t *, struct sockaddr *, + struct sockaddr *, int)); +#endif + +extern int copy_ph1addresses __P(( struct ph1handle *, + struct remoteconf *, struct sockaddr *, struct sockaddr *)); +extern void log_ph1established __P((const struct ph1handle *)); diff --git a/racoon.tproj/key_debug.c b/racoon.tproj/key_debug.c new file mode 100644 index 0000000..7ace6be --- /dev/null +++ b/racoon.tproj/key_debug.c @@ -0,0 +1,751 @@ +/* $FreeBSD: src/sys/netkey/key_debug.c,v 1.10.2.2 2001/07/03 11:01:59 ume Exp $ */ +/* $KAME: key_debug.c,v 1.25 2000/07/24 13:23:12 itojun 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. 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. + */ + +#ifdef _KERNEL +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" +#endif + +#include +#include +#ifdef _KERNEL +#include +#include +#include +#endif +#include + +#include + +#include +#include + +#include +#include + +#ifndef _KERNEL +#include +#include +#include +#endif /* !_KERNEL */ + +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) + +static void kdebug_sadb_prop __P((struct sadb_ext *)); +static void kdebug_sadb_identity __P((struct sadb_ext *)); +static void kdebug_sadb_supported __P((struct sadb_ext *)); +static void kdebug_sadb_lifetime __P((struct sadb_ext *)); +static void kdebug_sadb_sa __P((struct sadb_ext *)); +static void kdebug_sadb_address __P((struct sadb_ext *)); +static void kdebug_sadb_key __P((struct sadb_ext *)); +static void kdebug_sadb_x_sa2 __P((struct sadb_ext *)); + +#ifdef _KERNEL +static void kdebug_secreplay __P((struct secreplay *)); +#endif + +#ifndef _KERNEL +#define panic(param) { printf(param); exit(-1); } +#endif + +/* NOTE: host byte order */ + +/* %%%: about struct sadb_msg */ +void +kdebug_sadb(base) + struct sadb_msg *base; +{ + struct sadb_ext *ext; + int tlen, extlen; + + /* sanity check */ + if (base == NULL) + panic("kdebug_sadb: NULL pointer was passed.\n"); + + printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", + base->sadb_msg_version, base->sadb_msg_type, + base->sadb_msg_errno, base->sadb_msg_satype); + printf(" len=%u reserved=%u seq=%u pid=%u\n", + base->sadb_msg_len, base->sadb_msg_reserved, + base->sadb_msg_seq, base->sadb_msg_pid); + + tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); + + while (tlen > 0) { + printf("sadb_ext{ len=%u type=%u }\n", + ext->sadb_ext_len, ext->sadb_ext_type); + + if (ext->sadb_ext_len == 0) { + printf("kdebug_sadb: invalid ext_len=0 was passed.\n"); + return; + } + if (ext->sadb_ext_len > tlen) { + printf("kdebug_sadb: ext_len exceeds end of buffer.\n"); + return; + } + + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + kdebug_sadb_sa(ext); + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + kdebug_sadb_lifetime(ext); + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + kdebug_sadb_address(ext); + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + kdebug_sadb_key(ext); + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + kdebug_sadb_identity(ext); + break; + case SADB_EXT_SENSITIVITY: + break; + case SADB_EXT_PROPOSAL: + kdebug_sadb_prop(ext); + break; + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + kdebug_sadb_supported(ext); + break; + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_KMPRIVATE: + break; + case SADB_X_EXT_POLICY: + kdebug_sadb_x_policy(ext); + break; + case SADB_X_EXT_SA2: + kdebug_sadb_x_sa2(ext); + break; + default: + printf("kdebug_sadb: invalid ext_type %u was passed.\n", + ext->sadb_ext_type); + return; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (struct sadb_ext *)((caddr_t)ext + extlen); + } + + return; +} + +static void +kdebug_sadb_prop(ext) + struct sadb_ext *ext; +{ + struct sadb_prop *prop = (struct sadb_prop *)ext; + struct sadb_comb *comb; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_prop: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop)) + / sizeof(*comb); + comb = (struct sadb_comb *)(prop + 1); + printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay); + + while (len--) { + printf("sadb_comb{ auth=%u encrypt=%u " + "flags=0x%04x reserved=0x%08x\n", + comb->sadb_comb_auth, comb->sadb_comb_encrypt, + comb->sadb_comb_flags, comb->sadb_comb_reserved); + + printf(" auth_minbits=%u auth_maxbits=%u " + "encrypt_minbits=%u encrypt_maxbits=%u\n", + comb->sadb_comb_auth_minbits, + comb->sadb_comb_auth_maxbits, + comb->sadb_comb_encrypt_minbits, + comb->sadb_comb_encrypt_maxbits); + + printf(" soft_alloc=%u hard_alloc=%u " + "soft_bytes=%lu hard_bytes=%lu\n", + comb->sadb_comb_soft_allocations, + comb->sadb_comb_hard_allocations, + (unsigned long)comb->sadb_comb_soft_bytes, + (unsigned long)comb->sadb_comb_hard_bytes); + + printf(" soft_alloc=%lu hard_alloc=%lu " + "soft_bytes=%lu hard_bytes=%lu }\n", + (unsigned long)comb->sadb_comb_soft_addtime, + (unsigned long)comb->sadb_comb_hard_addtime, + (unsigned long)comb->sadb_comb_soft_usetime, + (unsigned long)comb->sadb_comb_hard_usetime); + comb++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_identity(ext) + struct sadb_ext *ext; +{ + struct sadb_ident *id = (struct sadb_ident *)ext; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_identity: NULL pointer was passed.\n"); + + len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); + printf("sadb_ident_%s{", + id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); + switch (id->sadb_ident_type) { + default: + printf(" type=%d id=%lu", + id->sadb_ident_type, (u_long)id->sadb_ident_id); + if (len) { +#ifdef _KERNEL + ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ +#else + char *p, *ep; + printf("\n str=\""); + p = (char *)(id + 1); + ep = p + len; + for (/*nothing*/; *p && p < ep; p++) { + if (isprint(*p)) + printf("%c", *p & 0xff); + else + printf("\\%03o", *p & 0xff); + } +#endif + printf("\""); + } + break; + } + + printf(" }\n"); + + return; +} + +static void +kdebug_sadb_supported(ext) + struct sadb_ext *ext; +{ + struct sadb_supported *sup = (struct sadb_supported *)ext; + struct sadb_alg *alg; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_supported: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup)) + / sizeof(*alg); + alg = (struct sadb_alg *)(sup + 1); + printf("sadb_sup{\n"); + while (len--) { + printf(" { id=%d ivlen=%d min=%d max=%d }\n", + alg->sadb_alg_id, alg->sadb_alg_ivlen, + alg->sadb_alg_minbits, alg->sadb_alg_maxbits); + alg++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_lifetime(ext) + struct sadb_ext *ext; +{ + struct sadb_lifetime *lft = (struct sadb_lifetime *)ext; + + /* sanity check */ + if (ext == NULL) + printf("kdebug_sadb_lifetime: NULL pointer was passed.\n"); + + printf("sadb_lifetime{ alloc=%u, bytes=%u\n", + lft->sadb_lifetime_allocations, + (u_int32_t)lft->sadb_lifetime_bytes); + printf(" addtime=%u, usetime=%u }\n", + (u_int32_t)lft->sadb_lifetime_addtime, + (u_int32_t)lft->sadb_lifetime_usetime); + + return; +} + +static void +kdebug_sadb_sa(ext) + struct sadb_ext *ext; +{ + struct sadb_sa *sa = (struct sadb_sa *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_sa: NULL pointer was passed.\n"); + + printf("sadb_sa{ spi=%u replay=%u state=%u\n", + (u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, + sa->sadb_sa_state); + printf(" auth=%u encrypt=%u flags=0x%08x }\n", + sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags); + + return; +} + +static void +kdebug_sadb_address(ext) + struct sadb_ext *ext; +{ + struct sadb_address *addr = (struct sadb_address *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_address: NULL pointer was passed.\n"); + + printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n", + addr->sadb_address_proto, addr->sadb_address_prefixlen, + ((u_char *)&addr->sadb_address_reserved)[0], + ((u_char *)&addr->sadb_address_reserved)[1]); + + kdebug_sockaddr((struct sockaddr *)((caddr_t)ext + sizeof(*addr))); + + return; +} + +static void +kdebug_sadb_key(ext) + struct sadb_ext *ext; +{ + struct sadb_key *key = (struct sadb_key *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_key: NULL pointer was passed.\n"); + + printf("sadb_key{ bits=%u reserved=%u\n", + key->sadb_key_bits, key->sadb_key_reserved); + printf(" key="); + + /* sanity check 2 */ + if ((key->sadb_key_bits >> 3) > + (PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) { + printf("kdebug_sadb_key: key length mismatch, bit:%d len:%ld.\n", + key->sadb_key_bits >> 3, + (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key)); + } + + ipsec_hexdump((caddr_t)key + sizeof(struct sadb_key), + key->sadb_key_bits >> 3); + printf(" }\n"); + return; +} + +static void +kdebug_sadb_x_sa2(ext) + struct sadb_ext *ext; +{ + struct sadb_x_sa2 *sa2 = (struct sadb_x_sa2 *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_sa2: NULL pointer was passed.\n"); + + printf("sadb_x_sa2{ mode=%u reqid=%u\n", + sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid); + printf(" reserved1=%u reserved2=%u reserved3=%u }\n", + sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved1, + sa2->sadb_x_sa2_reserved1); + + return; +} + +void +kdebug_sadb_x_policy(ext) + struct sadb_ext *ext; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext; + struct sockaddr *addr; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); + + printf("sadb_x_policy{ type=%u dir=%u id=%x }\n", + xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, + xpl->sadb_x_policy_id); + + if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + int tlen; + struct sadb_x_ipsecrequest *xisr; + + tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + while (tlen > 0) { + printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n", + xisr->sadb_x_ipsecrequest_len, + xisr->sadb_x_ipsecrequest_proto, + xisr->sadb_x_ipsecrequest_mode, + xisr->sadb_x_ipsecrequest_level, + xisr->sadb_x_ipsecrequest_reqid); + + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + addr = (struct sockaddr *)(xisr + 1); + kdebug_sockaddr(addr); + addr = (struct sockaddr *)((caddr_t)addr + + addr->sa_len); + kdebug_sockaddr(addr); + } + + printf(" }\n"); + + /* prevent infinite loop */ + if (xisr->sadb_x_ipsecrequest_len <= 0) { + printf("kdebug_sadb_x_policy: wrong policy struct.\n"); + return; + } + /* prevent overflow */ + if (xisr->sadb_x_ipsecrequest_len > tlen) { + printf("invalid ipsec policy length\n"); + return; + } + + tlen -= xisr->sadb_x_ipsecrequest_len; + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + + if (tlen != 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + } + + return; +} + +#ifdef _KERNEL +/* %%%: about SPD and SAD */ +void +kdebug_secpolicy(sp) + struct secpolicy *sp; +{ + /* sanity check */ + if (sp == NULL) + panic("kdebug_secpolicy: NULL pointer was passed.\n"); + + printf("secpolicy{ refcnt=%u state=%u policy=%u\n", + sp->refcnt, sp->state, sp->policy); + + kdebug_secpolicyindex(&sp->spidx); + + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + printf(" type=discard }\n"); + break; + case IPSEC_POLICY_NONE: + printf(" type=none }\n"); + break; + case IPSEC_POLICY_IPSEC: + { + struct ipsecrequest *isr; + for (isr = sp->req; isr != NULL; isr = isr->next) { + + printf(" level=%u\n", isr->level); + kdebug_secasindex(&isr->saidx); + + if (isr->sav != NULL) + kdebug_secasv(isr->sav); + } + printf(" }\n"); + } + break; + case IPSEC_POLICY_BYPASS: + printf(" type=bypass }\n"); + break; + case IPSEC_POLICY_ENTRUST: + printf(" type=entrust }\n"); + break; + default: + printf("kdebug_secpolicy: Invalid policy found. %d\n", + sp->policy); + break; + } + + return; +} + +void +kdebug_secpolicyindex(spidx) + struct secpolicyindex *spidx; +{ + /* sanity check */ + if (spidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n", + spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto); + + ipsec_hexdump((caddr_t)&spidx->src, + ((struct sockaddr *)&spidx->src)->sa_len); + printf("\n"); + ipsec_hexdump((caddr_t)&spidx->dst, + ((struct sockaddr *)&spidx->dst)->sa_len); + printf("}\n"); + + return; +} + +void +kdebug_secasindex(saidx) + struct secasindex *saidx; +{ + /* sanity check */ + if (saidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secasindex{ mode=%u proto=%u\n", + saidx->mode, saidx->proto); + + ipsec_hexdump((caddr_t)&saidx->src, + ((struct sockaddr *)&saidx->src)->sa_len); + printf("\n"); + ipsec_hexdump((caddr_t)&saidx->dst, + ((struct sockaddr *)&saidx->dst)->sa_len); + printf("\n"); + + return; +} + +void +kdebug_secasv(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("kdebug_secasv: NULL pointer was passed.\n"); + + printf("secas{"); + kdebug_secasindex(&sav->sah->saidx); + + printf(" refcnt=%u state=%u auth=%u enc=%u\n", + sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc); + printf(" spi=%u flags=%u\n", + (u_int32_t)ntohl(sav->spi), sav->flags); + + if (sav->key_auth != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_auth); + if (sav->key_enc != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_enc); + if (sav->iv != NULL) { + printf(" iv="); + ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); + printf("\n"); + } + + if (sav->replay != NULL) + kdebug_secreplay(sav->replay); + if (sav->lft_c != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c); + if (sav->lft_h != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h); + if (sav->lft_s != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s); + +#if notyet + /* XXX: misc[123] ? */ +#endif + + return; +} + +static void +kdebug_secreplay(rpl) + struct secreplay *rpl; +{ + int len, l; + + /* sanity check */ + if (rpl == NULL) + panic("kdebug_secreplay: NULL pointer was passed.\n"); + + printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u", + rpl->count, rpl->wsize, rpl->seq, rpl->lastseq); + + if (rpl->bitmap == NULL) { + printf(" }\n"); + return; + } + + printf("\n bitmap { "); + + for (len = 0; len < rpl->wsize; len++) { + for (l = 7; l >= 0; l--) + printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0); + } + printf(" }\n"); + + return; +} + +void +kdebug_mbufhdr(m) + struct mbuf *m; +{ + /* sanity check */ + if (m == NULL) + return; + + printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " + "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", + m, m->m_next, m->m_nextpkt, m->m_data, + m->m_len, m->m_type, m->m_flags); + + if (m->m_flags & M_PKTHDR) { + printf(" m_pkthdr{ len:%d rcvif:%p }\n", + m->m_pkthdr.len, m->m_pkthdr.rcvif); + } + + if (m->m_flags & M_EXT) { + printf(" m_ext{ ext_buf:%p ext_free:%p " + "ext_size:%u ext_ref:%p }\n", + m->m_ext.ext_buf, m->m_ext.ext_free, + m->m_ext.ext_size, m->m_ext.ext_ref); + } + + return; +} + +void +kdebug_mbuf(m0) + struct mbuf *m0; +{ + struct mbuf *m = m0; + int i, j; + + for (j = 0; m; m = m->m_next) { + kdebug_mbufhdr(m); + printf(" m_data:\n"); + for (i = 0; i < m->m_len; i++) { + if (i && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", mtod(m, u_char *)[i]); + j++; + } + printf("\n"); + } + + return; +} +#endif /* _KERNEL */ + +void +kdebug_sockaddr(addr) + struct sockaddr *addr; +{ + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + /* sanity check */ + if (addr == NULL) + panic("kdebug_sockaddr: NULL pointer was passed.\n"); + + /* NOTE: We deal with port number as host byte order. */ + printf("sockaddr{ len=%u family=%u", addr->sa_len, addr->sa_family); + + switch (addr->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *)addr; + printf(" port=%u\n", ntohs(sin->sin_port)); + ipsec_hexdump((caddr_t)&sin->sin_addr, sizeof(sin->sin_addr)); + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + printf(" port=%u\n", ntohs(sin6->sin6_port)); + printf(" flowinfo=0x%08x, scope_id=0x%08x\n", + sin6->sin6_flowinfo, sin6->sin6_scope_id); + ipsec_hexdump((caddr_t)&sin6->sin6_addr, + sizeof(sin6->sin6_addr)); + break; +#endif + } + + printf(" }\n"); + + return; +} + +void +ipsec_bindump(buf, len) + caddr_t buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) + printf("%c", (unsigned char)buf[i]); + + return; +} + + +void +ipsec_hexdump(buf, len) + caddr_t buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", (unsigned char)buf[i]); + } +#if 0 + if (i % 32 != 0) printf("\n"); +#endif + + return; +} + +#endif /* !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) */ diff --git a/racoon.tproj/libpfkey.h b/racoon.tproj/libpfkey.h new file mode 100644 index 0000000..28adea7 --- /dev/null +++ b/racoon.tproj/libpfkey.h @@ -0,0 +1,90 @@ +/* $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej 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. 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. + */ + +struct sadb_msg; +extern void pfkey_sadump __P((struct sadb_msg *)); +extern void pfkey_spdump __P((struct sadb_msg *)); + +struct sockaddr; +struct sadb_alg; +int ipsec_check_keylen __P((u_int, u_int, u_int)); +int ipsec_check_keylen2 __P((u_int, u_int, u_int)); +int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *)); +u_int pfkey_set_softrate __P((u_int, u_int)); +u_int pfkey_get_softrate __P((u_int)); +int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); +int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_delete __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_delete_all __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *)); +int pfkey_send_get __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_register __P((int, u_int)); +int pfkey_recv_register __P((int)); +int pfkey_set_supported __P((struct sadb_msg *, int)); +int pfkey_send_flush __P((int, u_int)); +int pfkey_send_dump __P((int, u_int)); +int pfkey_send_promisc_toggle __P((int, int)); +int pfkey_send_spdadd __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spddelete __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spddelete2 __P((int, u_int32_t)); +int pfkey_send_spdget __P((int, u_int32_t)); +int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdflush __P((int)); +int pfkey_send_spddump __P((int)); + +int pfkey_open __P((void)); +void pfkey_close __P((int)); +struct sadb_msg *pfkey_recv __P((int)); +int pfkey_send __P((int, struct sadb_msg *, int)); +int pfkey_align __P((struct sadb_msg *, caddr_t *)); +int pfkey_check __P((caddr_t *)); diff --git a/racoon.tproj/localconf.c b/racoon.tproj/localconf.c new file mode 100644 index 0000000..dbb42a2 --- /dev/null +++ b/racoon.tproj/localconf.c @@ -0,0 +1,324 @@ +/* $KAME: localconf.c,v 1.32 2001/06/01 08:26:05 sakane 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. 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. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "localconf.h" +#include "algorithm.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "grabmyaddr.h" +#include "vendorid.h" +#include "str2val.h" +#include "safefile.h" +#include "admin.h" +#include "gcmalloc.h" + +struct localconf *lcconf; + +static void setdefault __P((void)); +static vchar_t *getpsk __P((const char *, const int)); + +void +initlcconf() +{ + lcconf = racoon_calloc(1, sizeof(*lcconf)); + if (lcconf == NULL) + errx(1, "failed to allocate local conf."); + + setdefault(); + + lcconf->racoon_conf = LC_DEFAULT_CF; +} + +void +flushlcconf() +{ + int i; + + setdefault(); + clear_myaddr(&lcconf->myaddrs); + for (i = 0; i < LC_PATHTYPE_MAX; i++) { + if (lcconf->pathinfo[i]) { + racoon_free(lcconf->pathinfo[i]); + lcconf->pathinfo[i] = NULL; + } + } + for (i = 0; i < LC_IDENTTYPE_MAX; i++) { + if (lcconf->ident[i]) + vfree(lcconf->ident[i]); + lcconf->ident[i] = NULL; + } +} + +static void +setdefault() +{ + lcconf->autograbaddr = 1; + lcconf->port_isakmp = PORT_ISAKMP; + lcconf->default_af = AF_INET; + lcconf->pad_random = LC_DEFAULT_PAD_RANDOM; + lcconf->pad_randomlen = LC_DEFAULT_PAD_RANDOMLEN; + lcconf->pad_maxsize = LC_DEFAULT_PAD_MAXSIZE; + lcconf->pad_strict = LC_DEFAULT_PAD_STRICT; + lcconf->pad_excltail = LC_DEFAULT_PAD_EXCLTAIL; + lcconf->retry_counter = LC_DEFAULT_RETRY_COUNTER; + lcconf->retry_interval = LC_DEFAULT_RETRY_INTERVAL; + lcconf->count_persend = LC_DEFAULT_COUNT_PERSEND; + lcconf->secret_size = LC_DEFAULT_SECRETSIZE; + lcconf->retry_checkph1 = LC_DEFAULT_RETRY_CHECKPH1; + lcconf->wait_ph2complete = LC_DEFAULT_WAIT_PH2COMPLETE; + lcconf->strict_address = FALSE; + lcconf->complex_bundle = TRUE; /*XXX FALSE;*/ +} + +/* + * get PSK by string. + */ +vchar_t * +getpskbyname(id0) + vchar_t *id0; +{ + char *id; + vchar_t *key = NULL; + + id = racoon_calloc(1, 1 + id0->l - sizeof(struct ipsecdoi_id_b)); + if (id == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get psk buffer.\n"); + goto end; + } + memcpy(id, id0->v + sizeof(struct ipsecdoi_id_b), + id0->l - sizeof(struct ipsecdoi_id_b)); + id[id0->l - sizeof(struct ipsecdoi_id_b)] = '\0'; + + key = getpsk(id, id0->l - sizeof(struct ipsecdoi_id_b)); + +end: + if (id) + racoon_free(id); + return key; +} + +/* + * get PSK by address. + */ +vchar_t * +getpskbyaddr(remote) + struct sockaddr *remote; +{ + vchar_t *key = NULL; + char addr[NI_MAXHOST], port[NI_MAXSERV]; + + GETNAMEINFO(remote, addr, port); + + key = getpsk(addr, strlen(addr)); + + return key; +} + +static vchar_t * +getpsk(str, len) + const char *str; + const int len; +{ + FILE *fp; + char buf[1024]; /* XXX how is variable length ? */ + vchar_t *key = NULL; + char *p, *q; + size_t keylen; + char *k = NULL; + + if (safefile(lcconf->pathinfo[LC_PATHTYPE_PSK], 1) == 0) + fp = fopen(lcconf->pathinfo[LC_PATHTYPE_PSK], "r"); + else + fp = NULL; + if (fp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to open pre_share_key file %s\n", + lcconf->pathinfo[LC_PATHTYPE_PSK]); + return NULL; + } + + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* comment line */ + if (buf[0] == '#') + continue; + + /* search the end of 1st string. */ + for (p = buf; *p != '\0' && !isspace(*p); p++) + ; + if (*p == '\0') + continue; /* no 2nd parameter */ + *p = '\0'; + /* search the 1st of 2nd string. */ + while (isspace(*++p)) + ; + if (*p == '\0') + continue; /* no 2nd parameter */ + p--; + if (strncmp(buf, str, len) == 0 && buf[len] == '\0') { + p++; + keylen = 0; + for (q = p; *q != '\0' && *q != '\n'; q++) + keylen++; + *q = '\0'; + + /* fix key if hex string */ + if (strncmp(p, "0x", 2) == 0) { + k = str2val(p + 2, 16, &keylen); + if (k == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get psk buffer.\n"); + goto end; + } + p = k; + } + + key = vmalloc(keylen); + if (key == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate key buffer.\n"); + goto end; + } + memcpy(key->v, p, key->l); + if (k) + racoon_free(k); + goto end; + } + } + +end: + fclose(fp); + return key; +} + +/* + * get a file name of a type specified. + */ +void +getpathname(path, len, type, name) + char *path; + int len, type; + const char *name; +{ + snprintf(path, len, "%s%s%s", + name[0] == '/' ? "" : lcconf->pathinfo[type], + name[0] == '/' ? "" : "/", + name); + + plog(LLV_DEBUG, LOCATION, NULL, "filename: %s\n", path); +} + +#if 0 /* DELETEIT */ +static int lc_doi2idtype[] = { + -1, + -1, + LC_IDENTTYPE_FQDN, + LC_IDENTTYPE_USERFQDN, + -1, + -1, + -1, + -1, + -1, + LC_IDENTTYPE_CERTNAME, + -1, + LC_IDENTTYPE_KEYID, +}; + +/* + * convert DOI value to idtype + * OUT -1 : NG + * other: converted. + */ +int +doi2idtype(idtype) + int idtype; +{ + if (ARRAYLEN(lc_doi2idtype) > idtype) + return lc_doi2idtype[idtype]; + return -1; +} +#endif + +static int lc_sittype2doi[] = { + IPSECDOI_SIT_IDENTITY_ONLY, + IPSECDOI_SIT_SECRECY, + IPSECDOI_SIT_INTEGRITY, +}; + +/* + * convert sittype to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +sittype2doi(sittype) + int sittype; +{ + if (ARRAYLEN(lc_sittype2doi) > sittype) + return lc_sittype2doi[sittype]; + return -1; +} + +static int lc_doitype2doi[] = { + IPSEC_DOI, +}; + +/* + * convert doitype to DOI value. + * OUT -1 : NG + * other: converted. + */ +int +doitype2doi(doitype) + int doitype; +{ + if (ARRAYLEN(lc_doitype2doi) > doitype) + return lc_doitype2doi[doitype]; + return -1; +} + diff --git a/racoon.tproj/localconf.h b/racoon.tproj/localconf.h new file mode 100644 index 0000000..c1406f3 --- /dev/null +++ b/racoon.tproj/localconf.h @@ -0,0 +1,111 @@ +/* $KAME: localconf.h,v 1.27 2001/08/09 07:32:19 sakane 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. 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. + */ + +/* local configuration */ + +#define LC_DEFAULT_CF SYSCONFDIR "/racoon.conf" + +#define LC_PATHTYPE_INCLUDE 0 +#define LC_PATHTYPE_PSK 1 +#define LC_PATHTYPE_CERT 2 +#define LC_PATHTYPE_BACKUPSA 3 +#define LC_PATHTYPE_MAX 4 + +#define LC_DEFAULT_PAD_MAXSIZE 20 +#define LC_DEFAULT_PAD_RANDOM TRUE +#define LC_DEFAULT_PAD_RANDOMLEN FALSE +#define LC_DEFAULT_PAD_STRICT FALSE +#define LC_DEFAULT_PAD_EXCLTAIL TRUE +#define LC_DEFAULT_RETRY_COUNTER 5 +#define LC_DEFAULT_RETRY_INTERVAL 10 +#define LC_DEFAULT_COUNT_PERSEND 1 +#define LC_DEFAULT_RETRY_CHECKPH1 30 +#define LC_DEFAULT_WAIT_PH2COMPLETE 30 + +#define LC_DEFAULT_SECRETSIZE 16 /* 128 bits */ + +#define LC_IDENTTYPE_MAX 5 /* XXX */ + +struct localconf { + char *racoon_conf; /* configuration filename */ + + u_int16_t port_isakmp; /* port for isakmp as default */ + u_int16_t port_admin; /* port for admin */ + int default_af; /* default address family */ + + int sock_admin; + int sock_pfkey; + int rtsock; /* routing socket */ + + int autograbaddr; + struct myaddrs *myaddrs; + + char *pathinfo[LC_PATHTYPE_MAX]; + vchar_t *ident[LC_IDENTTYPE_MAX]; /* base of Identifier payload. */ + + int pad_random; + int pad_randomlen; + int pad_maxsize; + int pad_strict; + int pad_excltail; + + int retry_counter; /* times to retry. */ + int retry_interval; /* interval each retry. */ + int count_persend; /* the number of packets each retry. */ + /* above 3 values are copied into a handler. */ + + int retry_checkph1; + int wait_ph2complete; + + int secret_size; + int strict_address; /* strictly check addresses. */ + + int complex_bundle; + /* + * If we want to make a packet "IP2 AH ESP IP1 ULP", + * the SPD in KAME expresses AH transport + ESP tunnel. + * So racoon sent the proposal contained such the order. + * But lots of implementation interprets AH tunnel + ESP + * tunnel in this case. racoon has changed the format, + * usually uses this format. If the option, 'complex_bundle' + * is enable, racoon uses old format. + */ +}; + +extern struct localconf *lcconf; + +extern void initlcconf __P((void)); +extern void flushlcconf __P((void)); +extern vchar_t *getpskbyname __P((vchar_t *)); +extern vchar_t *getpskbyaddr __P((struct sockaddr *)); +extern void getpathname __P((char *, int, int, const char *)); +extern int sittype2doi __P((int)); +extern int doitype2doi __P((int)); diff --git a/racoon.tproj/logger.c b/racoon.tproj/logger.c new file mode 100644 index 0000000..0f3b5df --- /dev/null +++ b/racoon.tproj/logger.c @@ -0,0 +1,258 @@ +/* $KAME: logger.c,v 1.7 2000/10/04 17:41:01 itojun 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. 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. + */ + +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "logger.h" +#include "var.h" +#include "gcmalloc.h" + +struct log * +log_open(siz, fname) + size_t siz; + char *fname; +{ + struct log *p; + + p = (struct log *)racoon_malloc(sizeof(*p)); + if (p == NULL) + return NULL; + memset(p, 0, sizeof(*p)); + + p->buf = (char **)racoon_malloc(sizeof(char *) * siz); + if (p->buf == NULL) { + racoon_free(p); + return NULL; + } + memset(p->buf, 0, sizeof(char *) * siz); + + p->tbuf = (time_t *)racoon_malloc(sizeof(time_t *) * siz); + if (p->tbuf == NULL) { + racoon_free(p); + racoon_free(p->buf); + return NULL; + } + memset(p->tbuf, 0, sizeof(time_t *) * siz); + + p->siz = siz; + if (fname) + p->fname = strdup(fname); + + return p; +} + +/* + * append string to ring buffer. + * string must be \n-terminated (since we add timestamps). + * even if not, we'll add \n to avoid formatting mistake (see log_close()). + */ +void +log_add(p, str) + struct log *p; + char *str; +{ + /* syslog if p->fname == NULL? */ + if (p->buf[p->head]) + racoon_free(p->buf[p->head]); + p->buf[p->head] = strdup(str); + p->tbuf[p->head] = time(NULL); + p->head++; + p->head %= p->siz; +} + +/* + * write out string to the log file, as is. + * \n-termination is up to the caller. if you don't add \n, the file + * format may be broken. + */ +int +log_print(p, str) + struct log *p; + char *str; +{ + FILE *fp; + + if (p->fname == NULL) + return -1; /*XXX syslog?*/ + fp = fopen(p->fname, "a"); + if (fp == NULL) + return -1; + fprintf(fp, "%s", str); + fclose(fp); + + return 0; +} + +int +log_vprint(struct log *p, const char *fmt, ...) +{ + va_list ap; + + FILE *fp; + + if (p->fname == NULL) + return -1; /*XXX syslog?*/ + fp = fopen(p->fname, "a"); + if (fp == NULL) + return -1; + va_start(ap, fmt); + vfprintf(fp, fmt, ap); + va_end(ap); + + fclose(fp); + + return 0; +} + +int +log_vaprint(struct log *p, const char *fmt, va_list ap) +{ + FILE *fp; + + if (p->fname == NULL) + return -1; /*XXX syslog?*/ + fp = fopen(p->fname, "a"); + if (fp == NULL) + return -1; + vfprintf(fp, fmt, ap); + fclose(fp); + + return 0; +} + +/* + * write out content of ring buffer, and reclaim the log structure + */ +int +log_close(p) + struct log *p; +{ + FILE *fp; + int i, j; + char ts[256]; + struct tm *tm; + + if (p->fname == NULL) + goto nowrite; + fp = fopen(p->fname, "a"); + if (fp == NULL) + goto nowrite; + + for (i = 0; i < p->siz; i++) { + j = (p->head + i) % p->siz; + if (p->buf[j]) { + tm = localtime(&p->tbuf[j]); + strftime(ts, sizeof(ts), "%B %d %T", tm); + fprintf(fp, "%s: %s\n", ts, p->buf[j]); + if (*(p->buf[j] + strlen(p->buf[j]) - 1) != '\n') + fprintf(fp, "\n"); + } + } + fclose(fp); + +nowrite: + log_free(p); + return 0; +} + +void +log_free(p) + struct log *p; +{ + int i; + + for (i = 0; i < p->siz; i++) + racoon_free(p->buf[i]); + racoon_free(p->buf); + racoon_free(p->tbuf); + if (p->fname) + racoon_free(p->fname); + racoon_free(p); +} + +#ifdef TEST +struct log *l; + +void +vatest(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + log_vaprint(l, fmt, ap); + va_end(ap); +} + +int +main(argc, argv) + int argc; + char **argv; +{ + int i; + + l = log_open(30, "/tmp/hoge"); + if (l == NULL) + errx(1, "hoge"); + + for (i = 0; i < 50; i++) { + log_add(l, "foo"); + log_add(l, "baa"); + log_add(l, "baz"); + } + log_print(l, "hoge\n"); + log_vprint(l, "hoge %s\n", "this is test"); + vatest("%s %s\n", "this is", "vprint test"); + abort(); + log_free(l); +} + +#endif + diff --git a/racoon.tproj/logger.h b/racoon.tproj/logger.h new file mode 100644 index 0000000..280f041 --- /dev/null +++ b/racoon.tproj/logger.h @@ -0,0 +1,46 @@ +/* $KAME: logger.h,v 1.3 2000/09/13 04:50:27 itojun 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. 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. + */ + +struct log { + int head; + int siz; + char **buf; + time_t *tbuf; + char *fname; +}; + +extern struct log *log_open __P((size_t, char *)); +extern void log_add __P((struct log *, char *)); +extern int log_print __P((struct log *, char *)); +extern int log_vprint __P((struct log *, const char *, ...)); +extern int log_vaprint __P((struct log *, const char *, va_list)); +extern int log_close __P((struct log *)); +extern void log_free __P((struct log *)); diff --git a/racoon.tproj/main.c b/racoon.tproj/main.c new file mode 100644 index 0000000..109f96d --- /dev/null +++ b/racoon.tproj/main.c @@ -0,0 +1,395 @@ +/* $KAME: main.c,v 1.43 2001/11/16 04:34:57 sakane 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. 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. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +/* + * If we're using a debugging malloc library, this may define our + * wrapper stubs. + */ +#define RACOON_MAIN_PROGRAM +#include "gcmalloc.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "cfparse.h" +#include "isakmp_var.h" +#include "remoteconf.h" +#include "localconf.h" +#include "session.h" +#include "oakley.h" +#include "pfkey.h" +#include "crypto_openssl.h" +#include "backupsa.h" + +int f_foreground = 0; /* force running in foreground. */ +int f_local = 0; /* local test mode. behave like a wall. */ +int vflag = 1; /* for print-isakmp.c */ +static int loading_sa = 0; /* install sa when racoon boots up. */ + +#define RACOON_VERSION "20001216 sakane@kame.net" +#ifdef RACOON_PKG_VERSION +static char version0[] = "@(#)package version " RACOON_PKG_VERSION ; +static char version[] = "@(#)internal version " RACOON_VERSION ; +#else +static char version[] = "@(#)racoon 20001216 " RACOON_VERSION ; +#endif +static pid_t racoon_pid = 0; + +int main __P((int, char **)); +static void usage __P((void)); +static void parse __P((int, char **)); +static void restore_params __P((void)); +static void save_params __P((void)); +static void saverestore_params __P((int)); +static void cleanup_pidfile __P((void)); + +void +usage() +{ + printf("usage: racoon [-BdFv%s] %s[-f (file)] [-l (file)] [-p (port)]\n", +#ifdef INET6 + "46", +#else + "", +#endif +#ifdef ENABLE_ADMINPORT + "[-a (port)] " +#else + "" +#endif + ); + printf(" -B: install SA to the kernel from the file " + "specified by the configuration file.\n"); + printf(" -d: debug level, more -d will generate more debug message.\n"); + printf(" -F: run in foreground, do not become daemon.\n"); + printf(" -v: be more verbose\n"); +#ifdef INET6 + printf(" -4: IPv4 mode.\n"); + printf(" -6: IPv6 mode.\n"); +#endif +#ifdef ENABLE_ADMINPORT + printf(" -a: port number for admin port.\n"); +#endif + printf(" -f: pathname for configuration file.\n"); + printf(" -l: pathname for log file.\n"); + printf(" -p: port number for isakmp (default: %d).\n", PORT_ISAKMP); + exit(1); +} + +int +main(ac, av) + int ac; + char **av; +{ + int error; + + if (geteuid() != 0) { + errx(1, "must be root to invoke this program."); + /* NOTREACHED*/ + } + + /* + * Don't let anyone read files I write. Although some files (such as + * the PID file) can be other readable, we dare to use the global mask, + * because racoon uses fopen(3), which can't specify the permission + * at the creation time. + */ + umask(077); + if (umask(077) != 077) { + errx(1, "could not set umask"); + /* NOTREACHED*/ + } + +#ifdef DEBUG_RECORD_MALLOCATION + DRM_init(); +#endif + + initlcconf(); + initrmconf(); + oakley_dhinit(); + eay_init_error(); + + parse(ac, av); + + ploginit(); + +#ifdef RACOON_PKG_VERSION + plog(LLV_INFO, LOCATION, NULL, "%s\n", version0); +#endif + plog(LLV_INFO, LOCATION, NULL, "%s\n", version); + plog(LLV_INFO, LOCATION, NULL, "@(#)" + "This product linked %s (http://www.openssl.org/)" + "\n", eay_version()); + + if (pfkey_init() < 0) { + errx(1, "something error happened " + "while pfkey initializing."); + /* NOTREACHED*/ + } + + /* + * in order to prefer the parameters by command line, + * saving some parameters before parsing configuration file. + */ + save_params(); + error = cfparse(); + if (error != 0) + errx(1, "failed to parse configuration file."); + restore_params(); + + /* + * install SAs from the specified file. If the file is not specified + * by the configuration file, racoon will exit. + */ + if (loading_sa && !f_local) { + if (backupsa_from_file() != 0) + errx(1, "something error happened " + "SA recovering."); + } + + if (f_foreground) + close(0); + else { + const char *pid_file = _PATH_VARRUN "racoon.pid"; + FILE *fp; + + if (daemon(0, 0) < 0) { + errx(1, "failed to be daemon. (%s)", + strerror(errno)); + } + /* + * In case somebody has started inetd manually, we need to + * clear the logname, so that old servers run as root do not + * get the user's logname.. + */ + if (setlogin("") < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot clear logname: %s\n", strerror(errno)); + /* no big deal if it fails.. */ + } + racoon_pid = getpid(); + fp = fopen(pid_file, "w"); + if (fp) { + if (fchmod(fileno(fp), + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { + syslog(LOG_ERR, "%s", strerror(errno)); + fclose(fp); + exit(1); + } + fprintf(fp, "%ld\n", (long)racoon_pid); + fclose(fp); + } else { + plog(LLV_ERROR, LOCATION, NULL, + "cannot open %s", pid_file); + } + if (!f_local) { + if (atexit(cleanup_pidfile) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "cannot register pidfile cleanup"); + } + } + } + + session(); + + exit(0); +} + +static void +cleanup_pidfile() +{ + pid_t p = getpid(); + + /* if it's not child process, clean everything */ + if (racoon_pid == p) { + const char *pid_file = _PATH_VARRUN "racoon.pid"; + + (void) unlink(pid_file); + } +} + +static void +parse(ac, av) + int ac; + char **av; +{ + extern char *optarg; + extern int optind; + int c; +#ifdef YYDEBUG + extern int yydebug; +#endif + + pname = strrchr(*av, '/'); + if (pname) + pname++; + else + pname = *av; + + while ((c = getopt(ac, av, "dFp:a:f:l:vZB" +#ifdef YYDEBUG + "y" +#endif +#ifdef INET6 + "46" +#endif + )) != -1) { + switch (c) { + case 'd': + loglevel++; + break; + case 'F': + printf("Foreground mode.\n"); + f_foreground = 1; + break; + case 'p': + lcconf->port_isakmp = atoi(optarg); + break; + case 'a': +#ifdef ENABLE_ADMINPORT + lcconf->port_admin = atoi(optarg); + break; +#else + fprintf(stderr, "%s: the option is disabled " + "in the configuration\n", pname); + exit(1); +#endif + case 'f': + lcconf->racoon_conf = optarg; + break; + case 'l': + plogset(optarg); + break; + case 'v': + vflag++; + break; + case 'Z': + /* + * only local test. + * To specify -Z option and to choice a appropriate + * port number for ISAKMP, you can launch some racoons + * on the local host for debug. + * pk_sendadd() on initiator side is always failed + * even if this flag is used. Because there is same + * spi in the SAD which is inserted by pk_sendgetspi() + * on responder side. + */ + printf("Local test mode.\n"); + f_local = 1; + break; +#ifdef YYDEBUG + case 'y': + yydebug = 1; + break; +#endif +#ifdef INET6 + case '4': + lcconf->default_af = AF_INET; + break; + case '6': + lcconf->default_af = AF_INET6; + break; +#endif + case 'B': + loading_sa++; + break; + default: + usage(); + /* NOTREACHED */ + } + } + ac -= optind; + av += optind; + + if (ac != 0) { + usage(); + /* NOTREACHED */ + } + + return; +} + +static void +restore_params() +{ + saverestore_params(1); +} + +static void +save_params() +{ + saverestore_params(0); +} + +static void +saverestore_params(f) + int f; +{ + static u_int16_t s_port_isakmp; +#ifdef ENABLE_ADMINPORT + static u_int16_t s_port_admin; +#endif + + /* 0: save, 1: restore */ + if (f) { + lcconf->port_isakmp = s_port_isakmp; +#ifdef ENABLE_ADMINPORT + lcconf->port_admin = s_port_admin; +#endif + } else { + s_port_isakmp = lcconf->port_isakmp; +#ifdef ENABLE_ADMINPORT + s_port_admin = lcconf->port_admin; +#endif + } +} diff --git a/racoon.tproj/misc.c b/racoon.tproj/misc.c new file mode 100644 index 0000000..8906017 --- /dev/null +++ b/racoon.tproj/misc.c @@ -0,0 +1,167 @@ +/* $KAME: misc.c,v 1.22 2001/07/14 05:48:33 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "debug.h" + +#if 0 +static int bindump __P((void *, size_t)); + +static int +bindump(buf0, len) + void *buf0; + size_t len; +{ + unsigned char *buf = (unsigned char *)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if ((buf[i] & 0x80) || !isprint(buf[i])) + printf("\\x%x", buf[i]); + else + printf("%c", buf[i]); + } + printf("\n"); + + return 0; +} +#endif + +int +hexdump(buf0, len) + void *buf0; + size_t len; +{ + caddr_t buf = (caddr_t)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", (unsigned char)buf[i]); + } + printf("\n"); + + return 0; +} + +char * +bit2str(n, bl) + int n, bl; +{ +#define MAXBITLEN 128 + static char b[MAXBITLEN + 1]; + int i; + + if (bl > MAXBITLEN) + return "Failed to convert."; /* NG */ + memset(b, '0', bl); + b[bl] = '\0'; + + for (i = 0; i < bl; i++) { + if (n & (1 << i)) + b[bl - 1 - i] = '1'; + } + + return b; +} + +const char * +debug_location(file, line, func) + const char *file; + int line; + const char *func; +{ + static char buf[1024]; + const char *p; + + /* truncate pathname */ + p = strrchr(file, '/'); + if (p) + p++; + else + p = file; + + if (func) + snprintf(buf, sizeof(buf), "%s:%d:%s()", p, line, func); + else + snprintf(buf, sizeof(buf), "%s:%d", p, line); + + return buf; +} + +/* + * get file size. + * -1: error occured. + */ +int +getfsize(path) + char *path; +{ + struct stat st; + + if (stat(path, &st) != 0) + return -1; + else + return st.st_size; +} + +/* + * calculate the difference between two times. + * t1: start + * t2: end + */ +double +timedelta(t1, t2) + struct timeval *t1, *t2; +{ + if (t2->tv_usec >= t1->tv_usec) + return t2->tv_sec - t1->tv_sec + + (double)(t2->tv_usec - t1->tv_usec) / 1000000; + + return t2->tv_sec - t1->tv_sec - 1 + + (double)(1000000 + t2->tv_usec - t1->tv_usec) / 1000000; +} diff --git a/racoon.tproj/misc.h b/racoon.tproj/misc.h new file mode 100644 index 0000000..c5f2846 --- /dev/null +++ b/racoon.tproj/misc.h @@ -0,0 +1,46 @@ +/* $KAME: misc.h,v 1.11 2001/07/14 05:48:33 sakane 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. 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. + */ + +#define BIT2STR(b) bit2str(b, sizeof(b)<<3) + +#ifdef HAVE_FUNCTION_MACRO +#define LOCATION debug_location(__FILE__, __LINE__, __FUNCTION__) +#else +#define LOCATION debug_location(__FILE__, __LINE__, NULL) +#endif + +extern int hexdump __P((void *, size_t)); +extern char *bit2str __P((int, int)); +extern void *get_newbuf __P((void *, size_t)); +extern const char *debug_location __P((const char *, int, const char *)); +extern int getfsize __P((char *)); +struct timeval; +extern double timedelta __P((struct timeval *, struct timeval *)); diff --git a/racoon.tproj/netdb_dnssec.h b/racoon.tproj/netdb_dnssec.h new file mode 100644 index 0000000..f0d3582 --- /dev/null +++ b/racoon.tproj/netdb_dnssec.h @@ -0,0 +1,67 @@ +/* $KAME: netdb_dnssec.h,v 1.1 2001/04/11 06:11:55 sakane 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. 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. + */ + +#ifndef T_CERT +#define T_CERT 37 /* defined by RFC2538 section 2 */ +#endif + +/* RFC2538 section 2.1 */ +#define DNSSEC_TYPE_PKIX 1 +#define DNSSEC_TYPE_SPKI 2 +#define DNSSEC_TYPE_PGP 3 +#define DNSSEC_TYPE_URI 4 +#define DNSSEC_TYPE_OID 5 + +/* RFC2535 section 3.2 */ +#define DNSSEC_ALG_RSAMD5 1 +#define DNSSEC_ALG_DH 2 +#define DNSSEC_ALG_DSA 3 +#define DNSSEC_ALG_ECC 4 +#define DNSSEC_ALG_PRIVATEDNS 5 +#define DNSSEC_ALG_PRIVATEOID 6 + +/* + * Structures returned by network data base library. All addresses are + * supplied in host order, and returned in network order (suitable for + * use in system calls). + */ +struct certinfo { + int ci_type; /* certificate type */ + int ci_keytag; /* keytag */ + int ci_algorithm; /* algorithm */ + int ci_flags; /* currently, 1:valid or 0:uncertain */ + size_t ci_certlen; /* length of certificate */ + char *ci_cert; /* certificate */ + struct certinfo *ci_next; /* next structure */ +}; + +extern void freecertinfo __P((struct certinfo *)); +extern int getcertsbyname __P((char *, struct certinfo **)); diff --git a/racoon.tproj/oakley.c b/racoon.tproj/oakley.c new file mode 100644 index 0000000..5caa962 --- /dev/null +++ b/racoon.tproj/oakley.c @@ -0,0 +1,2852 @@ +/* $KAME: oakley.c,v 1.111 2001/12/20 23:33:22 sakane 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. 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. + */ + +#include +#include +#include /* XXX for subjectaltname */ +#include /* XXX for subjectaltname */ + +#include +#include +#include +#include + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "str2val.h" +#include "plog.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "localconf.h" +#include "remoteconf.h" +#include "policy.h" +#include "handler.h" +#include "ipsec_doi.h" +#include "algorithm.h" +#include "dhgroup.h" +#include "sainfo.h" +#include "proposal.h" +#include "crypto_openssl.h" +#include "dnssec.h" +#include "sockmisc.h" +#include "strnames.h" +#include "gcmalloc.h" + +#ifdef HAVE_GSSAPI +#include "gssapi.h" +#endif + +#define OUTBOUND_SA 0 +#define INBOUND_SA 1 + +#define INITDHVAL(a, s, d, t) \ +do { \ + vchar_t buf; \ + buf.v = str2val((s), 16, &buf.l); \ + memset(&a, 0, sizeof(struct dhgroup)); \ + a.type = (t); \ + a.prime = vdup(&buf); \ + a.gen1 = 2; \ + a.gen2 = 0; \ +} while(0); + +struct dhgroup dh_modp768; +struct dhgroup dh_modp1024; +struct dhgroup dh_modp1536; +struct dhgroup dh_modp2048; +struct dhgroup dh_modp3072; +struct dhgroup dh_modp4096; +struct dhgroup dh_modp6144; +struct dhgroup dh_modp8192; + +static int oakley_compute_keymat_x __P((struct ph2handle *, int, int)); +#ifdef HAVE_SIGNING_C +static int get_cert_fromlocal __P((struct ph1handle *, int)); +static int oakley_check_certid __P((struct ph1handle *iph1)); +static int check_typeofcertname __P((int, int)); +static cert_t *save_certbuf __P((struct isakmp_gen *)); +#endif +static int oakley_padlen __P((int, int)); + +int +oakley_get_defaultlifetime() +{ + return OAKLEY_ATTR_SA_LD_SEC_DEFAULT; +} + +int +oakley_dhinit() +{ + /* set DH MODP */ + INITDHVAL(dh_modp768, OAKLEY_PRIME_MODP768, + OAKLEY_ATTR_GRP_DESC_MODP768, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp1024, OAKLEY_PRIME_MODP1024, + OAKLEY_ATTR_GRP_DESC_MODP1024, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp1536, OAKLEY_PRIME_MODP1536, + OAKLEY_ATTR_GRP_DESC_MODP1536, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp2048, OAKLEY_PRIME_MODP2048, + OAKLEY_ATTR_GRP_DESC_MODP2048, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp3072, OAKLEY_PRIME_MODP3072, + OAKLEY_ATTR_GRP_DESC_MODP3072, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp4096, OAKLEY_PRIME_MODP4096, + OAKLEY_ATTR_GRP_DESC_MODP4096, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp6144, OAKLEY_PRIME_MODP6144, + OAKLEY_ATTR_GRP_DESC_MODP6144, OAKLEY_ATTR_GRP_TYPE_MODP); + INITDHVAL(dh_modp8192, OAKLEY_PRIME_MODP8192, + OAKLEY_ATTR_GRP_DESC_MODP8192, OAKLEY_ATTR_GRP_TYPE_MODP); + + return 0; +} + +void +oakley_dhgrp_free(dhgrp) + struct dhgroup *dhgrp; +{ + if (dhgrp->prime) + vfree(dhgrp->prime); + if (dhgrp->curve_a) + vfree(dhgrp->curve_a); + if (dhgrp->curve_b) + vfree(dhgrp->curve_b); + if (dhgrp->order) + vfree(dhgrp->order); + racoon_free(dhgrp); +} + +/* + * compute sharing secret of DH + * IN: *dh, *pub, *priv, *pub_p + * OUT: **gxy + */ +int +oakley_dh_compute(dh, pub, priv, pub_p, gxy) + const struct dhgroup *dh; + vchar_t *pub, *priv, *pub_p, **gxy; +{ +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + if ((*gxy = vmalloc(dh->prime->l)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get DH buffer.\n"); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + switch (dh->type) { + case OAKLEY_ATTR_GRP_TYPE_MODP: + if (eay_dh_compute(dh->prime, dh->gen1, pub, priv, pub_p, gxy) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to compute dh value.\n"); + return -1; + } + break; + case OAKLEY_ATTR_GRP_TYPE_ECP: + case OAKLEY_ATTR_GRP_TYPE_EC2N: + plog(LLV_ERROR, LOCATION, NULL, + "dh type %d isn't supported.\n", dh->type); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid dh type %d.\n", dh->type); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __FUNCTION__, + s_attr_isakmp_group(dh->type), dh->prime->l << 3, + timedelta(&start, &end)); +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's shared.\n"); + plogdump(LLV_DEBUG, (*gxy)->v, (*gxy)->l); + + return 0; +} + +/* + * generate values of DH + * IN: *dh + * OUT: **pub, **priv + */ +int +oakley_dh_generate(dh, pub, priv) + const struct dhgroup *dh; + vchar_t **pub, **priv; +{ +#ifdef ENABLE_STATS + struct timeval start, end; + gettimeofday(&start, NULL); +#endif + switch (dh->type) { + case OAKLEY_ATTR_GRP_TYPE_MODP: + if (eay_dh_generate(dh->prime, dh->gen1, dh->gen2, pub, priv) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to compute dh value.\n"); + return -1; + } + break; + + case OAKLEY_ATTR_GRP_TYPE_ECP: + case OAKLEY_ATTR_GRP_TYPE_EC2N: + plog(LLV_ERROR, LOCATION, NULL, + "dh type %d isn't supported.\n", dh->type); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid dh type %d.\n", dh->type); + return -1; + } + +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s%d): %8.6f", __FUNCTION__, + s_attr_isakmp_group(dh->type), dh->prime->l << 3, + timedelta(&start, &end)); +#endif + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's private.\n"); + plogdump(LLV_DEBUG, (*priv)->v, (*priv)->l); + plog(LLV_DEBUG, LOCATION, NULL, "compute DH's public.\n"); + plogdump(LLV_DEBUG, (*pub)->v, (*pub)->l); + + return 0; +} + +/* + * copy pre-defined dhgroup values. + */ +int +oakley_setdhgroup(group, dhgrp) + int group; + struct dhgroup **dhgrp; +{ + struct dhgroup *g; + + *dhgrp = NULL; /* just make sure, initialize */ + + g = alg_oakley_dhdef_group(group); + if (g == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid DH parameter grp=%d.\n", group); + return -1; + } + + if (!g->type || !g->prime || !g->gen1) { + /* unsuported */ + plog(LLV_ERROR, LOCATION, NULL, + "unsupported DH parameters grp=%d.\n", group); + return -1; + } + + *dhgrp = racoon_calloc(1, sizeof(struct dhgroup)); + if (*dhgrp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get DH buffer.\n"); + return 0; + } + + /* set defined dh vlaues */ + memcpy(*dhgrp, g, sizeof(*g)); + (*dhgrp)->prime = vdup(g->prime); + + return 0; +} + +/* + * PRF + * + * NOTE: we do not support prf with different input/output bitwidth, + * so we do not implement RFC2409 Appendix B (DOORAK-MAC example) in + * oakley_compute_keymat(). If you add support for such prf function, + * modify oakley_compute_keymat() accordingly. + */ +vchar_t * +oakley_prf(key, buf, iph1) + vchar_t *key, *buf; + struct ph1handle *iph1; +{ + vchar_t *res = NULL; + int type; + + if (iph1->approval == NULL) { + /* + * it's before negotiating hash algorithm. + * We use md5 as default. + */ + type = OAKLEY_ATTR_HASH_ALG_MD5; + } else + type = iph1->approval->hashtype; + + res = alg_oakley_hmacdef_one(type, key, buf); + if (res == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hmac algorithm %d.\n", type); + return NULL; + } + + return res; +} + +/* + * hash + */ +vchar_t * +oakley_hash(buf, iph1) + vchar_t *buf; + struct ph1handle *iph1; +{ + vchar_t *res = NULL; + int type; + + if (iph1->approval == NULL) { + /* + * it's before negotiating hash algorithm. + * We use md5 as default. + */ + type = OAKLEY_ATTR_HASH_ALG_MD5; + } else + type = iph1->approval->hashtype; + + res = alg_oakley_hashdef_one(type, buf); + if (res == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hash algoriym %d.\n", type); + return NULL; + } + + return res; +} + +/* + * compute KEYMAT + * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. + */ +int +oakley_compute_keymat(iph2, side) + struct ph2handle *iph2; + int side; +{ + int error = -1; + + /* compute sharing secret of DH when PFS */ + if (iph2->approval->pfs_group && iph2->dhpub_p) { + if (oakley_dh_compute(iph2->pfsgrp, iph2->dhpub, + iph2->dhpriv, iph2->dhpub_p, &iph2->dhgxy) < 0) + goto end; + } + + /* compute keymat */ + if (oakley_compute_keymat_x(iph2, side, INBOUND_SA) < 0 + || oakley_compute_keymat_x(iph2, side, OUTBOUND_SA) < 0) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT computed.\n"); + + error = 0; + +end: + return error; +} + +/* + * compute KEYMAT. + * KEYMAT = prf(SKEYID_d, protocol | SPI | Ni_b | Nr_b). + * If PFS is desired and KE payloads were exchanged, + * KEYMAT = prf(SKEYID_d, g(qm)^xy | protocol | SPI | Ni_b | Nr_b) + * + * NOTE: we do not support prf with different input/output bitwidth, + * so we do not implement RFC2409 Appendix B (DOORAK-MAC example). + */ +static int +oakley_compute_keymat_x(iph2, side, sa_dir) + struct ph2handle *iph2; + int side; + int sa_dir; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + char *p; + int len; + int error = -1; + int pfs = 0; + int dupkeymat; /* generate K[1-dupkeymat] */ + struct saproto *pr; + struct satrns *tr; + int encklen, authklen, l; + + pfs = ((iph2->approval->pfs_group && iph2->dhgxy) ? 1 : 0); + + len = pfs ? iph2->dhgxy->l : 0; + len += (1 + + sizeof(u_int32_t) /* XXX SPI size */ + + iph2->nonce->l + + iph2->nonce_p->l); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get keymat buffer.\n"); + goto end; + } + + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + p = buf->v; + + /* if PFS */ + if (pfs) { + memcpy(p, iph2->dhgxy->v, iph2->dhgxy->l); + p += iph2->dhgxy->l; + } + + p[0] = pr->proto_id; + p += 1; + + memcpy(p, (sa_dir == INBOUND_SA ? &pr->spi : &pr->spi_p), + sizeof(pr->spi)); + p += sizeof(pr->spi); + + bp = (side == INITIATOR ? iph2->nonce : iph2->nonce_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (side == INITIATOR ? iph2->nonce_p : iph2->nonce); + memcpy(p, bp->v, bp->l); + p += bp->l; + + /* compute IV */ + plog(LLV_DEBUG, LOCATION, NULL, "KEYMAT compute with\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* res = K1 */ + res = oakley_prf(iph2->ph1->skeyid_d, buf, iph2->ph1); + if (res == NULL) + goto end; + + /* compute key length needed */ + encklen = authklen = 0; + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + for (tr = pr->head; tr; tr = tr->next) { + l = alg_ipsec_encdef_keylen(tr->trns_id, + tr->encklen); + if (l > encklen) + encklen = l; + + l = alg_ipsec_hmacdef_hashlen(tr->authtype); + if (l > authklen) + authklen = l; + } + break; + case IPSECDOI_PROTO_IPSEC_AH: + for (tr = pr->head; tr; tr = tr->next) { + l = alg_ipsec_hmacdef_hashlen(tr->trns_id); + if (l > authklen) + authklen = l; + } + break; + default: + break; + } + plog(LLV_DEBUG, LOCATION, NULL, "encklen=%d authklen=%d\n", + encklen, authklen); + + dupkeymat = (encklen + authklen) / 8 / res->l; + dupkeymat += 2; /* safety mergin */ + if (dupkeymat < 3) + dupkeymat = 3; + plog(LLV_DEBUG, LOCATION, NULL, + "generating %d bits of key (dupkeymat=%d)\n", + dupkeymat * 8 * res->l, dupkeymat); + if (0 < --dupkeymat) { + vchar_t *prev = res; /* K(n-1) */ + vchar_t *seed = NULL; /* seed for Kn */ + size_t l; + + /* + * generating long key (isakmp-oakley-08 5.5) + * KEYMAT = K1 | K2 | K3 | ... + * where + * src = [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b + * K1 = prf(SKEYID_d, src) + * K2 = prf(SKEYID_d, K1 | src) + * K3 = prf(SKEYID_d, K2 | src) + * Kn = prf(SKEYID_d, K(n-1) | src) + */ + plog(LLV_DEBUG, LOCATION, NULL, + "generating K1...K%d for KEYMAT.\n", + dupkeymat + 1); + + seed = vmalloc(prev->l + buf->l); + if (seed == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get keymat buffer.\n"); + if (prev && prev != res) + vfree(prev); + goto end; + } + + while (dupkeymat--) { + vchar_t *this = NULL; /* Kn */ + + memcpy(seed->v, prev->v, prev->l); + memcpy(seed->v + prev->l, buf->v, buf->l); + this = oakley_prf(iph2->ph1->skeyid_d, seed, + iph2->ph1); + if (!this) { + plog(LLV_ERROR, LOCATION, NULL, + "oakley_prf memory overflow\n"); + if (prev && prev != res) + vfree(prev); + vfree(this); + vfree(seed); + goto end; + } + + l = res->l; + res = vrealloc(res, l + this->l); + if (res == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get keymat buffer.\n"); + if (prev && prev != res) + vfree(prev); + vfree(this); + vfree(seed); + goto end; + } + memcpy(res->v + l, this->v, this->l); + + if (prev && prev != res) + vfree(prev); + prev = this; + this = NULL; + } + + if (prev && prev != res) + vfree(prev); + vfree(seed); + } + + plogdump(LLV_DEBUG, res->v, res->l); + + if (sa_dir == INBOUND_SA) + pr->keymat = res; + else + pr->keymat_p = res; + res = NULL; + } + + error = 0; + +end: + if (error) { + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + if (pr->keymat) { + vfree(pr->keymat); + pr->keymat = NULL; + } + if (pr->keymat_p) { + vfree(pr->keymat_p); + pr->keymat_p = NULL; + } + } + } + + if (buf != NULL) + vfree(buf); + if (res) + vfree(res); + + return error; +} + +#if notyet +/* + * NOTE: Must terminate by NULL. + */ +vchar_t * +oakley_compute_hashx(struct ph1handle *iph1, ...) +{ + vchar_t *buf, *res; + vchar_t *s; + caddr_t p; + int len; + + va_list ap; + + /* get buffer length */ + va_start(ap, iph1); + len = 0; + while ((s = va_arg(ap, vchar_t *)) != NULL) { + len += s->l + } + va_end(ap); + + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + return NULL; + } + + /* set buffer */ + va_start(ap, iph1); + p = buf->v; + while ((s = va_arg(ap, char *)) != NULL) { + memcpy(p, s->v, s->l); + p += s->l; + } + va_end(ap); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid_a, buf, iph1); + vfree(buf); + if (res == NULL) + return NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + + return res; +} +#endif + +/* + * compute HASH(3) prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) + * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. + */ +vchar_t * +oakley_compute_hash3(iph1, msgid, body) + struct ph1handle *iph1; + u_int32_t msgid; + vchar_t *body; +{ + vchar_t *buf = 0, *res = 0; + int len; + int error = -1; + + /* create buffer */ + len = 1 + sizeof(u_int32_t) + body->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + + buf->v[0] = 0; + + memcpy(buf->v + 1, (char *)&msgid, sizeof(msgid)); + + memcpy(buf->v + 1 + sizeof(u_int32_t), body->v, body->l); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with: \n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid_a, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); + return res; +} + +/* + * compute HASH type of prf(SKEYID_a, M-ID | buffer) + * e.g. + * for quick mode HASH(1): + * prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr ]) + * for quick mode HASH(2): + * prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | IDcr ]) + * for Informational exchange: + * prf(SKEYID_a, M-ID | N/D) + */ +vchar_t * +oakley_compute_hash1(iph1, msgid, body) + struct ph1handle *iph1; + u_int32_t msgid; + vchar_t *body; +{ + vchar_t *buf = NULL, *res = NULL; + char *p; + int len; + int error = -1; + + /* create buffer */ + len = sizeof(u_int32_t) + body->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + + p = buf->v; + + memcpy(buf->v, (char *)&msgid, sizeof(msgid)); + p += sizeof(u_int32_t); + + memcpy(p, body->v, body->l); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid_a, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); + return res; +} + +/* + * compute phase1 HASH + * main/aggressive + * I-digest = prf(SKEYID, g^i | g^r | CKY-I | CKY-R | SAi_b | ID_i1_b) + * R-digest = prf(SKEYID, g^r | g^i | CKY-R | CKY-I | SAi_b | ID_r1_b) + * for gssapi, also include all GSS tokens, and call gss_wrap on the result + */ +vchar_t * +oakley_ph1hash_common(iph1, sw) + struct ph1handle *iph1; + int sw; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + char *p, *bp2; + int len, bl; + int error = -1; +#ifdef HAVE_GSSAPI + vchar_t *gsstokens = NULL; +#endif + + /* create buffer */ + len = iph1->dhpub->l + + iph1->dhpub_p->l + + sizeof(cookie_t) * 2 + + iph1->sa->l + + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (iph1->gi_i != NULL && iph1->gi_r != NULL) { + bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r); + len += bp->l; + } + if (sw == GENERATE) + gssapi_get_itokens(iph1, &gsstokens); + else + gssapi_get_rtokens(iph1, &gsstokens); + if (gsstokens == NULL) + return NULL; + len += gsstokens->l; + } +#endif + + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + + p = buf->v; + + bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub); + memcpy(p, bp->v, bp->l); + p += bp->l; + + if (iph1->side == INITIATOR) + bp2 = (sw == GENERATE ? + (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck); + else + bp2 = (sw == GENERATE ? + (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck); + bl = sizeof(cookie_t); + memcpy(p, bp2, bl); + p += bl; + + if (iph1->side == INITIATOR) + bp2 = (sw == GENERATE ? + (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck); + else + bp2 = (sw == GENERATE ? + (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck); + bl = sizeof(cookie_t); + memcpy(p, bp2, bl); + p += bl; + + bp = iph1->sa; + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->id : iph1->id_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + +#ifdef HAVE_GSSAPI + if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB) { + if (iph1->gi_i != NULL && iph1->gi_r != NULL) { + bp = (sw == GENERATE ? iph1->gi_i : iph1->gi_r); + memcpy(p, bp->v, bp->l); + p += bp->l; + } + memcpy(p, gsstokens->v, gsstokens->l); + p += gsstokens->l; + } +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(iph1->skeyid, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); +#ifdef HAVE_GSSAPI + if (gsstokens != NULL) + vfree(gsstokens); +#endif + return res; +} + +/* + * compute HASH_I on base mode. + * base:psk,rsa + * HASH_I = prf(SKEYID, g^xi | CKY-I | CKY-R | SAi_b | IDii_b) + * base:sig + * HASH_I = prf(hash(Ni_b | Nr_b), g^xi | CKY-I | CKY-R | SAi_b | IDii_b) + */ +vchar_t * +oakley_ph1hash_base_i(iph1, sw) + struct ph1handle *iph1; + int sw; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + vchar_t *hashkey = NULL; + vchar_t *hash = NULL; /* for signature mode */ + char *p; + int len; + int error = -1; + + /* sanity check */ + if (iph1->etype != ISAKMP_ETYPE_BASE) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype for this hash function\n"); + return NULL; + } + + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + if (iph1->skeyid == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n"); + return NULL; + } + hashkey = iph1->skeyid; + break; + + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + /* make hash for seed */ + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + hash = oakley_hash(buf, iph1); + if (hash == NULL) + goto end; + vfree(buf); + buf = NULL; + + hashkey = hash; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "not supported authentication method %d\n", + iph1->approval->authmethod); + return NULL; + + } + + len = (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l) + + sizeof(cookie_t) * 2 + + iph1->sa->l + + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + memcpy(p, &iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, &iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + + memcpy(p, iph1->sa->v, iph1->sa->l); + p += iph1->sa->l; + + bp = (sw == GENERATE ? iph1->id : iph1->id_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH_I with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(hashkey, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH_I computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (hash != NULL) + vfree(hash); + if (buf != NULL) + vfree(buf); + return res; +} + +/* + * compute HASH_R on base mode for signature method. + * base: + * HASH_R = prf(hash(Ni_b | Nr_b), g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b) + */ +vchar_t * +oakley_ph1hash_base_r(iph1, sw) + struct ph1handle *iph1; + int sw; +{ + vchar_t *buf = NULL, *res = NULL, *bp; + vchar_t *hash = NULL; + char *p; + int len; + int error = -1; + + /* sanity check */ + if (iph1->etype != ISAKMP_ETYPE_BASE) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype for this hash function\n"); + return NULL; + } + if (iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_DSSSIG + && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG) { + plog(LLV_ERROR, LOCATION, NULL, + "not supported authentication method %d\n", + iph1->approval->authmethod); + return NULL; + } + + /* make hash for seed */ + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + hash = oakley_hash(buf, iph1); + if (hash == NULL) + goto end; + vfree(buf); + buf = NULL; + + /* make really hash */ + len = (sw == GENERATE ? iph1->dhpub_p->l : iph1->dhpub->l) + + (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l) + + sizeof(cookie_t) * 2 + + iph1->sa->l + + (sw == GENERATE ? iph1->id_p->l : iph1->id->l); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get hash buffer\n"); + goto end; + } + p = buf->v; + + + bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + memcpy(p, &iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, &iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + + memcpy(p, iph1->sa->v, iph1->sa->l); + p += iph1->sa->l; + + bp = (sw == GENERATE ? iph1->id_p : iph1->id); + memcpy(p, bp->v, bp->l); + p += bp->l; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH with:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* compute HASH */ + res = oakley_prf(hash, buf, iph1); + if (res == NULL) + goto end; + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "HASH computed:\n"); + plogdump(LLV_DEBUG, res->v, res->l); + +end: + if (buf != NULL) + vfree(buf); + if (hash) + vfree(hash); + return res; +} + +/* + * compute each authentication method in phase 1. + * OUT: + * 0: OK + * -1: error + * other: error to be reply with notification. + * the value is notification type. + */ +int +oakley_validate_auth(iph1) + struct ph1handle *iph1; +{ + vchar_t *my_hash = NULL; + int result; +#ifdef HAVE_GSSAPI + vchar_t *gsshash = NULL; +#endif +#ifdef ENABLE_STATS + struct timeval start, end; +#endif + +#ifdef ENABLE_STATS + gettimeofday(&start, NULL); +#endif + switch (iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + /* validate HASH */ + { + char *r_hash; + + if (iph1->id_p == NULL || iph1->pl_hash == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + + r_hash = (caddr_t)(iph1->pl_hash + 1); + + plog(LLV_DEBUG, LOCATION, NULL, "HASH received:"); + plogdump(LLV_DEBUG, r_hash, + ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash)); + + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + break; + case ISAKMP_ETYPE_BASE: + if (iph1->side == INITIATOR) + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + else + my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + if (my_hash == NULL) + return ISAKMP_INTERNAL_ERROR; + + result = memcmp(my_hash->v, r_hash, my_hash->l); + vfree(my_hash); + + if (result) { + plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n"); + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + + plog(LLV_DEBUG, LOCATION, NULL, "HASH for PSK validated.\n"); + } + break; +#ifdef HAVE_SIGNING_C + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + { + int error = 0; + + /* validation */ + if (iph1->id_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "no ID payload was passed.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + if (iph1->sig_p == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "no SIG payload was passed.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + + plog(LLV_DEBUG, LOCATION, NULL, "SIGN passed:\n"); + plogdump(LLV_DEBUG, iph1->sig_p->v, iph1->sig_p->l); + + /* get peer's cert */ + switch (iph1->rmconf->getcert_method) { + case ISAKMP_GETCERT_PAYLOAD: + if (iph1->cert_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no peer's CERT payload found.\n"); + return ISAKMP_INTERNAL_ERROR; + } + break; + case ISAKMP_GETCERT_LOCALFILE: + if (iph1->rmconf->peerscertfile == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no peer's CERT file found.\n"); + return ISAKMP_INTERNAL_ERROR; + } + + /* don't use cached cert */ + if (iph1->cert_p != NULL) { + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + } + + error = get_cert_fromlocal(iph1, 0); + if (error) + return ISAKMP_INTERNAL_ERROR; + break; + case ISAKMP_GETCERT_DNS: + if (iph1->rmconf->peerscertfile != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "why peer's CERT file is defined " + "though getcert method is dns ?\n"); + return ISAKMP_INTERNAL_ERROR; + } + + /* don't use cached cert */ + if (iph1->cert_p != NULL) { + oakley_delcert(iph1->cert_p); + iph1->cert_p = NULL; + } + + iph1->cert_p = dnssec_getcert(iph1->id_p); + if (iph1->cert_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no CERT RR found.\n"); + return ISAKMP_INTERNAL_ERROR; + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid getcert_mothod: %d\n", + iph1->rmconf->getcert_method); + return ISAKMP_INTERNAL_ERROR; + } + + /* compare ID payload and certificate name */ + if (iph1->rmconf->verify_cert && + (error = oakley_check_certid(iph1)) != 0) + return error; + + /* verify certificate */ + if (iph1->rmconf->verify_cert + && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) { + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: + error = eay_check_x509cert(&iph1->cert_p->cert, + lcconf->pathinfo[LC_PATHTYPE_CERT]); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "no supported certtype %d\n", + iph1->rmconf->certtype); + return ISAKMP_INTERNAL_ERROR; + } + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid authority of the CERT.\n"); + return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY; + } + } + + plog(LLV_DEBUG, LOCATION, NULL, "CERT validated\n"); + + /* compute hash */ + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + break; + case ISAKMP_ETYPE_BASE: + if (iph1->side == INITIATOR) + my_hash = oakley_ph1hash_base_r(iph1, VALIDATE); + else + my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + if (my_hash == NULL) + return ISAKMP_INTERNAL_ERROR; + + /* check signature */ + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_DNS: + error = eay_check_x509sign(my_hash, + iph1->sig_p, + &iph1->cert_p->cert); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "no supported certtype %d\n", + iph1->rmconf->certtype); + vfree(my_hash); + return ISAKMP_INTERNAL_ERROR; + } + + vfree(my_hash); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid SIG.\n"); + return ISAKMP_NTYPE_INVALID_SIGNATURE; + } + plog(LLV_DEBUG, LOCATION, NULL, "SIG authenticated\n"); + } + break; +#endif +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: + switch (iph1->etype) { + case ISAKMP_ETYPE_IDENT: + case ISAKMP_ETYPE_AGG: + my_hash = oakley_ph1hash_common(iph1, VALIDATE); + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid etype %d\n", iph1->etype); + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + } + + if (my_hash == NULL) { + if (gssapi_more_tokens(iph1)) + return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; + else + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + + gsshash = gssapi_unwraphash(iph1); + if (gsshash == NULL) { + vfree(my_hash); + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + + result = memcmp(my_hash->v, gsshash->v, my_hash->l); + vfree(my_hash); + vfree(gsshash); + + if (result) { + plog(LLV_ERROR, LOCATION, NULL, "HASH mismatched\n"); + return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; + } + plog(LLV_DEBUG, LOCATION, NULL, "hash compared OK\n"); + break; +#endif + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + if (iph1->id_p == NULL || iph1->pl_hash == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "few isakmp message received.\n"); + return ISAKMP_NTYPE_PAYLOAD_MALFORMED; + } + plog(LLV_ERROR, LOCATION, iph1->remote, + "not supported authmethod type %s\n", + s_oakley_attr_method(iph1->approval->authmethod)); + return ISAKMP_INTERNAL_ERROR; + default: + plog(LLV_ERROR, LOCATION, iph1->remote, + "invalid authmethod %d why ?\n", + iph1->approval->authmethod); + return ISAKMP_INTERNAL_ERROR; + } +#ifdef ENABLE_STATS + gettimeofday(&end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", __FUNCTION__, + s_oakley_attr_method(iph1->approval->authmethod), + timedelta(&start, &end)); +#endif + + return 0; +} + +#ifdef HAVE_SIGNING_C +/* get my certificate + * NOTE: include certificate type. + */ +int +oakley_getmycert(iph1) + struct ph1handle *iph1; +{ + if (iph1->cert) + return 0; /* There is CERT. */ + + return get_cert_fromlocal(iph1, 1); +} + +/* + * get a CERT from local file. + * IN: + * my != 0 my cert. + * my == 0 peer's cert. + */ +static int +get_cert_fromlocal(iph1, my) + struct ph1handle *iph1; + int my; +{ + char path[MAXPATHLEN]; + vchar_t *cert = NULL; + cert_t **certpl; + char *certfile; + int error = -1; + + if (my) { + certfile = iph1->rmconf->mycertfile; + certpl = &iph1->cert; + } else { + certfile = iph1->rmconf->peerscertfile; + certpl = &iph1->cert_p; + } + if (!certfile) { + plog(LLV_ERROR, LOCATION, NULL, "no CERT defined.\n"); + return 0; + } + + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_DNS: + /* make public file name */ + getpathname(path, sizeof(path), LC_PATHTYPE_CERT, certfile); + cert = eay_get_x509cert(path); + if (cert) { + char *p = NULL; + p = eay_get_x509text(cert); + plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); + racoon_free(p); + }; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "not supported certtype %d\n", + iph1->rmconf->certtype); + goto end; + } + + if (!cert) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get %s CERT.\n", + my ? "my" : "peers"); + goto end; + } + + *certpl = oakley_newcert(); + if (!*certpl) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer.\n"); + goto end; + } + (*certpl)->pl = vmalloc(cert->l + 1); + if ((*certpl)->pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert buffer\n"); + oakley_delcert(*certpl); + *certpl = NULL; + goto end; + } + memcpy((*certpl)->pl->v + 1, cert->v, cert->l); + (*certpl)->pl->v[0] = iph1->rmconf->certtype; + (*certpl)->type = iph1->rmconf->certtype; + (*certpl)->cert.v = (*certpl)->pl->v + 1; + (*certpl)->cert.l = (*certpl)->pl->l - 1; + + plog(LLV_DEBUG, LOCATION, NULL, "created CERT payload:\n"); + plogdump(LLV_DEBUG, (*certpl)->pl->v, (*certpl)->pl->l); + + error = 0; + +end: + if (cert != NULL) + vfree(cert); + + return error; +} + +/* get signature */ +int +oakley_getsign(iph1) + struct ph1handle *iph1; +{ + char path[MAXPATHLEN]; + vchar_t *privkey = NULL; + int error = -1; + + switch (iph1->rmconf->certtype) { + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_DNS: + if (iph1->rmconf->myprivfile == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no cert defined.\n"); + goto end; + } + + /* make private file name */ + getpathname(path, sizeof(path), + LC_PATHTYPE_CERT, + iph1->rmconf->myprivfile); + privkey = eay_get_pkcs1privkey(path); + if (privkey == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get private key.\n"); + goto end; + } + plog(LLV_DEBUG2, LOCATION, NULL, "private key:\n"); + plogdump(LLV_DEBUG2, privkey->v, privkey->l); + + iph1->sig = eay_get_x509sign(iph1->hash, + privkey, &iph1->cert->cert); + break; + default: + goto end; + } + + if (iph1->sig == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "failed to sign.\n"); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "SIGN computed:\n"); + plogdump(LLV_DEBUG, iph1->sig->v, iph1->sig->l); + + error = 0; + +end: + if (privkey != NULL) + vfree(privkey); + + return error; +} + +/* + * compare certificate name and ID value. + */ +static int +oakley_check_certid(iph1) + struct ph1handle *iph1; +{ + struct ipsecdoi_id_b *id_b; + vchar_t *name = NULL; + char *altname = NULL; + int idlen, type; + int error; + + if (iph1->id_p == NULL || iph1->cert_p == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no ID nor CERT found.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + + id_b = (struct ipsecdoi_id_b *)iph1->id_p->v; + idlen = iph1->id_p->l - sizeof(*id_b); + + switch (id_b->type) { + case IPSECDOI_ID_DER_ASN1_DN: + name = eay_get_x509asn1subjectname(&iph1->cert_p->cert); + if (!name) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + if (idlen != name->l) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ID length in phase 1.\n"); + vfree(name); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + error = memcmp(id_b + 1, name->v, idlen); + vfree(name); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID mismatched with subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + return 0; + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV6_ADDR: + { + /* + * converting to binary from string because openssl return + * a string even if object is a binary. + * XXX fix it ! access by ASN.1 directly without. + */ + struct addrinfo hints, *res; + caddr_t a = NULL; + int pos; + + for (pos = 1; ; pos++) { + if (eay_get_x509subjectaltname(&iph1->cert_p->cert, + &altname, &type, pos) !=0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectAltName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + /* it's the end condition of the loop. */ + if (!altname) { + plog(LLV_ERROR, LOCATION, NULL, + "no proper subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + if (check_typeofcertname(id_b->type, type) == 0) + break; + + /* next name */ + racoon_free(altname); + altname = NULL; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_RAW; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(altname, NULL, &hints, &res); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "no proper subjectAltName.\n"); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + switch (res->ai_family) { + case AF_INET: + a = (caddr_t)&((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr; + break; +#ifdef INET6 + case AF_INET6: + a = (caddr_t)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "family not supported: %d.\n", res->ai_family); + racoon_free(altname); + freeaddrinfo(res); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + error = memcmp(id_b + 1, a, idlen); + freeaddrinfo(res); + vfree(name); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID mismatched with subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + return 0; + } + case IPSECDOI_ID_FQDN: + case IPSECDOI_ID_USER_FQDN: + { + int pos; + + for (pos = 1; ; pos++) { + if (eay_get_x509subjectaltname(&iph1->cert_p->cert, + &altname, &type, pos) != 0){ + plog(LLV_ERROR, LOCATION, NULL, + "failed to get subjectAltName\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + /* it's the end condition of the loop. */ + if (!altname) { + plog(LLV_ERROR, LOCATION, NULL, + "no proper subjectAltName.\n"); + return ISAKMP_NTYPE_INVALID_CERTIFICATE; + } + + if (check_typeofcertname(id_b->type, type) == 0) + break; + + /* next name */ + racoon_free(altname); + altname = NULL; + } + if (idlen != strlen(altname)) { + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ID length in phase 1.\n"); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + if (check_typeofcertname(id_b->type, type) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ID type mismatched. ID: %s CERT: %s.\n", + s_ipsecdoi_ident(id_b->type), + s_ipsecdoi_ident(type)); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + error = memcmp(id_b + 1, altname, idlen); + if (error) { + plog(LLV_ERROR, LOCATION, NULL, "ID mismatched.\n"); + racoon_free(altname); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + racoon_free(altname); + return 0; + } + default: + plog(LLV_ERROR, LOCATION, NULL, + "Inpropper ID type passed: %s.\n", + s_ipsecdoi_ident(id_b->type)); + return ISAKMP_NTYPE_INVALID_ID_INFORMATION; + } + /*NOTREACHED*/ +} + +static int +check_typeofcertname(doi, genid) + int doi, genid; +{ + switch (doi) { + case IPSECDOI_ID_IPV4_ADDR: + case IPSECDOI_ID_IPV4_ADDR_SUBNET: + case IPSECDOI_ID_IPV6_ADDR: + case IPSECDOI_ID_IPV6_ADDR_SUBNET: + case IPSECDOI_ID_IPV4_ADDR_RANGE: + case IPSECDOI_ID_IPV6_ADDR_RANGE: + if (genid != GENT_IPADD) + return -1; + return 0; + case IPSECDOI_ID_FQDN: + if (genid != GENT_DNS) + return -1; + return 0; + case IPSECDOI_ID_USER_FQDN: + if (genid != GENT_EMAIL) + return -1; + return 0; + case IPSECDOI_ID_DER_ASN1_DN: /* should not be passed to this function*/ + case IPSECDOI_ID_DER_ASN1_GN: + case IPSECDOI_ID_KEY_ID: + default: + return -1; + } + /*NOTREACHED*/ +} + +/* + * save certificate including certificate type. + */ +int +oakley_savecert(iph1, gen) + struct ph1handle *iph1; + struct isakmp_gen *gen; +{ + cert_t **c; + u_int8_t type; + + type = *(u_int8_t *)(gen + 1) & 0xff; + + switch (type) { + case ISAKMP_CERT_DNS: + plog(LLV_WARNING, LOCATION, NULL, + "CERT payload is unnecessary in DNSSEC. " + "ignore this CERT payload.\n"); + return 0; + case ISAKMP_CERT_PKCS7: + case ISAKMP_CERT_PGP: + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_KERBEROS: + case ISAKMP_CERT_SPKI: + c = &iph1->cert_p; + break; + case ISAKMP_CERT_CRL: + c = &iph1->crl_p; + break; + case ISAKMP_CERT_X509KE: + case ISAKMP_CERT_X509ATTR: + case ISAKMP_CERT_ARL: + plog(LLV_ERROR, LOCATION, NULL, + "No supported such CERT type %d\n", type); + return -1; + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid CERT type %d\n", type); + return -1; + } + + /* XXX choice the 1th cert, ignore after the cert. */ + /* XXX should be processed. */ + if (*c) { + plog(LLV_WARNING, LOCATION, NULL, + "ignore 2nd CERT payload.\n"); + return 0; + } + + *c = save_certbuf(gen); + if (!*c) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CERT buffer.\n"); + return -1; + } + + switch ((*c)->type) { + case ISAKMP_CERT_DNS: + plog(LLV_WARNING, LOCATION, NULL, + "CERT payload is unnecessary in DNSSEC. " + "ignore it.\n"); + return 0; + case ISAKMP_CERT_PKCS7: + case ISAKMP_CERT_PGP: + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_KERBEROS: + case ISAKMP_CERT_SPKI: + plog(LLV_DEBUG, LOCATION, NULL, "CERT saved:\n"); + plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + { + char *p = eay_get_x509text(&(*c)->cert); + plog(LLV_DEBUG, LOCATION, NULL, "%s", p ? p : "\n"); + racoon_free(p); + } + break; + case ISAKMP_CERT_CRL: + plog(LLV_DEBUG, LOCATION, NULL, "CRL saved:\n"); + plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + break; + case ISAKMP_CERT_X509KE: + case ISAKMP_CERT_X509ATTR: + case ISAKMP_CERT_ARL: + default: + /* XXX */ + oakley_delcert((*c)); + *c = NULL; + return 0; + } + + return 0; +} + +/* + * save certificate including certificate type. + */ +int +oakley_savecr(iph1, gen) + struct ph1handle *iph1; + struct isakmp_gen *gen; +{ + cert_t **c; + u_int8_t type; + + type = *(u_int8_t *)(gen + 1) & 0xff; + + switch (type) { + case ISAKMP_CERT_DNS: + plog(LLV_WARNING, LOCATION, NULL, + "CERT payload is unnecessary in DNSSEC\n"); + /*FALLTHRU*/ + case ISAKMP_CERT_PKCS7: + case ISAKMP_CERT_PGP: + case ISAKMP_CERT_X509SIGN: + case ISAKMP_CERT_KERBEROS: + case ISAKMP_CERT_SPKI: + c = &iph1->cr_p; + break; + case ISAKMP_CERT_X509KE: + case ISAKMP_CERT_X509ATTR: + case ISAKMP_CERT_ARL: + plog(LLV_ERROR, LOCATION, NULL, + "No supported such CR type %d\n", type); + return -1; + case ISAKMP_CERT_CRL: + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid CR type %d\n", type); + return -1; + } + + *c = save_certbuf(gen); + if (!*c) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CR buffer.\n"); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, "CR saved:\n"); + plogdump(LLV_DEBUG, (*c)->cert.v, (*c)->cert.l); + + return 0; +} + +static cert_t * +save_certbuf(gen) + struct isakmp_gen *gen; +{ + cert_t *new; + + new = oakley_newcert(); + if (!new) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to get CERT buffer.\n"); + return NULL; + } + + new->pl = vmalloc(ntohs(gen->len) - sizeof(*gen)); + if (new->pl == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "Failed to copy CERT from packet.\n"); + oakley_delcert(new); + new = NULL; + return NULL; + } + memcpy(new->pl->v, gen + 1, new->pl->l); + new->type = new->pl->v[0] & 0xff; + new->cert.v = new->pl->v + 1; + new->cert.l = new->pl->l - 1; + + return new; +} + +/* + * get my CR. + * NOTE: No Certificate Authority field is included to CR payload at the + * moment. Becuase any certificate authority are accepted without any check. + * The section 3.10 in RFC2408 says that this field SHOULD not be included, + * if there is no specific certificate authority requested. + */ +vchar_t * +oakley_getcr(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf; + + buf = vmalloc(1); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cr buffer\n"); + return NULL; + } + buf->v[0] = iph1->rmconf->certtype; + + plog(LLV_DEBUG, LOCATION, NULL, "create my CR: %s\n", + s_isakmp_certtype(iph1->rmconf->certtype)); + if (buf->l > 1) + plogdump(LLV_DEBUG, buf->v, buf->l); + + return buf; +} + +/* + * check peer's CR. + */ +int +oakley_checkcr(iph1) + struct ph1handle *iph1; +{ + if (iph1->cr_p == NULL) + return 0; + + plog(LLV_DEBUG, LOCATION, iph1->remote, + "peer transmitted CR: %s\n", + s_isakmp_certtype(iph1->cr_p->type)); + + if (iph1->cr_p->type != iph1->rmconf->certtype) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "such a cert type isn't supported: %d\n", + (char)iph1->cr_p->type); + return -1; + } + + return 0; +} + +/* + * check to need CR payload. + */ +int +oakley_needcr(type) + int type; +{ + switch (type) { + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: + return 1; + default: + return 0; + } + /*NOTREACHED*/ +} +#endif /*HAVE_SIGNING_C*/ + +/* + * compute SKEYID + * see seciton 5. Exchanges in RFC 2409 + * psk: SKEYID = prf(pre-shared-key, Ni_b | Nr_b) + * sig: SKEYID = prf(Ni_b | Nr_b, g^ir) + * enc: SKEYID = prf(H(Ni_b | Nr_b), CKY-I | CKY-R) + */ +int +oakley_skeyid(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL, *bp; + char *p; + int len; + int error = -1; + + /* SKEYID */ + switch(iph1->approval->authmethod) { + case OAKLEY_ATTR_AUTH_METHOD_PSKEY: + if (iph1->etype != ISAKMP_ETYPE_IDENT) { + iph1->authstr = getpskbyname(iph1->id_p); + if (iph1->authstr == NULL) { + if (iph1->rmconf->verify_identifier) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "couldn't find the pskey.\n"); + goto end; + } + plog(LLV_NOTIFY, LOCATION, iph1->remote, + "couldn't find the proper pskey, " + "try to get one by the peer's address.\n"); + } + } + if (iph1->authstr == NULL) { + /* + * If the exchange type is the main mode or if it's + * failed to get the psk by ID, racoon try to get + * the psk by remote IP address. + * It may be nonsense. + */ + iph1->authstr = getpskbyaddr(iph1->remote); + if (iph1->authstr == NULL) { + plog(LLV_ERROR, LOCATION, iph1->remote, + "couldn't find the pskey for %s.\n", + saddrwop2str(iph1->remote)); + goto end; + } + } + plog(LLV_DEBUG, LOCATION, NULL, "the psk found.\n"); + /* should be secret PSK */ + plog(LLV_DEBUG2, LOCATION, NULL, "psk: "); + plogdump(LLV_DEBUG2, iph1->authstr->v, iph1->authstr->l); + + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); + plog(LLV_DEBUG, LOCATION, NULL, "nonce 1: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); + plog(LLV_DEBUG, LOCATION, NULL, "nonce 2: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + iph1->skeyid = oakley_prf(iph1->authstr, buf, iph1); + if (iph1->skeyid == NULL) + goto end; + break; + + case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: + case OAKLEY_ATTR_AUTH_METHOD_RSASIG: +#ifdef HAVE_GSSAPI + case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: +#endif + len = iph1->nonce->l + iph1->nonce_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get nonce buffer\n"); + goto end; + } + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); + plog(LLV_DEBUG, LOCATION, NULL, "nonce1: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); + plog(LLV_DEBUG, LOCATION, NULL, "nonce2: "); + plogdump(LLV_DEBUG, bp->v, bp->l); + memcpy(p, bp->v, bp->l); + p += bp->l; + + iph1->skeyid = oakley_prf(buf, iph1->dhgxy, iph1); + if (iph1->skeyid == NULL) + goto end; + break; + case OAKLEY_ATTR_AUTH_METHOD_RSAENC: + case OAKLEY_ATTR_AUTH_METHOD_RSAREV: + plog(LLV_WARNING, LOCATION, NULL, + "not supported authentication method %s\n", + s_oakley_attr_method(iph1->approval->authmethod)); + goto end; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid authentication method %d\n", + iph1->approval->authmethod); + goto end; + } + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid->v, iph1->skeyid->l); + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + return error; +} + +/* + * compute SKEYID_[dae] + * see seciton 5. Exchanges in RFC 2409 + * SKEYID_d = prf(SKEYID, g^ir | CKY-I | CKY-R | 0) + * SKEYID_a = prf(SKEYID, SKEYID_d | g^ir | CKY-I | CKY-R | 1) + * SKEYID_e = prf(SKEYID, SKEYID_a | g^ir | CKY-I | CKY-R | 2) + */ +int +oakley_skeyid_dae(iph1) + struct ph1handle *iph1; +{ + vchar_t *buf = NULL; + char *p; + int len; + int error = -1; + + if (iph1->skeyid == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no SKEYID found.\n"); + goto end; + } + + /* SKEYID D */ + /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */ + len = iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + + memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); + p += iph1->dhgxy->l; + memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + *p = 0; + iph1->skeyid_d = oakley_prf(iph1->skeyid, buf, iph1); + if (iph1->skeyid_d == NULL) + goto end; + + vfree(buf); + buf = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_d computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid_d->v, iph1->skeyid->l); + + /* SKEYID A */ + /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ + len = iph1->skeyid_d->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + memcpy(p, iph1->skeyid_d->v, iph1->skeyid_d->l); + p += iph1->skeyid_d->l; + memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); + p += iph1->dhgxy->l; + memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + *p = 1; + iph1->skeyid_a = oakley_prf(iph1->skeyid, buf, iph1); + if (iph1->skeyid_a == NULL) + goto end; + + vfree(buf); + buf = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_a computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid_a->v, iph1->skeyid_a->l); + + /* SKEYID E */ + /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */ + len = iph1->skeyid_a->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get skeyid buffer\n"); + goto end; + } + p = buf->v; + memcpy(p, iph1->skeyid_a->v, iph1->skeyid_a->l); + p += iph1->skeyid_a->l; + memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); + p += iph1->dhgxy->l; + memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); + p += sizeof(cookie_t); + *p = 2; + iph1->skeyid_e = oakley_prf(iph1->skeyid, buf, iph1); + if (iph1->skeyid_e == NULL) + goto end; + + vfree(buf); + buf = NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "SKEYID_e computed:\n"); + plogdump(LLV_DEBUG, iph1->skeyid_e->v, iph1->skeyid_e->l); + + error = 0; + +end: + if (buf != NULL) + vfree(buf); + return error; +} + +/* + * compute final encryption key. + * see Appendix B. + */ +int +oakley_compute_enckey(iph1) + struct ph1handle *iph1; +{ + u_int keylen, prflen; + int error = -1; + + /* RFC2409 p39 */ + keylen = alg_oakley_encdef_keylen(iph1->approval->enctype, + iph1->approval->encklen); + if (keylen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoritym %d, " + "or invalid key length %d.\n", + iph1->approval->enctype, + iph1->approval->encklen); + goto end; + } + iph1->key = vmalloc(keylen >> 3); + if (iph1->key == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get key buffer\n"); + goto end; + } + + /* set prf length */ + prflen = alg_oakley_hashdef_hashlen(iph1->approval->hashtype); + if (prflen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hash type %d.\n", iph1->approval->hashtype); + goto end; + } + + /* see isakmp-oakley-08 5.3. */ + if (iph1->key->l <= iph1->skeyid_e->l) { + /* + * if length(Ka) <= length(SKEYID_e) + * Ka = first length(K) bit of SKEYID_e + */ + memcpy(iph1->key->v, iph1->skeyid_e->v, iph1->key->l); + } else { + vchar_t *buf = NULL, *res = NULL; + u_char *p, *ep; + int cplen; + int subkey; + + /* + * otherwise, + * Ka = K1 | K2 | K3 + * where + * K1 = prf(SKEYID_e, 0) + * K2 = prf(SKEYID_e, K1) + * K3 = prf(SKEYID_e, K2) + */ + plog(LLV_DEBUG, LOCATION, NULL, + "len(SKEYID_e) < len(Ka) (%d < %d), " + "generating long key (Ka = K1 | K2 | ...)\n", + iph1->skeyid_e->l, iph1->key->l); + + if ((buf = vmalloc(prflen >> 3)) == 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get key buffer\n"); + goto end; + } + p = (u_char *)iph1->key->v; + ep = p + iph1->key->l; + + subkey = 1; + while (p < ep) { + if (p == (u_char *)iph1->key->v) { + /* just for computing K1 */ + buf->v[0] = 0; + buf->l = 1; + } + res = oakley_prf(iph1->skeyid_e, buf, iph1); + if (res == NULL) { + vfree(buf); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, + "compute intermediate encryption key K%d\n", + subkey); + plogdump(LLV_DEBUG, buf->v, buf->l); + plogdump(LLV_DEBUG, res->v, res->l); + + cplen = (res->l < ep - p) ? res->l : ep - p; + memcpy(p, res->v, cplen); + p += cplen; + + buf->l = prflen >> 3; /* to cancel K1 speciality */ + if (res->l != buf->l) { + plog(LLV_ERROR, LOCATION, NULL, + "internal error: res->l=%d buf->l=%d\n", + res->l, buf->l); + vfree(res); + vfree(buf); + goto end; + } + memcpy(buf->v, res->v, res->l); + vfree(res); + subkey++; + } + + vfree(buf); + } + + /* + * don't check any weak key or not. + * draft-ietf-ipsec-ike-01.txt Appendix B. + * draft-ietf-ipsec-ciph-aes-cbc-00.txt Section 2.3. + */ +#if 0 + /* weakkey check */ + if (iph1->approval->enctype > ARRAYLEN(oakley_encdef) + || oakley_encdef[iph1->approval->enctype].weakkey == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "encryption algoritym %d isn't supported.\n", + iph1->approval->enctype); + goto end; + } + if ((oakley_encdef[iph1->approval->enctype].weakkey)(iph1->key)) { + plog(LLV_ERROR, LOCATION, NULL, + "weakkey was generated.\n"); + goto end; + } +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "final encryption key computed:\n"); + plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + + error = 0; + +end: + return error; +} + +/* allocated new buffer for CERT */ +cert_t * +oakley_newcert() +{ + cert_t *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get cert's buffer\n"); + return NULL; + } + + new->pl = NULL; + + return new; +} + +/* delete buffer for CERT */ +void +oakley_delcert(cert) + cert_t *cert; +{ + if (!cert) + return; + if (cert->pl) + VPTRINIT(cert->pl); + racoon_free(cert); +} + +/* + * compute IV and set to ph1handle + * IV = hash(g^xi | g^xr) + * see 4.1 Phase 1 state in draft-ietf-ipsec-ike. + */ +int +oakley_newiv(iph1) + struct ph1handle *iph1; +{ + struct isakmp_ivm *newivm = NULL; + vchar_t *buf = NULL, *bp; + char *p; + int len; + + /* create buffer */ + len = iph1->dhpub->l + iph1->dhpub_p->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + return -1; + } + + p = buf->v; + + bp = (iph1->side == INITIATOR ? iph1->dhpub : iph1->dhpub_p); + memcpy(p, bp->v, bp->l); + p += bp->l; + + bp = (iph1->side == INITIATOR ? iph1->dhpub_p : iph1->dhpub); + memcpy(p, bp->v, bp->l); + p += bp->l; + + /* allocate IVm */ + newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); + if (newivm == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + vfree(buf); + return -1; + } + + /* compute IV */ + newivm->iv = oakley_hash(buf, iph1); + if (newivm->iv == NULL) { + vfree(buf); + oakley_delivm(newivm); + return -1; + } + + /* adjust length of iv */ + newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (newivm->iv->l == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + vfree(buf); + oakley_delivm(newivm); + return -1; + } + + /* create buffer to save iv */ + if ((newivm->ive = vdup(newivm->iv)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "vdup (%s)\n", strerror(errno)); + vfree(buf); + oakley_delivm(newivm); + return -1; + } + + vfree(buf); + + plog(LLV_DEBUG, LOCATION, NULL, "IV computed:\n"); + plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l); + + iph1->ivm = newivm; + + return 0; +} + +/* + * compute IV for the payload after phase 1. + * It's not limited for phase 2. + * if pahse 1 was encrypted. + * IV = hash(last CBC block of Phase 1 | M-ID) + * if phase 1 was not encrypted. + * IV = hash(phase 1 IV | M-ID) + * see 4.2 Phase 2 state in draft-ietf-ipsec-ike. + */ +struct isakmp_ivm * +oakley_newiv2(iph1, msgid) + struct ph1handle *iph1; + u_int32_t msgid; +{ + struct isakmp_ivm *newivm = NULL; + vchar_t *buf = NULL; + char *p; + int len; + int error = -1; + + /* create buffer */ + len = iph1->ivm->iv->l + sizeof(msgid_t); + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + goto end; + } + + p = buf->v; + + memcpy(p, iph1->ivm->iv->v, iph1->ivm->iv->l); + p += iph1->ivm->iv->l; + + memcpy(p, &msgid, sizeof(msgid)); + + plog(LLV_DEBUG, LOCATION, NULL, "compute IV for phase2\n"); + plog(LLV_DEBUG, LOCATION, NULL, "phase1 last IV:\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* allocate IVm */ + newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); + if (newivm == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get iv buffer\n"); + goto end; + } + + /* compute IV */ + if ((newivm->iv = oakley_hash(buf, iph1)) == NULL) + goto end; + + /* adjust length of iv */ + newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (newivm->iv->l == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + goto end; + } + + /* create buffer to save new iv */ + if ((newivm->ive = vdup(newivm->iv)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "vdup (%s)\n", strerror(errno)); + goto end; + } + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "phase2 IV computed:\n"); + plogdump(LLV_DEBUG, newivm->iv->v, newivm->iv->l); + +end: + if (error && newivm != NULL) + oakley_delivm(newivm); + if (buf != NULL) + vfree(buf); + return newivm; +} + +void +oakley_delivm(ivm) + struct isakmp_ivm *ivm; +{ + if (ivm == NULL) + return; + + if (ivm->iv != NULL) + vfree(ivm->iv); + if (ivm->ive != NULL) + vfree(ivm->ive); + racoon_free(ivm); + + return; +} + +/* + * decrypt packet. + * save new iv and old iv. + */ +vchar_t * +oakley_do_decrypt(iph1, msg, ivdp, ivep) + struct ph1handle *iph1; + vchar_t *msg, *ivdp, *ivep; +{ + vchar_t *buf = NULL, *new = NULL; + char *pl; + int len; + u_int8_t padlen; + int blen; + int error = -1; + + plog(LLV_DEBUG, LOCATION, NULL, "begin decryption.\n"); + + blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (blen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + goto end; + } + + /* save IV for next, but not sync. */ + memset(ivep->v, 0, ivep->l); + memcpy(ivep->v, (caddr_t)&msg->v[msg->l - blen], blen); + + plog(LLV_DEBUG, LOCATION, NULL, + "IV was saved for next processing:\n"); + plogdump(LLV_DEBUG, ivep->v, ivep->l); + + pl = msg->v + sizeof(struct isakmp); + + len = msg->l - sizeof(struct isakmp); + + /* create buffer */ + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to decrypt.\n"); + goto end; + } + memcpy(buf->v, pl, len); + + /* do decrypt */ + new = alg_oakley_encdef_decrypt(iph1->approval->enctype, + buf, iph1->key, ivdp); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "decryption %d failed.\n", iph1->approval->enctype); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "with key:\n"); + plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + + vfree(buf); + buf = NULL; + if (new == NULL) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "decrypted payload by IV:\n"); + plogdump(LLV_DEBUG, ivdp->v, ivdp->l); + + plog(LLV_DEBUG, LOCATION, NULL, + "decrypted payload, but not trimed.\n"); + plogdump(LLV_DEBUG, new->v, new->l); + + /* get padding length */ + if (lcconf->pad_excltail) + padlen = new->v[new->l - 1] + 1; + else + padlen = new->v[new->l - 1]; + plog(LLV_DEBUG, LOCATION, NULL, "padding len=%u\n", padlen); + + /* trim padding */ + if (lcconf->pad_strict) { + if (padlen > new->l) { + plog(LLV_ERROR, LOCATION, NULL, + "invalied padding len=%u, buflen=%u.\n", + padlen, new->l); + plogdump(LLV_ERROR, new->v, new->l); + goto end; + } + new->l -= padlen; + plog(LLV_DEBUG, LOCATION, NULL, "trimmed padding\n"); + } else { + plog(LLV_DEBUG, LOCATION, NULL, "skip to trim padding.\n"); + } + + /* create new buffer */ + len = sizeof(struct isakmp) + new->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to decrypt.\n"); + goto end; + } + memcpy(buf->v, msg->v, sizeof(struct isakmp)); + memcpy(buf->v + sizeof(struct isakmp), new->v, new->l); + ((struct isakmp *)buf->v)->len = htonl(buf->l); + + plog(LLV_DEBUG, LOCATION, NULL, "decrypted.\n"); + plogdump(LLV_DEBUG, buf->v, buf->l); + +#ifdef HAVE_PRINT_ISAKMP_C + isakmp_printpacket(buf, iph1->remote, iph1->local, 1); +#endif + + error = 0; + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + if (new != NULL) + vfree(new); + + return buf; +} + +/* + * encrypt packet. + */ +vchar_t * +oakley_do_encrypt(iph1, msg, ivep, ivp) + struct ph1handle *iph1; + vchar_t *msg, *ivep, *ivp; +{ + vchar_t *buf = 0, *new = 0; + char *pl; + int len; + u_int padlen; + int blen; + int error = -1; + + plog(LLV_DEBUG, LOCATION, NULL, "begin encryption.\n"); + + /* set cbc block length */ + blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); + if (blen == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algoriym %d.\n", + iph1->approval->enctype); + goto end; + } + + pl = msg->v + sizeof(struct isakmp); + len = msg->l - sizeof(struct isakmp); + + /* add padding */ + padlen = oakley_padlen(len, blen); + plog(LLV_DEBUG, LOCATION, NULL, "pad length = %u\n", padlen); + + /* create buffer */ + buf = vmalloc(len + padlen); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to encrypt.\n"); + goto end; + } + if (padlen) { + int i; + char *p = &buf->v[len]; + if (lcconf->pad_random) { + for (i = 0; i < padlen; i++) + *p++ = (char)random(); + } + } + memcpy(buf->v, pl, len); + + /* make pad into tail */ + if (lcconf->pad_excltail) + buf->v[len + padlen - 1] = padlen - 1; + else + buf->v[len + padlen - 1] = padlen; + + plogdump(LLV_DEBUG, buf->v, buf->l); + + /* do encrypt */ + new = alg_oakley_encdef_encrypt(iph1->approval->enctype, + buf, iph1->key, ivep); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "encryption %d failed.\n", iph1->approval->enctype); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "with key:\n"); + plogdump(LLV_DEBUG, iph1->key->v, iph1->key->l); + + vfree(buf); + buf = NULL; + if (new == NULL) + goto end; + + plog(LLV_DEBUG, LOCATION, NULL, "encrypted payload by IV:\n"); + plogdump(LLV_DEBUG, ivep->v, ivep->l); + + /* save IV for next */ + memset(ivp->v, 0, ivp->l); + memcpy(ivp->v, (caddr_t)&new->v[new->l - blen], blen); + + plog(LLV_DEBUG, LOCATION, NULL, "save IV for next:\n"); + plogdump(LLV_DEBUG, ivp->v, ivp->l); + + /* create new buffer */ + len = sizeof(struct isakmp) + new->l; + buf = vmalloc(len); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to encrypt.\n"); + goto end; + } + memcpy(buf->v, msg->v, sizeof(struct isakmp)); + memcpy(buf->v + sizeof(struct isakmp), new->v, new->l); + ((struct isakmp *)buf->v)->len = htonl(buf->l); + + error = 0; + + plog(LLV_DEBUG, LOCATION, NULL, "encrypted.\n"); + +end: + if (error && buf != NULL) { + vfree(buf); + buf = NULL; + } + if (new != NULL) + vfree(new); + + return buf; +} + +/* culculate padding length */ +static int +oakley_padlen(len, base) + int len, base; +{ + int padlen; + + padlen = base - len % base; + + if (lcconf->pad_randomlen) + padlen += ((random() % (lcconf->pad_maxsize + 1) + 1) * base); + + return padlen; +} + diff --git a/racoon.tproj/oakley.h b/racoon.tproj/oakley.h new file mode 100644 index 0000000..6d2a58e --- /dev/null +++ b/racoon.tproj/oakley.h @@ -0,0 +1,191 @@ +/* $KAME: oakley.h,v 1.27 2001/08/17 10:50:27 sakane 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. 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. + */ + +/* refer to RFC 2409 */ + +/* Attribute Classes */ +#define OAKLEY_ATTR_ENC_ALG 1 /* B */ +#define OAKLEY_ATTR_ENC_ALG_DES 1 +#define OAKLEY_ATTR_ENC_ALG_IDEA 2 +#define OAKLEY_ATTR_ENC_ALG_BLOWFISH 3 +#define OAKLEY_ATTR_ENC_ALG_RC5 4 +#define OAKLEY_ATTR_ENC_ALG_3DES 5 +#define OAKLEY_ATTR_ENC_ALG_CAST 6 +#define OAKLEY_ATTR_ENC_ALG_RIJNDAEL 7 +#define OAKLEY_ATTR_ENC_ALG_AES 7 + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_HASH_ALG 2 /* B */ +#define OAKLEY_ATTR_HASH_ALG_MD5 1 +#define OAKLEY_ATTR_HASH_ALG_SHA 2 +#define OAKLEY_ATTR_HASH_ALG_TIGER 3 +#define OAKLEY_ATTR_HASH_ALG_SHA2_256 4 +#define OAKLEY_ATTR_HASH_ALG_SHA2_384 5 +#define OAKLEY_ATTR_HASH_ALG_SHA2_512 6 + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_AUTH_METHOD 3 /* B */ +#define OAKLEY_ATTR_AUTH_METHOD_PSKEY 1 +#define OAKLEY_ATTR_AUTH_METHOD_DSSSIG 2 +#define OAKLEY_ATTR_AUTH_METHOD_RSASIG 3 +#define OAKLEY_ATTR_AUTH_METHOD_RSAENC 4 +#define OAKLEY_ATTR_AUTH_METHOD_RSAREV 5 +#define OAKLEY_ATTR_AUTH_METHOD_EGENC 6 +#define OAKLEY_ATTR_AUTH_METHOD_EGREV 7 + /* 65001 - 65535 Private Use */ + /* + * The following are valid when the Vendor ID is one of + * the following: + * + * MD5("A GSS-API Authentication Method for IKE") + * MD5("GSSAPI") (recognized by Windows 2000) + * MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000) + */ +#define OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB 65001 +#define OAKLEY_ATTR_GRP_DESC 4 /* B */ +#define OAKLEY_ATTR_GRP_DESC_MODP768 1 +#define OAKLEY_ATTR_GRP_DESC_MODP1024 2 +#define OAKLEY_ATTR_GRP_DESC_EC2N155 3 +#define OAKLEY_ATTR_GRP_DESC_EC2N185 4 +#define OAKLEY_ATTR_GRP_DESC_MODP1536 5 +#define OAKLEY_ATTR_GRP_DESC_MODP2048 42048 /* these value are */ +#define OAKLEY_ATTR_GRP_DESC_MODP3072 43072 /* make consensus */ +#define OAKLEY_ATTR_GRP_DESC_MODP4096 44096 /* at the bake off */ +#define OAKLEY_ATTR_GRP_DESC_MODP8192 48192 /* in helsinki */ +#define OAKLEY_ATTR_GRP_DESC_MODP6144 46144 /* XXX */ + /* 32768 - 65535 Private Use */ +#define OAKLEY_ATTR_GRP_TYPE 5 /* B */ +#define OAKLEY_ATTR_GRP_TYPE_MODP 1 +#define OAKLEY_ATTR_GRP_TYPE_ECP 2 +#define OAKLEY_ATTR_GRP_TYPE_EC2N 3 + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_GRP_PI 6 /* V */ +#define OAKLEY_ATTR_GRP_GEN_ONE 7 /* V */ +#define OAKLEY_ATTR_GRP_GEN_TWO 8 /* V */ +#define OAKLEY_ATTR_GRP_CURVE_A 9 /* V */ +#define OAKLEY_ATTR_GRP_CURVE_B 10 /* V */ +#define OAKLEY_ATTR_SA_LD_TYPE 11 /* B */ +#define OAKLEY_ATTR_SA_LD_TYPE_DEFAULT 1 +#define OAKLEY_ATTR_SA_LD_TYPE_SEC 1 +#define OAKLEY_ATTR_SA_LD_TYPE_KB 2 +#define OAKLEY_ATTR_SA_LD_TYPE_MAX 3 + /* 65001 - 65535 Private Use */ +#define OAKLEY_ATTR_SA_LD 12 /* V */ +#define OAKLEY_ATTR_SA_LD_SEC_DEFAULT 28800 /* 8 hours */ +#define OAKLEY_ATTR_PRF 13 /* B */ +#define OAKLEY_ATTR_KEY_LEN 14 /* B */ +#define OAKLEY_ATTR_FIELD_SIZE 15 /* B */ +#define OAKLEY_ATTR_GRP_ORDER 16 /* V */ +#define OAKLEY_ATTR_BLOCK_SIZE 17 /* B */ + /* 16384 - 32767 Private Use */ + + /* + * The following are valid when the Vendor ID is one of + * the following: + * + * MD5("A GSS-API Authentication Method for IKE") + * MD5("GSSAPI") (recognized by Windows 2000) + * MD5("MS NT5 ISAKMPOAKLEY") (sent by Windows 2000) + */ +#define OAKLEY_ATTR_GSS_ID 16384 + +#define MAXPADLWORD 20 + +struct dhgroup { + int type; + vchar_t *prime; + int gen1; + int gen2; + vchar_t *curve_a; + vchar_t *curve_b; + vchar_t *order; +}; + +/* certificate holder */ +typedef struct cert_t_tag { + u_int8_t type; /* type of CERT, must be same to pl->v[0]*/ + vchar_t cert; /* pointer to the CERT */ + vchar_t *pl; /* CERT payload minus isakmp general header */ +} cert_t; + +struct ph1handle; +struct ph2handle; +struct isakmp_ivm; + +extern int oakley_get_defaultlifetime __P((void)); + +extern int oakley_dhinit __P((void)); +extern void oakley_dhgrp_free __P((struct dhgroup *)); +extern int oakley_dh_compute __P((const struct dhgroup *, + vchar_t *, vchar_t *, vchar_t *, vchar_t **)); +extern int oakley_dh_generate __P((const struct dhgroup *, + vchar_t **, vchar_t **)); +extern int oakley_setdhgroup __P((int, struct dhgroup **)); + +extern vchar_t *oakley_prf __P((vchar_t *, vchar_t *, struct ph1handle *)); +extern vchar_t *oakley_hash __P((vchar_t *, struct ph1handle *)); + +extern int oakley_compute_keymat __P((struct ph2handle *, int)); + +#if notyet +extern vchar_t *oakley_compute_hashx __P((void)); +#endif +extern vchar_t *oakley_compute_hash3 __P((struct ph1handle *, + u_int32_t, vchar_t *)); +extern vchar_t *oakley_compute_hash1 __P((struct ph1handle *, + u_int32_t, vchar_t *)); +extern vchar_t *oakley_ph1hash_common __P((struct ph1handle *, int)); +extern vchar_t *oakley_ph1hash_base_i __P((struct ph1handle *, int)); +extern vchar_t *oakley_ph1hash_base_r __P((struct ph1handle *, int)); + +extern int oakley_validate_auth __P((struct ph1handle *)); +#ifdef HAVE_SIGNING_C +extern int oakley_getmycert __P((struct ph1handle *)); +extern int oakley_getsign __P((struct ph1handle *)); +extern vchar_t *oakley_getcr __P((struct ph1handle *)); +extern int oakley_checkcr __P((struct ph1handle *)); +#endif +extern int oakley_needcr __P((int)); +struct isakmp_gen; +extern int oakley_savecert __P((struct ph1handle *, struct isakmp_gen *)); +extern int oakley_savecr __P((struct ph1handle *, struct isakmp_gen *)); + +extern int oakley_skeyid __P((struct ph1handle *)); +extern int oakley_skeyid_dae __P((struct ph1handle *)); + +extern int oakley_compute_enckey __P((struct ph1handle *)); +extern cert_t *oakley_newcert __P((void)); +extern void oakley_delcert __P((cert_t *)); +extern int oakley_newiv __P((struct ph1handle *)); +extern struct isakmp_ivm *oakley_newiv2 __P((struct ph1handle *, u_int32_t)); +extern void oakley_delivm __P((struct isakmp_ivm *)); +extern vchar_t *oakley_do_decrypt __P((struct ph1handle *, + vchar_t *, vchar_t *, vchar_t *)); +extern vchar_t *oakley_do_encrypt __P((struct ph1handle *, + vchar_t *, vchar_t *, vchar_t *)); diff --git a/racoon.tproj/pfkey.c b/racoon.tproj/pfkey.c new file mode 100644 index 0000000..5403c6f --- /dev/null +++ b/racoon.tproj/pfkey.c @@ -0,0 +1,2546 @@ +/* $KAME: pfkey.c,v 1.132 2001/10/19 05:31:22 sakane 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. 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. + */ + +#define _PFKEY_C_ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#ifdef IPV6_INRIA_VERSION +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "libpfkey.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "schedule.h" +#include "localconf.h" +#include "remoteconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "isakmp_inf.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "pfkey.h" +#include "handler.h" +#include "policy.h" +#include "algorithm.h" +#include "sainfo.h" +#include "proposal.h" +#include "admin.h" +#include "strnames.h" +#include "backupsa.h" +#include "gcmalloc.h" + +/* prototype */ +static u_int ipsecdoi2pfkey_aalg __P((u_int)); +static u_int ipsecdoi2pfkey_ealg __P((u_int)); +static u_int ipsecdoi2pfkey_calg __P((u_int)); +static u_int ipsecdoi2pfkey_alg __P((u_int, u_int)); +static u_int keylen_aalg __P((u_int)); +static u_int keylen_ealg __P((u_int, int)); + +static int pk_recvgetspi __P((caddr_t *)); +static int pk_recvupdate __P((caddr_t *)); +static int pk_recvadd __P((caddr_t *)); +static int pk_recvdelete __P((caddr_t *)); +static int pk_recvacquire __P((caddr_t *)); +static int pk_recvexpire __P((caddr_t *)); +static int pk_recvflush __P((caddr_t *)); +static int getsadbpolicy __P((caddr_t *, int *, int, struct ph2handle *)); +static int pk_recvspdupdate __P((caddr_t *)); +static int pk_recvspdadd __P((caddr_t *)); +static int pk_recvspddelete __P((caddr_t *)); +static int pk_recvspdexpire __P((caddr_t *)); +static int pk_recvspdget __P((caddr_t *)); +static int pk_recvspddump __P((caddr_t *)); +static int pk_recvspdflush __P((caddr_t *)); +static struct sadb_msg *pk_recv __P((int, int *)); + +static int (*pkrecvf[]) __P((caddr_t *)) = { +NULL, +pk_recvgetspi, +pk_recvupdate, +pk_recvadd, +pk_recvdelete, +NULL, /* SADB_GET */ +pk_recvacquire, +NULL, /* SABD_REGISTER */ +pk_recvexpire, +pk_recvflush, +NULL, /* SADB_DUMP */ +NULL, /* SADB_X_PROMISC */ +NULL, /* SADB_X_PCHANGE */ +pk_recvspdupdate, +pk_recvspdadd, +pk_recvspddelete, +pk_recvspdget, +NULL, /* SADB_X_SPDACQUIRE */ +pk_recvspddump, +pk_recvspdflush, +NULL, /* SADB_X_SPDSETIDX */ +pk_recvspdexpire, +NULL, /* SADB_X_SPDDELETE2 */ +}; + +static int addnewsp __P((caddr_t *)); + +/* cope with old kame headers - ugly */ +#ifndef SADB_X_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#endif +#ifndef SADB_X_AALG_SHA +#define SADB_X_AALG_SHA SADB_AALG_SHA +#endif +#ifndef SADB_X_AALG_NULL +#define SADB_X_AALG_NULL SADB_AALG_NULL +#endif + +#ifndef SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC +#endif +#ifndef SADB_X_EALG_CAST128CBC +#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC +#endif +#ifndef SADB_X_EALG_RC5CBC +#ifdef SADB_EALG_RC5CBC +#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC +#endif +#endif + +/* + * PF_KEY packet handler + * 0: success + * -1: fail + */ +int +pfkey_handler() +{ + struct sadb_msg *msg; + int len; + caddr_t mhp[SADB_EXT_MAX + 1]; + int error = -1; + + /* receive pfkey message. */ + len = 0; + msg = (struct sadb_msg *)pk_recv(lcconf->sock_pfkey, &len); + if (msg == NULL) { + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to recv from pfkey (%s)\n", + strerror(errno)); + goto end; + } else { + /* short message - msg not ready */ + return 0; + } + } + + plog(LLV_DEBUG, LOCATION, NULL, "get pfkey %s message\n", + s_pfkey_type(msg->sadb_msg_type)); + plogdump(LLV_DEBUG2, msg, msg->sadb_msg_len << 3); + + /* validity check */ + if (msg->sadb_msg_errno) { + int pri; + + /* when SPD is empty, treat the state as no error. */ + if (msg->sadb_msg_type == SADB_X_SPDDUMP && + msg->sadb_msg_errno == ENOENT) + pri = LLV_DEBUG; + else + pri = LLV_ERROR; + + plog(pri, LOCATION, NULL, + "pfkey %s failed: %s\n", + s_pfkey_type(msg->sadb_msg_type), + strerror(msg->sadb_msg_errno)); + + goto end; + } + + /* check pfkey message. */ + if (pfkey_align(msg, mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey align (%s)\n", + ipsec_strerror()); + goto end; + } + if (pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey check (%s)\n", + ipsec_strerror()); + goto end; + } + msg = (struct sadb_msg *)mhp[0]; + + if (pkrecvf[msg->sadb_msg_type] == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "not supported command %s\n", + s_pfkey_type(msg->sadb_msg_type)); + goto end; + } + + if ((pkrecvf[msg->sadb_msg_type])(mhp) < 0) + goto end; + + error = 0; +end: + if (msg) + racoon_free(msg); + return(error); +} + +/* + * dump SADB + */ +vchar_t * +pfkey_dump_sadb(satype) + int satype; +{ + int s = -1; + vchar_t *buf = NULL; + pid_t pid = getpid(); + struct sadb_msg *msg = NULL; + size_t bl, ml; + int len; + + if ((s = pfkey_open()) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey open: %s\n", + ipsec_strerror()); + return NULL; + } + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_dump\n"); + if (pfkey_send_dump(s, satype) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed dump: %s\n", ipsec_strerror()); + goto fail; + } + + while (1) { + if (msg) + racoon_free(msg); + msg = pk_recv(s, &len); + if (msg == NULL) { + if (len < 0) + goto done; + else + continue; + } + + if (msg->sadb_msg_type != SADB_DUMP || msg->sadb_msg_pid != pid) + continue; + + ml = msg->sadb_msg_len << 3; + bl = buf ? buf->l : 0; + buf = vrealloc(buf, bl + ml); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to reallocate buffer to dump.\n"); + goto fail; + } + memcpy(buf->v + bl, msg, ml); + + if (msg->sadb_msg_seq == 0) + break; + } + goto done; + +fail: + if (buf) + vfree(buf); + buf = NULL; +done: + if (msg) + racoon_free(msg); + if (s >= 0) + close(s); + return buf; +} + +/* + * flush SADB + */ +void +pfkey_flush_sadb(proto) + u_int proto; +{ + int satype; + + /* convert to SADB_SATYPE */ + if ((satype = admin2pfkey_proto(proto)) < 0) + return; + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_flush\n"); + if (pfkey_send_flush(lcconf->sock_pfkey, satype) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send flush (%s)\n", ipsec_strerror()); + return; + } + + return; +} + +/* + * These are the SATYPEs that we manage. We register to get + * PF_KEY messages related to these SATYPEs, and we also use + * this list to determine which SATYPEs to delete SAs for when + * we receive an INITIAL-CONTACT. + */ +const struct pfkey_satype pfkey_satypes[] = { + { SADB_SATYPE_AH, "AH" }, + { SADB_SATYPE_ESP, "ESP" }, + { SADB_X_SATYPE_IPCOMP, "IPCOMP" }, +}; +const int pfkey_nsatypes = + sizeof(pfkey_satypes) / sizeof(pfkey_satypes[0]); + +/* + * PF_KEY initialization + */ +int +pfkey_init() +{ + int i, reg_fail; + + if ((lcconf->sock_pfkey = pfkey_open()) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed pfkey open (%s)", ipsec_strerror()); + return -1; + } + + for (i = 0, reg_fail = 0; i < pfkey_nsatypes; i++) { + plog(LLV_DEBUG, LOCATION, NULL, + "call pfkey_send_register for %s\n", + pfkey_satypes[i].ps_name); + if (pfkey_send_register(lcconf->sock_pfkey, + pfkey_satypes[i].ps_satype) < 0 || + pfkey_recv_register(lcconf->sock_pfkey) < 0) { + plog(LLV_WARNING, LOCATION, NULL, + "failed to register %s (%s)", + pfkey_satypes[i].ps_name, + ipsec_strerror()); + reg_fail++; + } + } + + if (reg_fail == pfkey_nsatypes) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to regist any protocol."); + pfkey_close(lcconf->sock_pfkey); + return -1; + } + + initsp(); + + if (pfkey_send_spddump(lcconf->sock_pfkey) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec sending spddump failed: %s", + ipsec_strerror()); + pfkey_close(lcconf->sock_pfkey); + return -1; + } +#if 0 + if (pfkey_promisc_toggle(1) < 0) { + pfkey_close(lcconf->sock_pfkey); + return -1; + } +#endif + return 0; +} + +/* %%% for conversion */ +/* IPSECDOI_ATTR_AUTH -> SADB_AALG */ +static u_int +ipsecdoi2pfkey_aalg(hashtype) + u_int hashtype; +{ + switch (hashtype) { + case IPSECDOI_ATTR_AUTH_HMAC_MD5: + return SADB_AALG_MD5HMAC; + case IPSECDOI_ATTR_AUTH_HMAC_SHA1: + return SADB_AALG_SHA1HMAC; + case IPSECDOI_ATTR_AUTH_KPDK: /* need special care */ + return SADB_AALG_NONE; + + /* not supported */ + case IPSECDOI_ATTR_AUTH_DES_MAC: + plog(LLV_ERROR, LOCATION, NULL, + "Not supported hash type: %u\n", hashtype); + return ~0; + + case 0: /* reserved */ + default: + return SADB_AALG_NONE; + + plog(LLV_ERROR, LOCATION, NULL, + "Invalid hash type: %u\n", hashtype); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_ESP -> SADB_EALG */ +static u_int +ipsecdoi2pfkey_ealg(t_id) + u_int t_id; +{ + switch (t_id) { + case IPSECDOI_ESP_DES_IV64: /* sa_flags |= SADB_X_EXT_OLD */ + return SADB_EALG_DESCBC; + case IPSECDOI_ESP_DES: + return SADB_EALG_DESCBC; + case IPSECDOI_ESP_3DES: + return SADB_EALG_3DESCBC; +#ifdef SADB_X_EALG_RC5CBC + case IPSECDOI_ESP_RC5: + return SADB_X_EALG_RC5CBC; +#endif + case IPSECDOI_ESP_CAST: + return SADB_X_EALG_CAST128CBC; + case IPSECDOI_ESP_BLOWFISH: + return SADB_X_EALG_BLOWFISHCBC; + case IPSECDOI_ESP_DES_IV32: /* flags |= (SADB_X_EXT_OLD| + SADB_X_EXT_IV4B)*/ + return SADB_EALG_DESCBC; + case IPSECDOI_ESP_NULL: + return SADB_EALG_NULL; +#ifdef SADB_X_EALG_RIJNDAELCBC + case IPSECDOI_ESP_RIJNDAEL: + return SADB_X_EALG_RIJNDAELCBC; +#endif +#ifdef SADB_X_EALG_TWOFISHCBC + case IPSECDOI_ESP_TWOFISH: + return SADB_X_EALG_TWOFISHCBC; +#endif + + /* not supported */ + case IPSECDOI_ESP_3IDEA: + case IPSECDOI_ESP_IDEA: + case IPSECDOI_ESP_RC4: + plog(LLV_ERROR, LOCATION, NULL, + "Not supported transform: %u\n", t_id); + return ~0; + + case 0: /* reserved */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid transform id: %u\n", t_id); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPCOMP -> SADB_CALG */ +static u_int +ipsecdoi2pfkey_calg(t_id) + u_int t_id; +{ + switch (t_id) { + case IPSECDOI_IPCOMP_OUI: + return SADB_X_CALG_OUI; + case IPSECDOI_IPCOMP_DEFLATE: + return SADB_X_CALG_DEFLATE; + case IPSECDOI_IPCOMP_LZS: + return SADB_X_CALG_LZS; + + case 0: /* reserved */ + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid transform id: %u\n", t_id); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_PROTO -> SADB_SATYPE */ +u_int +ipsecdoi2pfkey_proto(proto) + u_int proto; +{ + switch (proto) { + case IPSECDOI_PROTO_IPSEC_AH: + return SADB_SATYPE_AH; + case IPSECDOI_PROTO_IPSEC_ESP: + return SADB_SATYPE_ESP; + case IPSECDOI_PROTO_IPCOMP: + return SADB_X_SATYPE_IPCOMP; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ipsec_doi proto: %u\n", proto); + return ~0; + } + /*NOTREACHED*/ +} + +static u_int +ipsecdoi2pfkey_alg(algclass, type) + u_int algclass, type; +{ + switch (algclass) { + case IPSECDOI_ATTR_AUTH: + return ipsecdoi2pfkey_aalg(type); + case IPSECDOI_PROTO_IPSEC_ESP: + return ipsecdoi2pfkey_ealg(type); + case IPSECDOI_PROTO_IPCOMP: + return ipsecdoi2pfkey_calg(type); + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid ipsec_doi algclass: %u\n", algclass); + return ~0; + } + /*NOTREACHED*/ +} + +/* SADB_SATYPE -> IPSECDOI_PROTO */ +u_int +pfkey2ipsecdoi_proto(satype) + u_int satype; +{ + switch (satype) { + case SADB_SATYPE_AH: + return IPSECDOI_PROTO_IPSEC_AH; + case SADB_SATYPE_ESP: + return IPSECDOI_PROTO_IPSEC_ESP; + case SADB_X_SATYPE_IPCOMP: + return IPSECDOI_PROTO_IPCOMP; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "Invalid pfkey proto: %u\n", satype); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */ +u_int +ipsecdoi2pfkey_mode(mode) + u_int mode; +{ + switch (mode) { + case IPSECDOI_ATTR_ENC_MODE_TUNNEL: + return IPSEC_MODE_TUNNEL; + case IPSECDOI_ATTR_ENC_MODE_TRNS: + return IPSEC_MODE_TRANSPORT; + default: + plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode); + return ~0; + } + /*NOTREACHED*/ +} + +/* IPSECDOI_ATTR_ENC_MODE -> IPSEC_MODE */ +u_int +pfkey2ipsecdoi_mode(mode) + u_int mode; +{ + switch (mode) { + case IPSEC_MODE_TUNNEL: + return IPSECDOI_ATTR_ENC_MODE_TUNNEL; + case IPSEC_MODE_TRANSPORT: + return IPSECDOI_ATTR_ENC_MODE_TRNS; + case IPSEC_MODE_ANY: + return IPSECDOI_ATTR_ENC_MODE_ANY; + default: + plog(LLV_ERROR, LOCATION, NULL, "Invalid mode type: %u\n", mode); + return ~0; + } + /*NOTREACHED*/ +} + +/* default key length for encryption algorithm */ +static u_int +keylen_aalg(hashtype) + u_int hashtype; +{ + int res; + + if (hashtype == 0) + return SADB_AALG_NONE; + + res = alg_ipsec_hmacdef_hashlen(hashtype); + if (res == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid hmac algorithm %u.\n", hashtype); + return ~0; + } + return res; +} + +/* default key length for encryption algorithm */ +static u_int +keylen_ealg(enctype, encklen) + u_int enctype; + int encklen; +{ + int res; + + res = alg_ipsec_encdef_keylen(enctype, encklen); + if (res == -1) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encryption algorithm %u.\n", enctype); + return ~0; + } + return res; +} + +int +pfkey_convertfromipsecdoi(proto_id, t_id, hashtype, + e_type, e_keylen, a_type, a_keylen, flags) + u_int proto_id; + u_int t_id; + u_int hashtype; + u_int *e_type; + u_int *e_keylen; + u_int *a_type; + u_int *a_keylen; + u_int *flags; +{ + *flags = 0; + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_ESP: + if ((*e_type = ipsecdoi2pfkey_ealg(t_id)) == ~0) + goto bad; + if ((*e_keylen = keylen_ealg(t_id, *e_keylen)) == ~0) + goto bad; + *e_keylen >>= 3; + + if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0) + goto bad; + if ((*a_keylen = keylen_aalg(hashtype)) == ~0) + goto bad; + *a_keylen >>= 3; + + if (*e_type == SADB_EALG_NONE) { + plog(LLV_ERROR, LOCATION, NULL, "no ESP algorithm.\n"); + goto bad; + } + break; + + case IPSECDOI_PROTO_IPSEC_AH: + if ((*a_type = ipsecdoi2pfkey_aalg(hashtype)) == ~0) + goto bad; + if ((*a_keylen = keylen_aalg(hashtype)) == ~0) + goto bad; + *a_keylen >>= 3; + + if (t_id == IPSECDOI_ATTR_AUTH_HMAC_MD5 + && hashtype == IPSECDOI_ATTR_AUTH_KPDK) { + /* AH_MD5 + Auth(KPDK) = RFC1826 keyed-MD5 */ + *a_type = SADB_X_AALG_MD5; + *flags |= SADB_X_EXT_OLD; + } + *e_type = SADB_EALG_NONE; + *e_keylen = 0; + if (*a_type == SADB_AALG_NONE) { + plog(LLV_ERROR, LOCATION, NULL, "no AH algorithm.\n"); + goto bad; + } + break; + + case IPSECDOI_PROTO_IPCOMP: + if ((*e_type = ipsecdoi2pfkey_calg(t_id)) == ~0) + goto bad; + *e_keylen = 0; + + *flags = SADB_X_EXT_RAWCPI; + + *a_type = SADB_AALG_NONE; + *a_keylen = 0; + if (*e_type == SADB_X_CALG_NONE) { + plog(LLV_ERROR, LOCATION, NULL, "no IPCOMP algorithm.\n"); + goto bad; + } + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, "unknown IPsec protocol.\n"); + goto bad; + } + + return 0; + + bad: + errno = EINVAL; + return -1; +} + +/* called from scheduler */ +void +pfkey_timeover_stub(p) + void *p; +{ + + pfkey_timeover((struct ph2handle *)p); +} + +void +pfkey_timeover(iph2) + struct ph2handle *iph2; +{ + plog(LLV_ERROR, LOCATION, NULL, + "%s give up to get IPsec-SA due to time up to wait.\n", + saddrwop2str(iph2->dst)); + SCHED_KILL(iph2->sce); + + /* If initiator side, send error to kernel by SADB_ACQUIRE. */ + if (iph2->side == INITIATOR) + pk_sendeacquire(iph2); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return; +} + +/*%%%*/ +/* send getspi message per ipsec protocol per remote address */ +/* + * the local address and remote address in ph1handle are dealed + * with destination address and source address respectively. + * Because SPI is decided by responder. + */ +int +pk_sendgetspi(iph2) + struct ph2handle *iph2; +{ + u_int satype, mode; + struct saprop *pp; + struct saproto *pr; + + pp = iph2->side == INITIATOR + ? iph2->proposal + : iph2->approval; + + for (pr = pp->head; pr != NULL; pr = pr->next) { + + /* validity check */ + satype = ipsecdoi2pfkey_proto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + return -1; + } + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_getspi\n"); + if (pfkey_send_getspi( + lcconf->sock_pfkey, + satype, + mode, + iph2->dst, /* src of SA */ + iph2->src, /* dst of SA */ + 0, 0, pr->reqid_in, iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "ipseclib failed send getspi (%s)\n", + ipsec_strerror()); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey GETSPI sent: %s\n", + sadbsecas2str(iph2->dst, iph2->src, satype, 0, mode)); + } + + return 0; +} + +/* + * receive GETSPI from kernel. + */ +static int +pk_recvgetspi(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct ph2handle *iph2; + struct sockaddr *dst; + int proto_id; + int allspiok, notfound; + struct saprop *pp; + struct saproto *pr; + + /* validity check */ + if (mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb getspi message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); /* note SA dir */ + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid != getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because pid %d is not mine.\n", + s_pfkey_type(msg->sadb_msg_type), + msg->sadb_msg_pid); + return -1; + } + + iph2 = getph2byseq(msg->sadb_msg_seq); + if (iph2 == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "seq %d of %s message not interesting.\n", + msg->sadb_msg_seq, + s_pfkey_type(msg->sadb_msg_type)); + return -1; + } + + if (iph2->status != PHASE2ST_GETSPISENT) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatch (db:%d msg:%d)\n", + iph2->status, PHASE2ST_GETSPISENT); + return -1; + } + + /* set SPI, and check to get all spi whether or not */ + allspiok = 1; + notfound = 1; + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + pp = iph2->side == INITIATOR ? iph2->proposal : iph2->approval; + + for (pr = pp->head; pr != NULL; pr = pr->next) { + if (pr->proto_id == proto_id && pr->spi == 0) { + pr->spi = sa->sadb_sa_spi; + notfound = 0; + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey GETSPI succeeded: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + msg->sadb_msg_satype, + sa->sadb_sa_spi, + ipsecdoi2pfkey_mode(pr->encmode))); + } + if (pr->spi == 0) + allspiok = 0; /* not get all spi */ + } + + if (notfound) { + plog(LLV_ERROR, LOCATION, NULL, + "get spi for unknown address %s\n", + saddrwop2str(iph2->dst)); + return -1; + } + + if (allspiok) { + /* update status */ + iph2->status = PHASE2ST_GETSPIDONE; + if (isakmp_post_getspi(iph2) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to start post getspi.\n"); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + iph2 = NULL; + return -1; + } + } + + return 0; +} + +/* + * set inbound SA + */ +int +pk_sendupdate(iph2) + struct ph2handle *iph2; +{ + struct saproto *pr; + struct sockaddr *src = NULL, *dst = NULL; + int e_type, e_keylen, a_type, a_keylen, flags; + u_int satype, mode; + u_int64_t lifebyte = 0; + + /* sanity check */ + if (iph2->approval == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no approvaled SAs found.\n"); + } + + /* for mobile IPv6 */ + if (iph2->ph1->rmconf->support_mip6 && iph2->src_id && iph2->dst_id) { + src = iph2->src_id; + dst = iph2->dst_id; + } else { + src = iph2->src; + dst = iph2->dst; + } + + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + /* validity check */ + satype = ipsecdoi2pfkey_proto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + return -1; + } +#ifdef ENABLE_SAMODE_UNSPECIFIED + mode = IPSEC_MODE_ANY; +#else + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + return -1; + } +#endif + + /* set algorithm type and key length */ + e_keylen = pr->head->encklen; + if (pfkey_convertfromipsecdoi( + pr->proto_id, + pr->head->trns_id, + pr->head->authtype, + &e_type, &e_keylen, + &a_type, &a_keylen, &flags) < 0) + return -1; + +#if 0 + lifebyte = iph2->approval->lifebyte * 1024, +#else + lifebyte = 0; +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_update\n"); + + if (pfkey_send_update( + lcconf->sock_pfkey, + satype, + mode, + iph2->dst, + iph2->src, + pr->spi, + pr->reqid_in, + 4, /* XXX static size of window */ + pr->keymat->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send update (%s)\n", + ipsec_strerror()); + return -1; + } + + if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) + continue; + + /* + * It maybe good idea to call backupsa_to_file() after + * racoon will receive the sadb_update messages. + * But it is impossible because there is not key in the + * information from the kernel. + */ + if (backupsa_to_file(satype, mode, iph2->dst, iph2->src, + pr->spi, pr->reqid_in, 4, + pr->keymat->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, iph2->approval->lifebyte * 1024, + iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "backuped SA failed: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + satype, pr->spi, mode)); + } + plog(LLV_DEBUG, LOCATION, NULL, + "backuped SA: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + satype, pr->spi, mode)); + } + + return 0; +} + +static int +pk_recvupdate(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + u_int proto_id, encmode, sa_mode; + int incomplete = 0; + struct saproto *pr; + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb update message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + + sa_mode = mhp[SADB_X_EXT_SA2] == NULL + ? IPSEC_MODE_ANY + : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid != getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because pid %d is not mine.\n", + s_pfkey_type(msg->sadb_msg_type), + msg->sadb_msg_pid); + return -1; + } + + iph2 = getph2byseq(msg->sadb_msg_seq); + if (iph2 == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "seq %d of %s message not interesting.\n", + msg->sadb_msg_seq, + s_pfkey_type(msg->sadb_msg_type)); + return -1; + } + + if (iph2->status != PHASE2ST_ADDSA) { + plog(LLV_ERROR, LOCATION, NULL, + "status mismatch (db:%d msg:%d)\n", + iph2->status, PHASE2ST_ADDSA); + return -1; + } + + /* check to complete all keys ? */ + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + if (proto_id == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", msg->sadb_msg_satype); + return -1; + } + encmode = pfkey2ipsecdoi_mode(sa_mode); + if (encmode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", sa_mode); + return -1; + } + + if (pr->proto_id == proto_id + && pr->spi == sa->sadb_sa_spi) { + pr->ok = 1; + plog(LLV_DEBUG, LOCATION, NULL, + "pfkey UPDATE succeeded: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + msg->sadb_msg_satype, + sa->sadb_sa_spi, + sa_mode)); + + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA established: %s\n", + sadbsecas2str(iph2->dst, iph2->src, + msg->sadb_msg_satype, sa->sadb_sa_spi, + sa_mode)); + } + + if (pr->ok == 0) + incomplete = 1; + } + + if (incomplete) + return 0; + + /* turn off the timer for calling pfkey_timeover() */ + SCHED_KILL(iph2->sce); + + /* update status */ + iph2->status = PHASE2ST_ESTABLISHED; + +#ifdef ENABLE_STATS + gettimeofday(&iph2->end, NULL); + syslog(LOG_NOTICE, "%s(%s): %8.6f", + "phase2", "quick", timedelta(&iph2->start, &iph2->end)); +#endif + + /* count up */ + iph2->ph1->ph2cnt++; + + /* + * since we are going to reuse the phase2 handler, we need to + * remain it and refresh all the references between ph1 and ph2 to use. + */ + unbindph12(iph2); + + iph2->sce = sched_new(iph2->approval->lifetime, + isakmp_ph2expire_stub, iph2); + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + return 0; +} + +/* + * set outbound SA + */ +int +pk_sendadd(iph2) + struct ph2handle *iph2; +{ + struct saproto *pr; + struct sockaddr *src = NULL, *dst = NULL; + int e_type, e_keylen, a_type, a_keylen, flags; + u_int satype, mode; + u_int64_t lifebyte = 0; + + /* sanity check */ + if (iph2->approval == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no approvaled SAs found.\n"); + } + + /* for mobile IPv6 */ + if (iph2->ph1->rmconf->support_mip6 && iph2->src_id && iph2->dst_id) { + src = iph2->src_id; + dst = iph2->dst_id; + } else { + src = iph2->src; + dst = iph2->dst; + } + + for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { + /* validity check */ + satype = ipsecdoi2pfkey_proto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + return -1; + } +#ifdef ENABLE_SAMODE_UNSPECIFIED + mode = IPSEC_MODE_ANY; +#else + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + return -1; + } +#endif + + /* set algorithm type and key length */ + e_keylen = pr->head->encklen; + if (pfkey_convertfromipsecdoi( + pr->proto_id, + pr->head->trns_id, + pr->head->authtype, + &e_type, &e_keylen, + &a_type, &a_keylen, &flags) < 0) + return -1; + +#if 0 + lifebyte = iph2->approval->lifebyte * 1024, +#else + lifebyte = 0; +#endif + + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_add\n"); + + if (pfkey_send_add( + lcconf->sock_pfkey, + satype, + mode, + iph2->src, + iph2->dst, + pr->spi_p, + pr->reqid_out, + 4, /* XXX static size of window */ + pr->keymat_p->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, lifebyte, iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send add (%s)\n", + ipsec_strerror()); + return -1; + } + + if (!lcconf->pathinfo[LC_PATHTYPE_BACKUPSA]) + continue; + + /* + * It maybe good idea to call backupsa_to_file() after + * racoon will receive the sadb_update messages. + * But it is impossible because there is not key in the + * information from the kernel. + */ + if (backupsa_to_file(satype, mode, iph2->src, iph2->dst, + pr->spi_p, pr->reqid_out, 4, + pr->keymat_p->v, + e_type, e_keylen, a_type, a_keylen, flags, + 0, iph2->approval->lifebyte * 1024, + iph2->approval->lifetime, 0, + iph2->seq) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "backuped SA failed: %s\n", + sadbsecas2str(iph2->src, iph2->dst, + satype, pr->spi_p, mode)); + } + plog(LLV_DEBUG, LOCATION, NULL, + "backuped SA: %s\n", + sadbsecas2str(iph2->src, iph2->dst, + satype, pr->spi_p, mode)); + } + + return 0; +} + +static int +pk_recvadd(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + u_int sa_mode; + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb add message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + + sa_mode = mhp[SADB_X_EXT_SA2] == NULL + ? IPSEC_MODE_ANY + : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid != getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because pid %d is not mine.\n", + s_pfkey_type(msg->sadb_msg_type), + msg->sadb_msg_pid); + return -1; + } + + iph2 = getph2byseq(msg->sadb_msg_seq); + if (iph2 == NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "seq %d of %s message not interesting.\n", + msg->sadb_msg_seq, + s_pfkey_type(msg->sadb_msg_type)); + return -1; + } + + /* + * NOTE don't update any status of phase2 handle + * because they must be updated by SADB_UPDATE message + */ + + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA established: %s\n", + sadbsecas2str(iph2->src, iph2->dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); + + plog(LLV_DEBUG, LOCATION, NULL, "===\n"); + return 0; +} + +static int +pk_recvexpire(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2; + u_int proto_id, sa_mode; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || (mhp[SADB_EXT_LIFETIME_HARD] != NULL + && mhp[SADB_EXT_LIFETIME_SOFT] != NULL)) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb expire message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + sa_mode = mhp[SADB_X_EXT_SA2] == NULL + ? IPSEC_MODE_ANY + : ((struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2])->sadb_x_sa2_mode; + + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + if (proto_id == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", msg->sadb_msg_satype); + return -1; + } + + plog(LLV_INFO, LOCATION, NULL, + "IPsec-SA expired: %s\n", + sadbsecas2str(src, dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, sa_mode)); + + iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + if (iph2 == NULL) { + /* + * Ignore it because two expire messages are come up. + * phase2 handler has been deleted already when 2nd message + * is received. + */ + plog(LLV_DEBUG, LOCATION, NULL, + "no such a SA found: %s\n", + sadbsecas2str(src, dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, + sa_mode)); + return 0; + } + if (iph2->status != PHASE2ST_ESTABLISHED) { + /* + * If the status is not equal to PHASE2ST_ESTABLISHED, + * racoon ignores this expire message. There are two reason. + * One is that the phase 2 probably starts becuase there is + * a potential that racoon receives the acquire message + * without receiving a expire message. Another is that racoon + * may receive the multiple expire messages from the kernel. + */ + plog(LLV_WARNING, LOCATION, NULL, + "the expire message is received " + "but the handler has not been established.\n"); + return 0; + } + + /* turn off the timer for calling isakmp_ph2expire() */ + SCHED_KILL(iph2->sce); + + iph2->status = PHASE2ST_EXPIRED; + + /* INITIATOR, begin phase 2 exchange. */ + /* allocate buffer for status management of pfkey message */ + if (iph2->side == INITIATOR) { + + initph2(iph2); + + /* update status for re-use */ + iph2->status = PHASE2ST_STATUS2; + + /* start isakmp initiation by using ident exchange */ + if (isakmp_post_acquire(iph2) < 0) { + plog(LLV_ERROR, LOCATION, iph2->dst, + "failed to begin ipsec sa " + "re-negotication.\n"); + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + return -1; + } + + return 0; + /*NOTREACHED*/ + } + + /* If not received SADB_EXPIRE, INITIATOR delete ph2handle. */ + /* RESPONDER always delete ph2handle, keep silent. RESPONDER doesn't + * manage IPsec SA, so delete the list */ + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return 0; +} + +static int +pk_recvacquire(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_x_policy *xpl; + struct secpolicy *sp_out = NULL, *sp_in = NULL; +#define MAXNESTEDSA 5 /* XXX */ + struct ph2handle *iph2[MAXNESTEDSA]; + int n; /* # of phase 2 handler */ + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb acquire message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + /* ignore if type is not IPSEC_POLICY_IPSEC */ + if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore SPDGET message. type is not IPsec.\n"); + return 0; + } + + /* ignore it if src is multicast address */ + { + struct sockaddr *sa = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + if ((sa->sa_family == AF_INET + && IN_MULTICAST(ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr))) +#ifdef INET6 + || (sa->sa_family == AF_INET6 + && IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr)) +#endif + ) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore due to multicast address: %s.\n", + saddrwop2str(sa)); + return 0; + } + } + + /* + * If there is a phase 2 handler against the policy identifier in + * the acquire message, and if + * 1. its state is less than PHASE2ST_ESTABLISHED, then racoon + * should ignore such a acquire message becuase the phase 2 + * is just negotiating. + * 2. its state is equal to PHASE2ST_ESTABLISHED, then racoon + * has to prcesss such a acquire message becuase racoon may + * lost the expire message. + */ + iph2[0] = getph2byspid(xpl->sadb_x_policy_id); + if (iph2[0] != NULL) { + if (iph2[0]->status < PHASE2ST_ESTABLISHED) { + plog(LLV_DEBUG, LOCATION, NULL, + "ignore the acquire becuase ph2 found\n"); + return -1; + } + if (iph2[0]->status == PHASE2ST_EXPIRED) + iph2[0] = NULL; + /*FALLTHROUGH*/ + } + + /* search for proper policyindex */ + sp_out = getspbyspid(xpl->sadb_x_policy_id); + if (sp_out == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no policy found: id:%d.\n", + xpl->sadb_x_policy_id); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "suitable outbound SP found: %s.\n", spidx2str(&sp_out->spidx)); + + /* get inbound policy */ + { + struct policyindex spidx; + + spidx.dir = IPSEC_DIR_INBOUND; + memcpy(&spidx.src, &sp_out->spidx.dst, sizeof(spidx.src)); + memcpy(&spidx.dst, &sp_out->spidx.src, sizeof(spidx.dst)); + spidx.prefs = sp_out->spidx.prefd; + spidx.prefd = sp_out->spidx.prefs; + spidx.ul_proto = sp_out->spidx.ul_proto; + + sp_in = getsp(&spidx); + if (sp_in) { + plog(LLV_DEBUG, LOCATION, NULL, + "suitable inbound SP found: %s.\n", + spidx2str(&sp_in->spidx)); + } else { + plog(LLV_NOTIFY, LOCATION, NULL, + "no in-bound policy found: %s\n", + spidx2str(&spidx)); + } + } + + memset(iph2, 0, MAXNESTEDSA); + + n = 0; + + /* allocate a phase 2 */ + iph2[n] = newph2(); + if (iph2[n] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate phase2 entry.\n"); + return -1; + } + iph2[n]->side = INITIATOR; + iph2[n]->spid = xpl->sadb_x_policy_id; + iph2[n]->satype = msg->sadb_msg_satype; + iph2[n]->seq = msg->sadb_msg_seq; + iph2[n]->status = PHASE2ST_STATUS2; + + /* set end addresses of SA */ + iph2[n]->dst = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST])); + if (iph2[n]->dst == NULL) { + delph2(iph2[n]); + return -1; + } + iph2[n]->src = dupsaddr(PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC])); + if (iph2[n]->src == NULL) { + delph2(iph2[n]); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "new acquire %s\n", spidx2str(&sp_out->spidx)); + + /* get sainfo */ + { + vchar_t *idsrc, *iddst; + + idsrc = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.src, + sp_out->spidx.prefs, sp_out->spidx.ul_proto); + if (idsrc == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp_out->spidx)); + delph2(iph2[n]); + return -1; + } + iddst = ipsecdoi_sockaddr2id((struct sockaddr *)&sp_out->spidx.dst, + sp_out->spidx.prefd, sp_out->spidx.ul_proto); + if (iddst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get ID for %s\n", + spidx2str(&sp_out->spidx)); + vfree(idsrc); + delph2(iph2[n]); + return -1; + } + iph2[n]->sainfo = getsainfo(idsrc, iddst); + vfree(idsrc); + vfree(iddst); + if (iph2[n]->sainfo == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get sainfo.\n"); + delph2(iph2[n]); + return -1; + /* XXX should use the algorithm list from register message */ + } + } + + if (set_proposal_from_policy(iph2[n], sp_out, sp_in) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to create saprop.\n"); + delph2(iph2[n]); + return -1; + } + insph2(iph2[n]); + + /* start isakmp initiation by using ident exchange */ + /* XXX should be looped if there are multiple phase 2 handler. */ + if (isakmp_post_acquire(iph2[n]) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to begin ipsec sa negotication.\n"); + goto err; + } + + return 0; + +err: + while (n >= 0) { + unbindph12(iph2[n]); + remph2(iph2[n]); + delph2(iph2[n]); + iph2[n] = NULL; + n--; + } + return -1; +} + +static int +pk_recvdelete(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_sa *sa; + struct sockaddr *src, *dst; + struct ph2handle *iph2 = NULL; + u_int proto_id; + + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_SA] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb acquire message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + src = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_SRC]); + dst = PFKEY_ADDR_SADDR(mhp[SADB_EXT_ADDRESS_DST]); + + /* the message has to be processed or not ? */ + if (msg->sadb_msg_pid == getpid()) { + plog(LLV_DEBUG, LOCATION, NULL, + "%s message is not interesting " + "because the message was originated by me.\n", + s_pfkey_type(msg->sadb_msg_type), + msg->sadb_msg_pid); + return -1; + } + + proto_id = pfkey2ipsecdoi_proto(msg->sadb_msg_satype); + if (proto_id == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", msg->sadb_msg_satype); + return -1; + } + + iph2 = getph2bysaidx(src, dst, proto_id, sa->sadb_sa_spi); + if (iph2 == NULL) { + /* ignore */ + plog(LLV_ERROR, LOCATION, NULL, + "no iph2 found: %s\n", + sadbsecas2str(src, dst, msg->sadb_msg_satype, + sa->sadb_sa_spi, IPSEC_MODE_ANY)); + return 0; + } + + plog(LLV_ERROR, LOCATION, NULL, + "pfkey DELETE received: %s\n", + sadbsecas2str(iph2->src, iph2->dst, + msg->sadb_msg_satype, sa->sadb_sa_spi, IPSEC_MODE_ANY)); + + /* send delete information */ + if (iph2->status == PHASE2ST_ESTABLISHED) + isakmp_info_send_d2(iph2); + + unbindph12(iph2); + remph2(iph2); + delph2(iph2); + + return 0; +} + +static int +pk_recvflush(mhp) + caddr_t *mhp; +{ + /* ignore this message because of local test mode. */ + if (f_local) + return 0; + + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb acquire message passed.\n"); + return -1; + } + + flushph2(); + + return 0; +} + +static int +getsadbpolicy(policy0, policylen0, type, iph2) + caddr_t *policy0; + int *policylen0, type; + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + struct sadb_x_policy *xpl; + struct sadb_x_ipsecrequest *xisr; + struct saproto *pr; + caddr_t policy, p; + int policylen; + int xisrlen; + u_int satype, mode; + + /* get policy buffer size */ + policylen = sizeof(struct sadb_x_policy); + if (type != SADB_X_SPDDELETE) { + for (pr = iph2->approval->head; pr; pr = pr->next) { + xisrlen = sizeof(*xisr); + if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) { + xisrlen += (iph2->src->sa_len + + iph2->dst->sa_len); + } + + policylen += PFKEY_ALIGN8(xisrlen); + } + } + + /* make policy structure */ + policy = racoon_malloc(policylen); + if (!policy) { + plog(LLV_ERROR, LOCATION, NULL, + "buffer allocation failed.\n"); + return -1; + } + + xpl = (struct sadb_x_policy *)policy; + xpl->sadb_x_policy_len = PFKEY_UNIT64(policylen); + xpl->sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl->sadb_x_policy_type = IPSEC_POLICY_IPSEC; + xpl->sadb_x_policy_dir = spidx->dir; + xpl->sadb_x_policy_id = 0; + + /* no need to append policy information any more if type is SPDDELETE */ + if (type == SADB_X_SPDDELETE) + goto end; + + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + for (pr = iph2->approval->head; pr; pr = pr->next) { + + satype = doi2ipproto(pr->proto_id); + if (satype == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto_id %d\n", pr->proto_id); + goto err; + } + mode = ipsecdoi2pfkey_mode(pr->encmode); + if (mode == ~0) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid encmode %d\n", pr->encmode); + goto err; + } + + /* + * the policy level cannot be unique because the policy + * is defined later than SA, so req_id cannot be bound to SA. + */ + xisr->sadb_x_ipsecrequest_proto = satype; + xisr->sadb_x_ipsecrequest_mode = mode; + xisr->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; + xisr->sadb_x_ipsecrequest_reqid = 0; + p = (caddr_t)(xisr + 1); + + xisrlen = sizeof(*xisr); + + if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL) { + xisrlen += (iph2->src->sa_len + iph2->dst->sa_len); + + memcpy(p, iph2->src, iph2->src->sa_len); + p += iph2->src->sa_len; + + memcpy(p, iph2->dst, iph2->dst->sa_len); + p += iph2->dst->sa_len; + } + + xisr->sadb_x_ipsecrequest_len = PFKEY_ALIGN8(xisrlen); + } + +end: + *policy0 = policy; + *policylen0 = policylen; + + return 0; + +err: + if (policy) + racoon_free(policy); + + return -1; +} + +int +pk_sendspdupdate2(iph2) + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + caddr_t policy = NULL; + int policylen = 0; + u_int64_t ltime, vtime; + + ltime = iph2->approval->lifetime; + vtime = 0; + + if (getsadbpolicy(&policy, &policylen, SADB_X_SPDUPDATE, iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "getting sadb policy failed.\n"); + return -1; + } + + if (pfkey_send_spdupdate2( + lcconf->sock_pfkey, + (struct sockaddr *)&spidx->src, + spidx->prefs, + (struct sockaddr *)&spidx->dst, + spidx->prefd, + spidx->ul_proto, + ltime, vtime, + policy, policylen, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send spdupdate2 (%s)\n", + ipsec_strerror()); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdupdate2\n"); + +end: + if (policy) + racoon_free(policy); + + return 0; +} + +static int +pk_recvspdupdate(mhp) + caddr_t *mhp; +{ + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdupdate message passed.\n"); + return -1; + } + + return 0; +} + +/* + * this function has to be used by responder side. + */ +int +pk_sendspdadd2(iph2) + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + caddr_t policy = NULL; + int policylen = 0; + u_int64_t ltime, vtime; + + ltime = iph2->approval->lifetime; + vtime = 0; + + if (getsadbpolicy(&policy, &policylen, SADB_X_SPDADD, iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "getting sadb policy failed.\n"); + return -1; + } + + if (pfkey_send_spdadd2( + lcconf->sock_pfkey, + (struct sockaddr *)&spidx->src, + spidx->prefs, + (struct sockaddr *)&spidx->dst, + spidx->prefd, + spidx->ul_proto, + ltime, vtime, + policy, policylen, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send spdadd2 (%s)\n", + ipsec_strerror()); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spdadd2\n"); + +end: + if (policy) + racoon_free(policy); + + return 0; +} + +static int +pk_recvspdadd(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdadd message passed.\n"); + return -1; + } + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); + + sp = getsp(&spidx); + if (sp != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "such policy already exists. " + "anyway replace it: %s\n", + spidx2str(&spidx)); + remsp(sp); + delsp(sp); + } + + if (addnewsp(mhp) < 0) + return -1; + + return 0; +} + +/* + * this function has to be used by responder side. + */ +int +pk_sendspddelete(iph2) + struct ph2handle *iph2; +{ + struct policyindex *spidx = (struct policyindex *)iph2->spidx_gen; + caddr_t policy = NULL; + int policylen; + + if (getsadbpolicy(&policy, &policylen, SADB_X_SPDDELETE, iph2)) { + plog(LLV_ERROR, LOCATION, NULL, + "getting sadb policy failed.\n"); + return -1; + } + + if (pfkey_send_spddelete( + lcconf->sock_pfkey, + (struct sockaddr *)&spidx->src, + spidx->prefs, + (struct sockaddr *)&spidx->dst, + spidx->prefd, + spidx->ul_proto, + policy, policylen, 0) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "libipsec failed send spddelete (%s)\n", + ipsec_strerror()); + goto end; + } + plog(LLV_DEBUG, LOCATION, NULL, "call pfkey_send_spddelete\n"); + +end: + if (policy) + racoon_free(policy); + + return 0; +} + +static int +pk_recvspddelete(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spddelete message passed.\n"); + return -1; + } + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); + + sp = getsp(&spidx); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no policy found: %s\n", + spidx2str(&spidx)); + return -1; + } + + remsp(sp); + delsp(sp); + + return 0; +} + +static int +pk_recvspdexpire(mhp) + caddr_t *mhp; +{ + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL + || mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdexpire message passed.\n"); + return -1; + } + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); + + sp = getsp(&spidx); + if (sp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no policy found: %s\n", + spidx2str(&spidx)); + return -1; + } + + remsp(sp); + delsp(sp); + + return 0; +} + +static int +pk_recvspdget(mhp) + caddr_t *mhp; +{ + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdget message passed.\n"); + return -1; + } + + return 0; +} + +static int +pk_recvspddump(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + struct policyindex spidx; + struct secpolicy *sp; + + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spddump message passed.\n"); + return -1; + } + msg = (struct sadb_msg *)mhp[0]; + + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &spidx); + + sp = getsp(&spidx); + if (sp != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "such policy already exists. " + "anyway replace it: %s\n", + spidx2str(&spidx)); + remsp(sp); + delsp(sp); + } + + if (addnewsp(mhp) < 0) + return -1; + + return 0; +} + +static int +pk_recvspdflush(mhp) + caddr_t *mhp; +{ + /* sanity check */ + if (mhp[0] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spdflush message passed.\n"); + return -1; + } + + flushsp(); + + return 0; +} + +/* + * send error against acquire message to kenrel. + */ +int +pk_sendeacquire(iph2) + struct ph2handle *iph2; +{ + struct sadb_msg *newmsg; + int len; + + len = sizeof(struct sadb_msg); + newmsg = racoon_calloc(1, len); + if (newmsg == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get buffer to send acquire.\n"); + return -1; + } + + memset(newmsg, 0, len); + newmsg->sadb_msg_version = PF_KEY_V2; + newmsg->sadb_msg_type = SADB_ACQUIRE; + newmsg->sadb_msg_errno = ENOENT; /* XXX */ + newmsg->sadb_msg_satype = iph2->satype; + newmsg->sadb_msg_len = PFKEY_UNIT64(len); + newmsg->sadb_msg_reserved = 0; + newmsg->sadb_msg_seq = iph2->seq; + newmsg->sadb_msg_pid = (u_int32_t)getpid(); + + /* send message */ + len = pfkey_send(lcconf->sock_pfkey, newmsg, len); + + racoon_free(newmsg); + + return 0; +} + +/* + * check if the algorithm is supported or not. + * OUT 0: ok + * -1: ng + */ +int +pk_checkalg(class, calg, keylen) + int class, calg, keylen; +{ + int sup, error; + u_int alg; + struct sadb_alg alg0; + + switch (algclass2doi(class)) { + case IPSECDOI_PROTO_IPSEC_ESP: + sup = SADB_EXT_SUPPORTED_ENCRYPT; + break; + case IPSECDOI_ATTR_AUTH: + sup = SADB_EXT_SUPPORTED_AUTH; + break; + case IPSECDOI_PROTO_IPCOMP: + plog(LLV_DEBUG, LOCATION, NULL, + "compression algorithm can not be checked " + "because sadb message doesn't support it.\n"); + return 0; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid algorithm class.\n"); + return -1; + } + alg = ipsecdoi2pfkey_alg(algclass2doi(class), algtype2doi(class, calg)); + if (alg == ~0) + return -1; + + if (keylen == 0) { + if (ipsec_get_keylen(sup, alg, &alg0)) { + plog(LLV_ERROR, LOCATION, NULL, + "%s.\n", ipsec_strerror()); + return -1; + } + keylen = alg0.sadb_alg_minbits; + } + + error = ipsec_check_keylen(sup, alg, keylen); + if (error) + plog(LLV_ERROR, LOCATION, NULL, + "%s.\n", ipsec_strerror()); + + return error; +} + +/* + * differences with pfkey_recv() in libipsec/pfkey.c: + * - never performs busy wait loop. + * - returns NULL and set *lenp to negative on fatal failures + * - returns NULL and set *lenp to non-negative on non-fatal failures + * - returns non-NULL on success + */ +static struct sadb_msg * +pk_recv(so, lenp) + int so; + int *lenp; +{ + struct sadb_msg buf, *newmsg; + int reallen; + + *lenp = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK); + if (*lenp < 0) + return NULL; /*fatal*/ + else if (*lenp < sizeof(buf)) + return NULL; + + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = racoon_calloc(1, reallen)) == NULL) + return NULL; + + *lenp = recv(so, (caddr_t)newmsg, reallen, MSG_PEEK); + if (*lenp < 0) { + racoon_free(newmsg); + return NULL; /*fatal*/ + } else if (*lenp != reallen) { + racoon_free(newmsg); + return NULL; + } + + *lenp = recv(so, (caddr_t)newmsg, reallen, 0); + if (*lenp < 0) { + racoon_free(newmsg); + return NULL; /*fatal*/ + } else if (*lenp != reallen) { + racoon_free(newmsg); + return NULL; + } + + return newmsg; +} + +/* see handler.h */ +u_int32_t +pk_getseq() +{ + return (u_int32_t)random(); +} + +static int +addnewsp(mhp) + caddr_t *mhp; +{ + struct secpolicy *new; + struct sadb_address *saddr, *daddr; + struct sadb_x_policy *xpl; + + /* sanity check */ + if (mhp[SADB_EXT_ADDRESS_SRC] == NULL + || mhp[SADB_EXT_ADDRESS_DST] == NULL + || mhp[SADB_X_EXT_POLICY] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "inappropriate sadb spd management message passed.\n"); + return -1; + } + + saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + + new = newsp(); + if (new == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer\n"); + return -1; + } + + new->spidx.dir = xpl->sadb_x_policy_dir; + new->id = xpl->sadb_x_policy_id; + new->policy = xpl->sadb_x_policy_type; + new->req = NULL; + + /* check policy */ + switch (xpl->sadb_x_policy_type) { + case IPSEC_POLICY_DISCARD: + case IPSEC_POLICY_NONE: + case IPSEC_POLICY_ENTRUST: + case IPSEC_POLICY_BYPASS: + break; + + case IPSEC_POLICY_IPSEC: + { + int tlen; + struct sadb_x_ipsecrequest *xisr; + struct ipsecrequest **p_isr = &new->req; + + /* validity check */ + if (PFKEY_EXTLEN(xpl) < sizeof(*xpl)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid msg length.\n"); + return -1; + } + + tlen = PFKEY_EXTLEN(xpl) - sizeof(*xpl); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + while (tlen > 0) { + + /* length check */ + if (xisr->sadb_x_ipsecrequest_len < sizeof(*xisr)) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid msg length.\n"); + return -1; + } + + /* allocate request buffer */ + *p_isr = newipsecreq(); + if (*p_isr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get new ipsecreq.\n"); + return -1; + } + + /* set values */ + (*p_isr)->next = NULL; + + switch (xisr->sadb_x_ipsecrequest_proto) { + case IPPROTO_ESP: + case IPPROTO_AH: + case IPPROTO_IPCOMP: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid proto type: %u\n", + xisr->sadb_x_ipsecrequest_proto); + return -1; + } + (*p_isr)->saidx.proto = xisr->sadb_x_ipsecrequest_proto; + + switch (xisr->sadb_x_ipsecrequest_mode) { + case IPSEC_MODE_TRANSPORT: + case IPSEC_MODE_TUNNEL: + break; + case IPSEC_MODE_ANY: + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid mode: %u\n", + xisr->sadb_x_ipsecrequest_mode); + return -1; + } + (*p_isr)->saidx.mode = xisr->sadb_x_ipsecrequest_mode; + + switch (xisr->sadb_x_ipsecrequest_level) { + case IPSEC_LEVEL_DEFAULT: + case IPSEC_LEVEL_USE: + case IPSEC_LEVEL_REQUIRE: + break; + case IPSEC_LEVEL_UNIQUE: + (*p_isr)->saidx.reqid = + xisr->sadb_x_ipsecrequest_reqid; + break; + + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid level: %u\n", + xisr->sadb_x_ipsecrequest_level); + return -1; + } + (*p_isr)->level = xisr->sadb_x_ipsecrequest_level; + + /* set IP addresses if there */ + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + struct sockaddr *paddr; + + paddr = (struct sockaddr *)(xisr + 1); + bcopy(paddr, &(*p_isr)->saidx.src, + paddr->sa_len); + + paddr = (struct sockaddr *)((caddr_t)paddr + + paddr->sa_len); + bcopy(paddr, &(*p_isr)->saidx.dst, + paddr->sa_len); + } + + (*p_isr)->sp = new; + + /* initialization for the next. */ + p_isr = &(*p_isr)->next; + tlen -= xisr->sadb_x_ipsecrequest_len; + + /* validity check */ + if (tlen < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "becoming tlen < 0\n"); + } + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid policy type.\n"); + return -1; + } + + KEY_SETSECSPIDX(xpl->sadb_x_policy_dir, + saddr + 1, + daddr + 1, + saddr->sadb_address_prefixlen, + daddr->sadb_address_prefixlen, + saddr->sadb_address_proto, + &new->spidx); + + inssp(new); + + return 0; +} + +/* proto/mode/src->dst spi */ +const char * +sadbsecas2str(src, dst, proto, spi, mode) + struct sockaddr *src, *dst; + int proto; + u_int32_t spi; + int mode; +{ + static char buf[256]; + u_int doi_proto, doi_mode = 0; + char *p; + int blen, i; + + doi_proto = pfkey2ipsecdoi_proto(proto); + if (doi_proto == ~0) + return NULL; + if (mode) { + doi_mode = pfkey2ipsecdoi_mode(mode); + if (doi_mode == ~0) + return NULL; + } + + blen = sizeof(buf) - 1; + p = buf; + + i = snprintf(p, blen, "%s%s%s ", + s_ipsecdoi_proto(doi_proto), + mode ? "/" : "", + mode ? s_ipsecdoi_encmode(doi_mode) : ""); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + i = snprintf(p, blen, "%s->", saddrwop2str(src)); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + i = snprintf(p, blen, "%s ", saddrwop2str(dst)); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + if (spi) { + snprintf(p, blen, "spi=%lu(0x%lx)", (unsigned long)ntohl(spi), + (unsigned long)ntohl(spi)); + } + + return buf; +} diff --git a/racoon.tproj/pfkey.h b/racoon.tproj/pfkey.h new file mode 100644 index 0000000..ebc9ef8 --- /dev/null +++ b/racoon.tproj/pfkey.h @@ -0,0 +1,70 @@ +/* $KAME: pfkey.h,v 1.19 2001/06/27 15:54:40 sakane 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. 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. + */ + +struct pfkey_satype { + u_int8_t ps_satype; + const char *ps_name; +}; + +extern const struct pfkey_satype pfkey_satypes[]; +extern const int pfkey_nsatypes; + +extern int pfkey_handler __P((void)); +extern vchar_t *pfkey_dump_sadb __P((int)); +extern void pfkey_flush_sadb __P((u_int)); +extern int pfkey_init __P((void)); + +extern struct pfkey_st *pfkey_getpst __P((caddr_t *, int, int)); + +extern int pk_checkalg __P((int, int, int)); + +struct ph2handle; +extern int pk_sendgetspi __P((struct ph2handle *)); +extern int pk_sendupdate __P((struct ph2handle *)); +extern int pk_sendadd __P((struct ph2handle *)); +extern int pk_sendeacquire __P((struct ph2handle *)); +extern int pk_sendspdupdate2 __P((struct ph2handle *)); +extern int pk_sendspdadd2 __P((struct ph2handle *)); +extern int pk_sendspddelete __P((struct ph2handle *)); + +extern void pfkey_timeover_stub __P((void *)); +extern void pfkey_timeover __P((struct ph2handle *)); + +extern u_int pfkey2ipsecdoi_proto __P((u_int)); +extern u_int ipsecdoi2pfkey_proto __P((u_int)); +extern u_int pfkey2ipsecdoi_mode __P((u_int)); +extern u_int ipsecdoi2pfkey_mode __P((u_int)); + +extern int pfkey_convertfromipsecdoi __P(( u_int, u_int, u_int, + u_int *, u_int *, u_int *, u_int *, u_int *)); +extern u_int32_t pk_getseq __P((void)); +extern const char *sadbsecas2str + __P((struct sockaddr *, struct sockaddr *, int, u_int32_t, int)); diff --git a/racoon.tproj/pfkey2.c b/racoon.tproj/pfkey2.c new file mode 100644 index 0000000..813b304 --- /dev/null +++ b/racoon.tproj/pfkey2.c @@ -0,0 +1,2108 @@ +/* $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +#define CALLOC(size, cast) (cast)calloc(1, (size)) + +static int findsupportedmap __P((int)); +static int setsupportedmap __P((struct sadb_supported *)); +static struct sadb_alg *findsupportedalg __P((u_int, u_int)); +static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, + u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static int pfkey_send_x2 __P((int, u_int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +static int pfkey_send_x3 __P((int, u_int, u_int)); +static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + char *, int, u_int32_t)); +static int pfkey_send_x5 __P((int, u_int, u_int32_t)); + +static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int, + u_int, u_int32_t, pid_t)); +static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, + u_int, u_int, u_int32_t)); +static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int, + struct sockaddr *, u_int, u_int)); +static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int)); +static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t)); + +/* + * make and search supported algorithm structure. + */ +static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, }; + +static int supported_map[] = { + SADB_SATYPE_AH, + SADB_SATYPE_ESP, + SADB_X_SATYPE_IPCOMP, +}; + +static int +findsupportedmap(satype) + int satype; +{ + int i; + + for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++) + if (supported_map[i] == satype) + return i; + return -1; +} + +static struct sadb_alg * +findsupportedalg(satype, alg_id) + u_int satype, alg_id; +{ + int algno; + int tlen; + caddr_t p; + + /* validity check */ + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + if (ipsec_supported[algno] == NULL) { + __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; + return NULL; + } + + tlen = ipsec_supported[algno]->sadb_supported_len + - sizeof(struct sadb_supported); + p = (caddr_t)(ipsec_supported[algno] + 1); + while (tlen > 0) { + if (tlen < sizeof(struct sadb_alg)) { + /* invalid format */ + break; + } + if (((struct sadb_alg *)p)->sadb_alg_id == alg_id) + return (struct sadb_alg *)p; + + tlen -= sizeof(struct sadb_alg); + p += sizeof(struct sadb_alg); + } + + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return NULL; +} + +static int +setsupportedmap(sup) + struct sadb_supported *sup; +{ + struct sadb_supported **ipsup; + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + if (*ipsup) + free(*ipsup); + + *ipsup = malloc(sup->sadb_supported_len); + if (!*ipsup) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + memcpy(*ipsup, sup, sup->sadb_supported_len); + + return 0; +} + +/* + * check key length against algorithm specified. + * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the + * augument, and only calls to ipsec_check_keylen2(); + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen(supported, alg_id, keylen) + u_int supported; + u_int alg_id; + u_int keylen; +{ + int satype; + + /* validity check */ + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + return ipsec_check_keylen2(satype, alg_id, keylen); +} + +/* + * check key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen2(satype, alg_id, keylen) + u_int satype; + u_int alg_id; + u_int keylen; +{ + struct sadb_alg *alg; + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { + __ipsec_errcode = EIPSEC_INVAL_KEYLEN; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * get max/min key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_get_keylen(supported, alg_id, alg0) + u_int supported, alg_id; + struct sadb_alg *alg0; +{ + struct sadb_alg *alg; + u_int satype; + + /* validity check */ + if (!alg0) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + memcpy(alg0, alg, sizeof(*alg0)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set the rate for SOFT lifetime against HARD one. + * If rate is more than 100 or equal to zero, then set to 100. + */ +static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; + +u_int +pfkey_set_softrate(type, rate) + u_int type, rate; +{ + __ipsec_errcode = EIPSEC_NO_ERROR; + + if (rate > 100 || rate == 0) + rate = 100; + + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + soft_lifetime_allocations_rate = rate; + return 0; + case SADB_X_LIFETIME_BYTES: + soft_lifetime_bytes_rate = rate; + return 0; + case SADB_X_LIFETIME_ADDTIME: + soft_lifetime_addtime_rate = rate; + return 0; + case SADB_X_LIFETIME_USETIME: + soft_lifetime_usetime_rate = rate; + return 0; + } + + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return 1; +} + +/* + * get current rate for SOFT lifetime against HARD one. + * ATTENTION: ~0 is returned if invalid type was passed. + */ +u_int +pfkey_get_softrate(type) + u_int type; +{ + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + return soft_lifetime_allocations_rate; + case SADB_X_LIFETIME_BYTES: + return soft_lifetime_bytes_rate; + case SADB_X_LIFETIME_ADDTIME: + return soft_lifetime_addtime_rate; + case SADB_X_LIFETIME_USETIME: + return soft_lifetime_usetime_rate; + } + + return ~0; +} + +/* + * sending SADB_GETSPI message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t min, max, reqid, seq; +{ + struct sadb_msg *newmsg; + caddr_t ep; + int len; + int need_spirange = 0; + caddr_t p; + int plen; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (min > max || (min > 0 && min <= 255)) { + __ipsec_errcode = EIPSEC_INVAL_SPI; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if (min > 255 && max < ~0) { + need_spirange++; + len += sizeof(struct sadb_spirange); + } + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI, + len, satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for source */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for destination */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* proccessing spi range */ + if (need_spirange) { + struct sadb_spirange spirange; + + if (p + sizeof(spirange) > ep) { + free(newmsg); + return -1; + } + + memset(&spirange, 0, sizeof(spirange)); + spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); + spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + spirange.sadb_spirange_min = min; + spirange.sadb_spirange_max = max; + + memcpy(p, &spirange, sizeof(spirange)); + + p += sizeof(spirange); + } + if (p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_UPDATE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_ADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_delete(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE without spi to the kernel. This is + * the "delete all" request (an extension also present in + * Solaris). + * + * OUT: + * positive: success and return length sent + * -1 : error occured, and set errno + */ +int +pfkey_send_delete_all(so, satype, mode, src, dst) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_GET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_get(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_REGISTER message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_register(so, satype) + int so; + u_int satype; +{ + int len, algno; + + if (satype == PF_UNSPEC) { + for (algno = 0; + algno < sizeof(supported_map)/sizeof(supported_map[0]); + algno++) { + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + } else { + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + + if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) + return -1; + + return len; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_recv_register(so) + int so; +{ + pid_t pid = getpid(); + struct sadb_msg *newmsg; + int error = -1; + + /* receive message */ + do { + if ((newmsg = pfkey_recv(so)) == NULL) + return -1; + } while (newmsg->sadb_msg_type != SADB_REGISTER + || newmsg->sadb_msg_pid != pid); + + /* check and fix */ + newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); + + error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); + free(newmsg); + + if (error == 0) + __ipsec_errcode = EIPSEC_NO_ERROR; + + return error; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * NOTE: sadb_msg_len must be host order. + * IN: + * tlen: msg length, it's to makeing sure. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_set_supported(msg, tlen) + struct sadb_msg *msg; + int tlen; +{ + struct sadb_supported *sup; + caddr_t p; + caddr_t ep; + + /* validity */ + if (msg->sadb_msg_len != tlen) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + p = (caddr_t)msg; + ep = p + tlen; + + p += sizeof(struct sadb_msg); + + while (p < ep) { + sup = (struct sadb_supported *)p; + if (ep < p + sizeof(*sup) || + PFKEY_EXTLEN(sup) < sizeof(*sup) || + ep < p + sup->sadb_supported_len) { + /* invalid format */ + break; + } + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* fixed length */ + sup->sadb_supported_len = PFKEY_EXTLEN(sup); + + /* set supported map */ + if (setsupportedmap(sup) != 0) + return -1; + + p += sup->sadb_supported_len; + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + + return 0; +} + +/* + * sending SADB_FLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_flush(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_dump(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_PROMISC message to the kernel. + * NOTE that this function handles promisc mode toggle only. + * IN: + * flag: set promisc off if zero, set promisc on if non-zero. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + * 0 : error occured, and set errno. + * others: a pointer to new allocated buffer in which supported + * algorithms is. + */ +int +pfkey_send_promisc_toggle(so, flag) + int so; + int flag; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete2(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDGET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdget(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDSETIDX message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDFLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdflush(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDDUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddump(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* sending SADB_ADD or SADB_UPDATE message to the kernel */ +static int +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + u_int wsize; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + switch (satype) { + case SADB_SATYPE_ESP: + if (e_type == SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_SATYPE_AH: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type == SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_X_SATYPE_IPCOMP: + if (e_type == SADB_X_CALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime); + + if (e_type != SADB_EALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); + if (a_type != SADB_AALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + if (e_type != SADB_EALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, + keymat, e_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + if (a_type != SADB_AALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, + keymat + e_keylen, a_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + + /* set sadb_lifetime for destination */ + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_DELETE or SADB_GET message to the kernel */ +static int +pfkey_send_x2(so, type, satype, mode, src, dst, spi) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message + * to the kernel + */ +static int +pfkey_send_x3(so, type, satype) + int so; + u_int type, satype; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + caddr_t ep; + + /* validity check */ + switch (type) { + case SADB_X_PROMISC: + if (satype != 0 && satype != 1) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + default: + switch (satype) { + case SADB_SATYPE_UNSPEC: + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDADD message to the kernel */ +static int +pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int type, prefs, prefd, proto; + u_int64_t ltime, vtime; + char *policy; + int policylen; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + if (prefs > plen || prefd > plen) { + __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_lifetime) + + policylen; + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + 0, 0, ltime, vtime); + if (!p || p + policylen != ep) { + free(newmsg); + return -1; + } + memcpy(p, policy, policylen); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ +static int +pfkey_send_x5(so, type, spid) + int so; + u_int type; + u_int32_t spid; +{ + struct sadb_msg *newmsg; + struct sadb_x_policy xpl; + int len; + caddr_t p; + caddr_t ep; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(xpl); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, 0, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + if (p + sizeof(xpl) != ep) { + free(newmsg); + return -1; + } + memset(&xpl, 0, sizeof(xpl)); + xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl)); + xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl.sadb_x_policy_id = spid; + memcpy(p, &xpl, sizeof(xpl)); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * open a socket. + * OUT: + * -1: fail. + * others : success and return value of socket. + */ +int +pfkey_open() +{ + int so; + const int bufsiz = 128 * 1024; /*is 128K enough?*/ + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + /* + * This is a temporary workaround for KAME PR 154. + * Don't really care even if it fails. + */ + (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); + (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return so; +} + +/* + * close a socket. + * OUT: + * 0: success. + * -1: fail. + */ +void +pfkey_close(so) + int so; +{ + (void)close(so); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return; +} + +/* + * receive sadb_msg data, and return pointer to new buffer allocated. + * Must free this buffer later. + * OUT: + * NULL : error occured. + * others : a pointer to sadb_msg structure. + * + * XXX should be rewritten to pass length explicitly + */ +struct sadb_msg * +pfkey_recv(so) + int so; +{ + struct sadb_msg buf, *newmsg; + int len, reallen; + + while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + if (len < sizeof(buf)) { + recv(so, (caddr_t)&buf, sizeof(buf), 0); + __ipsec_errcode = EIPSEC_MAX; + return NULL; + } + + /* read real message */ + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + free(newmsg); + return NULL; + } + + if (len != reallen) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + /* don't trust what the kernel says, validate! */ + if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return newmsg; +} + +/* + * send message to a socket. + * OUT: + * others: success and return length sent. + * -1 : fail. + */ +int +pfkey_send(so, msg, len) + int so; + struct sadb_msg *msg; + int len; +{ + if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * %%% Utilities + * NOTE: These functions are derived from netkey/key.c in KAME. + */ +/* + * set the pointer to each header in this message buffer. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * caddr_t mhp[SADB_EXT_MAX + 1]; + * OUT: -1: invalid. + * 0: valid. + * + * XXX should be rewritten to obtain length explicitly + */ +int +pfkey_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; +{ + struct sadb_ext *ext; + int i; + caddr_t p; + caddr_t ep; /* XXX should be passed from upper layer */ + + /* validity check */ + if (msg == NULL || mhp == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (caddr_t)msg; + + /* initialize */ + p = (caddr_t) msg; + ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); + + /* skip base header */ + p += sizeof(struct sadb_msg); + + while (p < ep) { + ext = (struct sadb_ext *)p; + if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) || + ep < p + PFKEY_EXTLEN(ext)) { + /* invalid format */ + break; + } + + /* duplicate check */ + /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ + if (mhp[ext->sadb_ext_type] != NULL) { + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* XXX should to be check weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* XXX should to be check weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: + mhp[ext->sadb_ext_type] = (caddr_t)ext; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + p += PFKEY_EXTLEN(ext); + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * check basic usage for sadb_msg, + * NOTE: This routine is derived from netkey/key.c in KAME. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * + * caddr_t mhp[SADB_EXT_MAX + 1]; + * + * OUT: -1: invalid. + * 0: valid. + */ +int +pfkey_check(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + + /* validity check */ + if (mhp == NULL || mhp[0] == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + msg = (struct sadb_msg *)mhp[0]; + + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + __ipsec_errcode = EIPSEC_INVAL_VERSION; + return -1; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; + return -1; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_ESP: + case SADB_SATYPE_AH: + case SADB_X_SATYPE_IPCOMP: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return -1; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + if (src0->sadb_address_proto != dst0->sadb_address_proto) { + __ipsec_errcode = EIPSEC_PROTO_MISMATCH; + return -1; + } + + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* + * prefixlen == 0 is valid because there must be the case + * all addresses are matched. + */ + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) + caddr_t buf; + caddr_t lim; + u_int type, satype; + u_int tlen; + u_int32_t seq; + pid_t pid; +{ + struct sadb_msg *p; + u_int len; + + p = (struct sadb_msg *)buf; + len = sizeof(struct sadb_msg); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_reserved = 0; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + + return(buf + len); +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) + caddr_t buf; + caddr_t lim; + u_int32_t spi, flags; + u_int wsize, auth, enc; +{ + struct sadb_sa *p; + u_int len; + + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = spi; + p->sadb_sa_replay = wsize; + p->sadb_sa_state = SADB_SASTATE_LARVAL; + p->sadb_sa_auth = auth; + p->sadb_sa_encrypt = enc; + p->sadb_sa_flags = flags; + + return(buf + len); +} + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + * prefixlen is in bits. + */ +static caddr_t +pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + caddr_t lim; + u_int exttype; + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + struct sadb_address *p; + u_int len; + + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype & 0xffff; + p->sadb_address_proto = ul_proto & 0xff; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + memcpy(p + 1, saddr, saddr->sa_len); + + return(buf + len); +} + +/* + * set sadb_key structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadbkey(buf, lim, type, key, keylen) + caddr_t buf; + caddr_t lim; + caddr_t key; + u_int type, keylen; +{ + struct sadb_key *p; + u_int len; + + p = (struct sadb_key *)buf; + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_key_len = PFKEY_UNIT64(len); + p->sadb_key_exttype = type; + p->sadb_key_bits = keylen << 3; + p->sadb_key_reserved = 0; + + memcpy(p + 1, key, keylen); + + return buf + len; +} + +/* + * set sadb_lifetime structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) + caddr_t buf; + caddr_t lim; + u_int type; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; +{ + struct sadb_lifetime *p; + u_int len; + + p = (struct sadb_lifetime *)buf; + len = sizeof(struct sadb_lifetime); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_lifetime_len = PFKEY_UNIT64(len); + p->sadb_lifetime_exttype = type; + + switch (type) { + case SADB_EXT_LIFETIME_SOFT: + p->sadb_lifetime_allocations + = (l_alloc * soft_lifetime_allocations_rate) /100; + p->sadb_lifetime_bytes + = (l_bytes * soft_lifetime_bytes_rate) /100; + p->sadb_lifetime_addtime + = (l_addtime * soft_lifetime_addtime_rate) /100; + p->sadb_lifetime_usetime + = (l_usetime * soft_lifetime_usetime_rate) /100; + break; + case SADB_EXT_LIFETIME_HARD: + p->sadb_lifetime_allocations = l_alloc; + p->sadb_lifetime_bytes = l_bytes; + p->sadb_lifetime_addtime = l_addtime; + p->sadb_lifetime_usetime = l_usetime; + break; + } + + return buf + len; +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbxsa2(buf, lim, mode0, reqid) + caddr_t buf; + caddr_t lim; + u_int32_t mode0; + u_int32_t reqid; +{ + struct sadb_x_sa2 *p; + u_int8_t mode = mode0 & 0xff; + u_int len; + + p = (struct sadb_x_sa2 *)buf; + len = sizeof(struct sadb_x_sa2); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_sa2_len = PFKEY_UNIT64(len); + p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + p->sadb_x_sa2_mode = mode; + p->sadb_x_sa2_reqid = reqid; + + return(buf + len); +} diff --git a/racoon.tproj/pfkey_dump.c b/racoon.tproj/pfkey_dump.c new file mode 100644 index 0000000..485ed46 --- /dev/null +++ b/racoon.tproj/pfkey_dump.c @@ -0,0 +1,596 @@ +/* $FreeBSD: src/lib/libipsec/pfkey_dump.c,v 1.1.2.2 2001/07/03 11:01:15 ume Exp $ */ +/* $KAME: pfkey_dump.c,v 1.27 2001/03/12 09:03:38 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +/* cope with old kame headers - ugly */ +#ifndef SADB_X_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#endif +#ifndef SADB_X_AALG_SHA +#define SADB_X_AALG_SHA SADB_AALG_SHA +#endif +#ifndef SADB_X_AALG_NULL +#define SADB_X_AALG_NULL SADB_AALG_NULL +#endif + +#ifndef SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC +#endif +#ifndef SADB_X_EALG_CAST128CBC +#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC +#endif +#ifndef SADB_X_EALG_RC5CBC +#ifdef SADB_EALG_RC5CBC +#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC +#endif +#endif + +#define GETMSGSTR(str, num) \ +do { \ + if (sizeof((str)[0]) == 0 \ + || num >= sizeof(str)/sizeof((str)[0])) \ + printf("%d ", (num)); \ + else if (strlen((str)[(num)]) == 0) \ + printf("%d ", (num)); \ + else \ + printf("%s ", (str)[(num)]); \ +} while (0) + +#define GETMSGV2S(v2s, num) \ +do { \ + struct val2str *p; \ + for (p = (v2s); p && p->str; p++) { \ + if (p->val == (num)) \ + break; \ + } \ + if (p && p->str) \ + printf("%s ", p->str); \ + else \ + printf("%d ", (num)); \ +} while (0) + +static char *str_ipaddr __P((struct sockaddr *)); +static char *str_prefport __P((u_int, u_int, u_int)); +static char *str_time __P((time_t)); +static void str_lifetime_byte __P((struct sadb_lifetime *, char *)); + +struct val2str { + int val; + const char *str; +}; + +/* + * Must to be re-written about following strings. + */ +static char *str_satype[] = { + "unspec", + "unknown", + "ah", + "esp", + "unknown", + "rsvp", + "ospfv2", + "ripv2", + "mip", + "ipcomp", +}; + +static char *str_mode[] = { + "any", + "transport", + "tunnel", +}; + +static char *str_upper[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + "", "tcp", "", "egp", "", +/*10*/ "", "", "", "", "", + "", "", "udp", "", "", +/*20*/ "", "", "idp", "", "", + "", "", "", "", "tp", +/*30*/ "", "", "", "", "", + "", "", "", "", "", +/*40*/ "", "ip6", "", "rt6", "frag6", + "", "rsvp", "gre", "", "", +/*50*/ "esp", "ah", "", "", "", + "", "", "", "icmp6", "none", +/*60*/ "dst6", +}; + +static char *str_state[] = { + "larval", + "mature", + "dying", + "dead", +}; + +static struct val2str str_alg_auth[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_enc[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, +#ifdef SADB_X_EALG_RC5CBC + { SADB_X_EALG_RC5CBC, "rc5-cbc", }, +#endif + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_RIJNDAELCBC + { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, +#endif +#ifdef SADB_X_EALG_TWOFISHCBC + { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_comp[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL, }, +}; + +/* + * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). + */ +void +pfkey_sadump(m) + struct sadb_msg *m; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_sa *m_sa; + struct sadb_x_sa2 *m_sa2; + struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; + struct sadb_address *m_saddr, *m_daddr, *m_paddr; + struct sadb_key *m_auth, *m_enc; + struct sadb_ident *m_sid, *m_did; + struct sadb_sens *m_sens; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2]; + m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; + m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + m_paddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_PROXY]; + m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; + m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; + m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; + m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; + m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY]; + + /* source address */ + if (m_saddr == NULL) { + printf("no ADDRESS_SRC extension.\n"); + return; + } + printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1))); + + /* destination address */ + if (m_daddr == NULL) { + printf("no ADDRESS_DST extension.\n"); + return; + } + printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1))); + + /* SA type */ + if (m_sa == NULL) { + printf("no SA extension.\n"); + return; + } + if (m_sa2 == NULL) { + printf("no SA2 extension.\n"); + return; + } + printf("\n\t"); + + GETMSGSTR(str_satype, m->sadb_msg_satype); + + printf("mode="); + GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); + + printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)m_sa2->sadb_x_sa2_reqid, + (u_int32_t)m_sa2->sadb_x_sa2_reqid); + + /* encryption key */ + if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { + printf("\tC: "); + GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt); + } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) { + if (m_enc != NULL) { + printf("\tE: "); + GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt); + ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc), + m_enc->sadb_key_bits / 8); + printf("\n"); + } + } + + /* authentication key */ + if (m_auth != NULL) { + printf("\tA: "); + GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth); + ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth), + m_auth->sadb_key_bits / 8); + printf("\n"); + } + + /* replay windoe size & flags */ + printf("\treplay=%u flags=0x%08x ", + m_sa->sadb_sa_replay, + m_sa->sadb_sa_flags); + + /* state */ + printf("state="); + GETMSGSTR(str_state, m_sa->sadb_sa_state); + + printf("seq=%lu pid=%lu\n", + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* lifetime */ + if (m_lftc != NULL) { + time_t tmp_time = time(0); + + printf("\tcreated: %s", + str_time(m_lftc->sadb_lifetime_addtime)); + printf("\tcurrent: %s\n", str_time(tmp_time)); + printf("\tdiff: %lu(s)", + (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? + 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); + + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_addtime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_addtime)); + + printf("\tlast: %s", + str_time(m_lftc->sadb_lifetime_usetime)); + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_usetime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_usetime)); + + str_lifetime_byte(m_lftc, "current"); + str_lifetime_byte(m_lfth, "hard"); + str_lifetime_byte(m_lfts, "soft"); + printf("\n"); + + printf("\tallocated: %lu", + (unsigned long)m_lftc->sadb_lifetime_allocations); + printf("\thard: %lu", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_allocations)); + printf("\tsoft: %lu\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_allocations)); + } + + /* XXX DEBUG */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +void +pfkey_spdump(m) + struct sadb_msg *m; +{ + char pbuf[NI_MAXSERV]; + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_address *m_saddr, *m_daddr; + struct sadb_x_policy *m_xpl; + struct sadb_lifetime *m_lft = NULL; + struct sockaddr *sa; + u_int16_t port; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + m_lft = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + + /* source address */ + if (m_saddr == NULL) { + printf("no ADDRESS_SRC extension.\n"); + return; + } + sa = (struct sockaddr *)(m_saddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_saddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } + + /* destination address */ + if (m_daddr == NULL) { + printf("no ADDRESS_DST extension.\n"); + return; + } + sa = (struct sockaddr *)(m_daddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_daddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } + + /* upper layer protocol */ + if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { + printf("upper layer protocol mismatched.\n"); + return; + } + if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY) + printf("any"); + else + GETMSGSTR(str_upper, m_saddr->sadb_address_proto); + + /* policy */ + { + char *d_xpl; + + if (m_xpl == NULL) { + printf("no X_POLICY extension.\n"); + return; + } + d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t"); + + /* dump SPD */ + printf("\n\t%s\n", d_xpl); + free(d_xpl); + } + + /* lifetime */ + if (m_lft) { + printf("\tlifetime:%lu validtime:%lu\n", + (u_long)m_lft->sadb_lifetime_addtime, + (u_long)m_lft->sadb_lifetime_usetime); + } + + printf("\tspid=%ld seq=%ld pid=%ld\n", + (u_long)m_xpl->sadb_x_policy_id, + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* XXX TEST */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +/* + * set "ipaddress" to buffer. + */ +static char * +str_ipaddr(sa) + struct sockaddr *sa; +{ + static char buf[NI_MAXHOST]; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif + + if (sa == NULL) + return ""; + + if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, niflag) == 0) + return buf; + return NULL; +} + +/* + * set "/prefix[port number]" to buffer. + */ +static char * +str_prefport(family, pref, port) + u_int family, pref, port; +{ + static char buf[128]; + char prefbuf[10]; + char portbuf[10]; + int plen; + + switch (family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + return "?"; + } + + if (pref == plen) + prefbuf[0] = '\0'; + else + snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); + + if (port == IPSEC_PORT_ANY) + snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); + else + snprintf(portbuf, sizeof(portbuf), "[%u]", port); + + snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); + + return buf; +} + +/* + * set "Mon Day Time Year" to buffer + */ +static char * +str_time(t) + time_t t; +{ + static char buf[128]; + + if (t == 0) { + int i = 0; + for (;i < 20;) buf[i++] = ' '; + } else { + char *t0; + t0 = ctime(&t); + memcpy(buf, t0 + 4, 20); + } + + buf[20] = '\0'; + + return(buf); +} + +static void +str_lifetime_byte(x, str) + struct sadb_lifetime *x; + char *str; +{ + double y; + char *unit; + int w; + + if (x == NULL) { + printf("\t%s: 0(bytes)", str); + return; + } + +#if 0 + if ((x->sadb_lifetime_bytes) / 1024 / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024; + unit = "M"; + w = 1; + } else if ((x->sadb_lifetime_bytes) / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024; + unit = "K"; + w = 1; + } else { + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; + } +#else + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; +#endif + printf("\t%s: %.*f(%sbytes)", str, w, y, unit); +} diff --git a/racoon.tproj/plog.c b/racoon.tproj/plog.c new file mode 100644 index 0000000..d864f1c --- /dev/null +++ b/racoon.tproj/plog.c @@ -0,0 +1,219 @@ +/* $KAME: plog.c,v 1.19 2001/09/23 12:40:32 itojun 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. 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. + */ + +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#include + +#include "var.h" +#include "misc.h" +#include "plog.h" +#include "logger.h" +#include "debug.h" +#include "gcmalloc.h" + +char *pname = NULL; +u_int32_t loglevel = LLV_BASE; + +static struct log *logp = NULL; +static char *logfile = NULL; + +static char *plog_common __P((int, const char *, const char *)); + +static struct plogtags { + char *name; + int priority; +} ptab[] = { + { "(not defined)", 0, }, + { "INFO", LOG_INFO, }, + { "NOTIFY", LOG_INFO, }, + { "WARNING", LOG_INFO, }, + { "ERROR", LOG_INFO, }, + { "DEBUG", LOG_DEBUG, }, + { "DEBUG2", LOG_DEBUG, }, +}; + +static char * +plog_common(pri, fmt, func) + int pri; + const char *fmt, *func; +{ + static char buf[800]; /* XXX shoule be allocated every time ? */ + char *p; + int reslen, len; + + p = buf; + reslen = sizeof(buf); + + if (logfile || f_foreground) { + time_t t; + struct tm *tm; + + t = time(0); + tm = localtime(&t); + len = strftime(p, reslen, "%Y-%m-%d %T: ", tm); + p += len; + reslen -= len; + } + + if (pri < ARRAYLEN(ptab)) { + len = snprintf(p, reslen, "%s: ", ptab[pri].name); + if (len >= 0 && len < reslen) { + p += len; + reslen -= len; + } else + *p = '\0'; + } + + snprintf(p, reslen, "%s: %s", func, fmt); + + return buf; +} + +void +plog(int pri, const char *func, struct sockaddr *sa, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + plogv(pri, func, sa, fmt, ap); + va_end(ap); +} + +void +plogv(int pri, const char *func, struct sockaddr *sa, + const char *fmt, va_list ap) +{ + char *newfmt; + + if (pri > loglevel) + return; + + newfmt = plog_common(pri, fmt, func); + + if (f_foreground) + vprintf(newfmt, ap); + + if (logfile) + log_vaprint(logp, newfmt, ap); + else { + if (pri < ARRAYLEN(ptab)) + vsyslog(ptab[pri].priority, newfmt, ap); + else + vsyslog(LOG_ALERT, newfmt, ap); + } +} + +void +plogdump(pri, data, len) + int pri; + void *data; + size_t len; +{ + caddr_t buf; + size_t buflen; + int i, j; + + if (pri > loglevel) + return; + + /* + * 2 words a bytes + 1 space 4 bytes + 1 newline 32 bytes + * + 2 newline + '\0' + */ + buflen = (len * 2) + (len / 4) + (len / 32) + 3; + buf = racoon_malloc(buflen); + + i = 0; + j = 0; + while (j < len) { + if (j % 32 == 0) + buf[i++] = '\n'; + else + if (j % 4 == 0) + buf[i++] = ' '; + snprintf(&buf[i], buflen - i, "%02x", + ((unsigned char *)data)[j] & 0xff); + i += 2; + j++; + } + if (buflen - i >= 2) { + buf[i++] = '\n'; + buf[i] = '\0'; + } + plog(pri, LOCATION, NULL, "%s", buf); + + racoon_free(buf); +} + +void +ploginit() +{ + if (logfile) { + logp = log_open(250, logfile); + if (logp == NULL) + errx(1, "ERROR: failed to open log file %s.", logfile); + return; + } + + openlog(pname, LOG_NDELAY, LOG_DAEMON); +} + +void +plogset(file) + char *file; +{ + if (logfile != NULL) + racoon_free(logfile); + logfile = strdup(file); +} + diff --git a/racoon.tproj/plog.h b/racoon.tproj/plog.h new file mode 100644 index 0000000..a8d21b4 --- /dev/null +++ b/racoon.tproj/plog.h @@ -0,0 +1,68 @@ +/* $KAME: plog.h,v 1.7 2001/01/10 02:58:58 sakane 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. 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. + */ + +#define LC_DEFAULT_LOGF "/var/log/racoon.log" + +#ifdef HAVE_STDARG_H +#include +#else +#include +#endif +#include + +/* + * INFO: begin negotiation, SA establishment/deletion/expiration. + * NOTIFY: just notifiable. + * WARNING: not error strictly. + * ERROR: system call error. also invalid parameter/format. + * DEBUG1: debugging informatioin. + * DEBUG2: too more verbose. e.g. parsing config. + */ +#define LLV_INFO 1 +#define LLV_NOTIFY 2 +#define LLV_WARNING 3 +#define LLV_ERROR 4 +#define LLV_DEBUG 5 +#define LLV_DEBUG2 6 + +#define LLV_BASE 4 /* always logging less than this value. */ + +extern char *pname; +extern u_int32_t loglevel; +extern int f_foreground; + +struct sockaddr; +extern void plog __P((int, const char *, struct sockaddr *, const char *, ...)); +extern void plogv __P((int, const char *, struct sockaddr *, + const char *, va_list)); +extern void plogdump __P((int, void *, size_t)); +extern void ploginit __P((void)); +extern void plogset __P((char *)); diff --git a/racoon.tproj/policy.c b/racoon.tproj/policy.c new file mode 100644 index 0000000..7ab1e5f --- /dev/null +++ b/racoon.tproj/policy.c @@ -0,0 +1,416 @@ +/* $KAME: policy.c,v 1.45 2001/10/16 14:55:57 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "policy.h" +#include "localconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "strnames.h" +#include "gcmalloc.h" + +static TAILQ_HEAD(_sptree, secpolicy) sptree; + +/* perform exact match against security policy table. */ +struct secpolicy * +getsp(spidx) + struct policyindex *spidx; +{ + struct secpolicy *p; + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (!cmpspidxstrict(spidx, &p->spidx)) + return p; + } + + return NULL; +} + +/* + * perform non-exact match against security policy table, only if this is + * transport mode SA negotiation. for example, 0.0.0.0/0 -> 0.0.0.0/0 + * entry in policy.txt can be returned when we're negotiating transport + * mode SA. this is how the kernel works. + */ +#if 1 +struct secpolicy * +getsp_r(spidx) + struct policyindex *spidx; +{ + struct secpolicy *p; + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (!cmpspidxwild(spidx, &p->spidx)) + return p; + } + + return NULL; +} +#else +struct secpolicy * +getsp_r(spidx, iph2) + struct policyindex *spidx; + struct ph2handle *iph2; +{ + struct secpolicy *p; + u_int8_t prefixlen; + + plog(LLV_DEBUG, LOCATION, NULL, "checking for transport mode\n"); + + if (spidx->src.ss_family != spidx->dst.ss_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch, src:%d dst:%d\n", + spidx->src.ss_family, + spidx->dst.ss_family); + return NULL; + } + switch (spidx->src.ss_family) { + case AF_INET: + prefixlen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + prefixlen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", spidx->src.ss_family); + return NULL; + } + + /* is it transport mode SA negotiation? */ + plog(LLV_DEBUG, LOCATION, NULL, "src1: %s\n", + saddr2str(iph2->src)); + plog(LLV_DEBUG, LOCATION, NULL, "src2: %s\n", + saddr2str((struct sockaddr *)&spidx->src)); + if (cmpsaddrwop(iph2->src, (struct sockaddr *)&spidx->src) + || spidx->prefs != prefixlen) + return NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "dst1: %s\n", + saddr2str(iph2->dst)); + plog(LLV_DEBUG, LOCATION, NULL, "dst2: %s\n", + saddr2str((struct sockaddr *)&spidx->dst)); + if (cmpsaddrwop(iph2->dst, (struct sockaddr *)&spidx->dst) + || spidx->prefd != prefixlen) + return NULL; + + plog(LLV_DEBUG, LOCATION, NULL, "looks to be transport mode\n"); + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (!cmpspidx_wild(spidx, &p->spidx)) + return p; + } + + return NULL; +} +#endif + +struct secpolicy * +getspbyspid(spid) + u_int32_t spid; +{ + struct secpolicy *p; + + for (p = TAILQ_FIRST(&sptree); p; p = TAILQ_NEXT(p, chain)) { + if (p->id == spid) + return p; + } + + return NULL; +} + +/* + * compare policyindex. + * a: subject b: db + * OUT: 0: equal + * 1: not equal + */ +int +cmpspidxstrict(a, b) + struct policyindex *a, *b; +{ + plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a)); + plog(LLV_DEBUG, LOCATION, NULL, "db :%p: %s\n", b, spidx2str(b)); + + /* XXX don't check direction now, but it's to be checked carefully. */ + if (a->dir != b->dir + || a->prefs != b->prefs + || a->prefd != b->prefd + || a->ul_proto != b->ul_proto) + return 1; + + if (cmpsaddrstrict((struct sockaddr *)&a->src, + (struct sockaddr *)&b->src)) + return 1; + if (cmpsaddrstrict((struct sockaddr *)&a->dst, + (struct sockaddr *)&b->dst)) + return 1; + + return 0; +} + +/* + * compare policyindex, with wildcard address/protocol match. + * a: subject b: db, can contain wildcard things. + * OUT: 0: equal + * 1: not equal + */ +int +cmpspidxwild(a, b) + struct policyindex *a, *b; +{ + struct sockaddr_storage sa1, sa2; + + plog(LLV_DEBUG, LOCATION, NULL, "sub:%p: %s\n", a, spidx2str(a)); + plog(LLV_DEBUG, LOCATION, NULL, "db: %p: %s\n", b, spidx2str(b)); + + if (!(b->dir == IPSEC_DIR_ANY || a->dir == b->dir)) + return 1; + + if (!(a->ul_proto == IPSEC_ULPROTO_ANY || + b->ul_proto == IPSEC_ULPROTO_ANY || + a->ul_proto == b->ul_proto)) + return 1; + + if (a->src.ss_family != b->src.ss_family) + return 1; + if (a->dst.ss_family != b->dst.ss_family) + return 1; + + /* compare src address */ + if (sizeof(sa1) < a->src.ss_len || sizeof(sa2) < b->src.ss_len) { + plog(LLV_ERROR, LOCATION, NULL, + "unexpected error: " + "src.ss_len:%d dst.ss_len:%d\n", + a->src.ss_len, b->src.ss_len); + return 1; + } + mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->src, + b->prefs); + mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->src, + b->prefs); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + a, b->prefs, saddr2str((struct sockaddr *)&sa1)); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + b, b->prefs, saddr2str((struct sockaddr *)&sa2)); + if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2)) + return 1; + + /* compare dst address */ + if (sizeof(sa1) < a->dst.ss_len || sizeof(sa2) < b->dst.ss_len) { + plog(LLV_ERROR, LOCATION, NULL, "unexpected error\n"); + exit(1); + } + mask_sockaddr((struct sockaddr *)&sa1, (struct sockaddr *)&a->dst, + b->prefd); + mask_sockaddr((struct sockaddr *)&sa2, (struct sockaddr *)&b->dst, + b->prefd); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + a, b->prefd, saddr2str((struct sockaddr *)&sa1)); + plog(LLV_DEBUG, LOCATION, NULL, "%p masked with /%d: %s\n", + b, b->prefd, saddr2str((struct sockaddr *)&sa2)); + if (cmpsaddrwild((struct sockaddr *)&sa1, (struct sockaddr *)&sa2)) + return 1; + + return 0; +} + +struct secpolicy * +newsp() +{ + struct secpolicy *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +void +delsp(sp) + struct secpolicy *sp; +{ + struct ipsecrequest *req = NULL, *next; + + for (req = sp->req; req; req = next) { + next = req->next; + racoon_free(req); + } + + racoon_free(sp); +} + +void +delsp_bothdir(spidx0) + struct policyindex *spidx0; +{ + struct policyindex spidx; + struct secpolicy *sp; + struct sockaddr_storage addr; + u_int8_t pref; + + memcpy(&spidx, spidx0, sizeof(spidx)); + + sp = getsp(&spidx); + if (sp) { + remsp(sp); + delsp(sp); + } + + spidx.dir = spidx.dir == IPSEC_DIR_OUTBOUND + ? IPSEC_DIR_INBOUND + : IPSEC_DIR_OUTBOUND ; + addr = spidx.src; + spidx.src = spidx.dst; + spidx.dst = addr; + pref = spidx.prefs; + spidx.prefs = spidx.prefd; + spidx.prefd = pref; + + sp = getsp(&spidx); + if (sp) { + remsp(sp); + delsp(sp); + } +} + +void +inssp(new) + struct secpolicy *new; +{ + TAILQ_INSERT_TAIL(&sptree, new, chain); +} + +void +remsp(sp) + struct secpolicy *sp; +{ + TAILQ_REMOVE(&sptree, sp, chain); +} + +void +flushsp() +{ + struct secpolicy *p, *next; + + for (p = TAILQ_FIRST(&sptree); p; p = next) { + next = TAILQ_NEXT(p, chain); + remsp(p); + delsp(p); + } +} + +void +initsp() +{ + TAILQ_INIT(&sptree); +} + +struct ipsecrequest * +newipsecreq() +{ + struct ipsecrequest *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +const char * +spidx2str(spidx) + const struct policyindex *spidx; +{ + /* addr/pref[port] addr/pref[port] ul dir act */ + static char buf[256]; + char *p, *a, *b; + int blen, i; + + blen = sizeof(buf) - 1; + p = buf; + + a = saddr2str((const struct sockaddr *)&spidx->src); + for (b = a; *b != '\0'; b++) + if (*b == '[') { + *b = '\0'; + b++; + break; + } + i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefs, b); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + a = saddr2str((const struct sockaddr *)&spidx->dst); + for (b = a; *b != '\0'; b++) + if (*b == '[') { + *b = '\0'; + b++; + break; + } + i = snprintf(p, blen, "%s/%d[%s ", a, spidx->prefd, b); + if (i < 0 || i >= blen) + return NULL; + p += i; + blen -= i; + + snprintf(p, blen, "proto=%s dir=%s", + s_proto(spidx->ul_proto), s_direction(spidx->dir)); + + return buf; +} diff --git a/racoon.tproj/policy.h b/racoon.tproj/policy.h new file mode 100644 index 0000000..a9bd525 --- /dev/null +++ b/racoon.tproj/policy.h @@ -0,0 +1,115 @@ +/* $KAME: policy.h,v 1.17 2001/06/27 15:55:58 sakane 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. 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. + */ + +#include + +/* refs. ipsec.h */ +/* + * Security Policy Index + * NOTE: Ensure to be same address family and upper layer protocol. + * NOTE: ul_proto, port number, uid, gid: + * ANY: reserved for waldcard. + * 0 to (~0 - 1): is one of the number of each value. + */ +struct policyindex { + u_int8_t dir; /* direction of packet flow, see blow */ + struct sockaddr_storage src; /* IP src address for SP */ + struct sockaddr_storage dst; /* IP dst address for SP */ + u_int8_t prefs; /* prefix length in bits for src */ + u_int8_t prefd; /* prefix length in bits for dst */ + u_int16_t ul_proto; /* upper layer Protocol */ +}; + +/* Security Policy Data Base */ +struct secpolicy { + TAILQ_ENTRY(secpolicy) chain; + + struct policyindex spidx; /* selector */ + u_int32_t id; /* It's unique number on the system. */ + + u_int policy; /* DISCARD, NONE or IPSEC, see keyv2.h */ + struct ipsecrequest *req; + /* pointer to the ipsec request tree, */ + /* if policy == IPSEC else this value == NULL.*/ +}; + +/* Security Assocciation Index */ +/* NOTE: Ensure to be same address family */ +struct secasindex { + struct sockaddr_storage src; /* srouce address for SA */ + struct sockaddr_storage dst; /* destination address for SA */ + u_int16_t proto; /* IPPROTO_ESP or IPPROTO_AH */ + u_int8_t mode; /* mode of protocol, see ipsec.h */ + u_int32_t reqid; /* reqid id who owned this SA */ + /* see IPSEC_MANUAL_REQID_MAX. */ +}; + +/* Request for IPsec */ +struct ipsecrequest { + struct ipsecrequest *next; + /* pointer to next structure */ + /* If NULL, it means the end of chain. */ + + struct secasindex saidx;/* hint for search proper SA */ + /* if __ss_len == 0 then no address specified.*/ + u_int level; /* IPsec level defined below. */ + + struct secpolicy *sp; /* back pointer to SP */ +}; + +#define KEY_SETSECSPIDX(_dir, s, d, ps, pd, ulp, idx) \ +do { \ + bzero((idx), sizeof(struct policyindex)); \ + (idx)->dir = (_dir); \ + (idx)->prefs = (ps); \ + (idx)->prefd = (pd); \ + (idx)->ul_proto = (ulp); \ + memcpy(&(idx)->src, (s), ((struct sockaddr *)(s))->sa_len); \ + memcpy(&(idx)->dst, (d), ((struct sockaddr *)(d))->sa_len); \ +} while (0) + +struct ph2handle; +struct policyindex; +extern struct secpolicy *getsp __P((struct policyindex *)); +extern struct secpolicy *getsp_r __P((struct policyindex *)); +struct secpolicy *getspbyspid __P((u_int32_t)); +extern int cmpspidxstrict __P((struct policyindex *, struct policyindex *)); +extern int cmpspidxwild __P((struct policyindex *, struct policyindex *)); +extern struct secpolicy *newsp __P((void)); +extern void delsp __P((struct secpolicy *)); +extern void delsp_bothdir __P((struct policyindex *)); +extern void inssp __P((struct secpolicy *)); +extern void remsp __P((struct secpolicy *)); +extern void flushsp __P((void)); +extern void initsp __P((void)); +extern struct ipsecrequest *newipsecreq __P((void)); + +extern const char *spidx2str __P((const struct policyindex *)); diff --git a/racoon.tproj/proposal.c b/racoon.tproj/proposal.c new file mode 100644 index 0000000..bb284f9 --- /dev/null +++ b/racoon.tproj/proposal.c @@ -0,0 +1,1113 @@ +/* $KAME: proposal.c,v 1.45 2001/11/16 04:08:10 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "policy.h" +#include "pfkey.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "algorithm.h" +#include "proposal.h" +#include "sainfo.h" +#include "localconf.h" +#include "remoteconf.h" +#include "oakley.h" +#include "handler.h" +#include "strnames.h" +#include "gcmalloc.h" + +/* %%% + * modules for ipsec sa spec + */ +struct saprop * +newsaprop() +{ + struct saprop *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +struct saproto * +newsaproto() +{ + struct saproto *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +/* set saprop to last part of the prop tree */ +void +inssaprop(head, new) + struct saprop **head; + struct saprop *new; +{ + struct saprop *p; + + if (*head == NULL) { + *head = new; + return; + } + + for (p = *head; p->next; p = p->next) + ; + p->next = new; + + return; +} + +/* set saproto to the end of the proto tree in saprop */ +void +inssaproto(pp, new) + struct saprop *pp; + struct saproto *new; +{ + struct saproto *p; + + for (p = pp->head; p && p->next; p = p->next) + ; + if (p == NULL) + pp->head = new; + else + p->next = new; + + return; +} + +/* set saproto to the top of the proto tree in saprop */ +void +inssaprotorev(pp, new) + struct saprop *pp; + struct saproto *new; +{ + new->next = pp->head; + pp->head = new; + + return; +} + +struct satrns * +newsatrns() +{ + struct satrns *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +/* set saproto to last part of the proto tree in saprop */ +void +inssatrns(pr, new) + struct saproto *pr; + struct satrns *new; +{ + struct satrns *tr; + + for (tr = pr->head; tr && tr->next; tr = tr->next) + ; + if (tr == NULL) + pr->head = new; + else + tr->next = new; + + return; +} + +/* + * take a single match between saprop. allocate a new proposal and return it + * for future use (like picking single proposal from a bundle). + * pp1: peer's proposal. + * pp2: my proposal. + * NOTE: In the case of initiator, must be ensured that there is no + * modification of the proposal by calling cmp_aproppair_i() before + * this function. + * XXX cannot understand the comment! + */ +struct saprop * +cmpsaprop_alloc(ph1, pp1, pp2, side) + struct ph1handle *ph1; + const struct saprop *pp1, *pp2; + int side; +{ + struct saprop *newpp = NULL; + struct saproto *pr1, *pr2, *newpr = NULL; + struct satrns *tr1, *tr2, *newtr; + const int ordermatters = 0; + int npr1, npr2; + int spisizematch; + + newpp = newsaprop(); + if (newpp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + return NULL; + } + newpp->prop_no = pp1->prop_no; + + /* see proposal.h about lifetime/key length and PFS selection. */ + + /* check time/bytes lifetime and PFS */ + switch (ph1->rmconf->pcheck_level) { + case PROP_CHECK_OBEY: + newpp->lifetime = pp1->lifetime; + newpp->lifebyte = pp1->lifebyte; + newpp->pfs_group = pp1->pfs_group; + break; + case PROP_CHECK_STRICT: + if (pp1->lifetime > pp2->lifetime) { + plog(LLV_ERROR, LOCATION, NULL, + "long lifetime proposed: " + "my:%d peer:%d\n", + pp2->lifetime, pp1->lifetime); + goto err; + } + if (pp1->lifebyte > pp2->lifebyte) { + plog(LLV_ERROR, LOCATION, NULL, + "long lifebyte proposed: " + "my:%d peer:%d\n", + pp2->lifebyte, pp1->lifebyte); + goto err; + } + newpp->lifetime = pp1->lifetime; + newpp->lifebyte = pp1->lifebyte; + + prop_pfs_check: + if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) { + plog(LLV_ERROR, LOCATION, NULL, + "pfs group mismatched: " + "my:%d peer:%d\n", + pp2->pfs_group, pp1->pfs_group); + goto err; + } + newpp->pfs_group = pp1->pfs_group; + break; + case PROP_CHECK_CLAIM: + /* lifetime */ + if (pp1->lifetime <= pp2->lifetime) { + newpp->lifetime = pp1->lifetime; + } else { + newpp->lifetime = pp2->lifetime; + newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC; + plog(LLV_NOTIFY, LOCATION, NULL, + "use own lifetime: " + "my:%d peer:%d\n", + pp2->lifetime, pp1->lifetime); + } + + /* lifebyte */ + if (pp1->lifebyte > pp2->lifebyte) { + newpp->lifebyte = pp2->lifebyte; + newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC; + plog(LLV_NOTIFY, LOCATION, NULL, + "use own lifebyte: " + "my:%d peer:%d\n", + pp2->lifebyte, pp1->lifebyte); + } + newpp->lifebyte = pp1->lifebyte; + + goto prop_pfs_check; + break; + case PROP_CHECK_EXACT: + if (pp1->lifetime != pp2->lifetime) { + plog(LLV_ERROR, LOCATION, NULL, + "lifetime mismatched: " + "my:%d peer:%d\n", + pp2->lifetime, pp1->lifetime); + goto err; + } + if (pp1->lifebyte != pp2->lifebyte) { + plog(LLV_ERROR, LOCATION, NULL, + "lifebyte mismatched: " + "my:%d peer:%d\n", + pp2->lifebyte, pp1->lifebyte); + goto err; + } + if (pp1->pfs_group != pp2->pfs_group) { + plog(LLV_ERROR, LOCATION, NULL, + "pfs group mismatched: " + "my:%d peer:%d\n", + pp2->pfs_group, pp1->pfs_group); + goto err; + } + newpp->lifebyte = pp1->lifebyte; + newpp->lifebyte = pp1->lifebyte; + newpp->pfs_group = pp1->pfs_group; + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid pcheck_level why?.\n"); + goto err; + } + + npr1 = npr2 = 0; + for (pr1 = pp1->head; pr1; pr1 = pr1->next) + npr1++; + for (pr2 = pp2->head; pr2; pr2 = pr2->next) + npr2++; + if (npr1 != npr2) + goto err; + + /* check protocol order */ + pr1 = pp1->head; + pr2 = pp2->head; + + while (1) { + if (!ordermatters) { + /* + * XXX does not work if we have multiple proposals + * with the same proto_id + */ + switch (side) { + case RESPONDER: + if (!pr2) + break; + for (pr1 = pp1->head; pr1; pr1 = pr1->next) { + if (pr1->proto_id == pr2->proto_id) + break; + } + break; + case INITIATOR: + if (!pr1) + break; + for (pr2 = pp2->head; pr2; pr2 = pr2->next) { + if (pr2->proto_id == pr1->proto_id) + break; + } + break; + } + } + if (!pr1 || !pr2) + break; + + if (pr1->proto_id != pr2->proto_id) { + plog(LLV_ERROR, LOCATION, NULL, + "proto_id mismatched: " + "my:%d peer:%d\n", + pr2->proto_id, pr1->proto_id); + goto err; + } + spisizematch = 0; + if (pr1->spisize == pr2->spisize) + spisizematch = 1; + else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) { + /* + * draft-shacham-ippcp-rfc2393bis-05.txt: + * need to accept 16bit and 32bit SPI (CPI) for IPComp. + */ + if (pr1->spisize == sizeof(u_int16_t) && + pr2->spisize == sizeof(u_int32_t)) { + spisizematch = 1; + } else if (pr1->spisize == sizeof(u_int16_t) && + pr2->spisize == sizeof(u_int32_t)) { + spisizematch = 1; + } + if (spisizematch) { + plog(LLV_ERROR, LOCATION, NULL, + "IPComp SPI size promoted " + "from 16bit to 32bit\n"); + } + } + if (!spisizematch) { + plog(LLV_ERROR, LOCATION, NULL, + "spisize mismatched: " + "my:%d peer:%d\n", + pr2->spisize, pr1->spisize); + goto err; + } + if (pr1->encmode != pr2->encmode) { + plog(LLV_ERROR, LOCATION, NULL, + "encmode mismatched: " + "my:%d peer:%d\n", + pr2->encmode, pr1->encmode); + goto err; + } + + for (tr1 = pr1->head; tr1; tr1 = tr1->next) { + for (tr2 = pr2->head; tr2; tr2 = tr2->next) { + if (cmpsatrns(tr1, tr2) == 0) + goto found; + } + } + + goto err; + + found: + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto err; + } + newpr->proto_id = pr1->proto_id; + newpr->spisize = pr1->spisize; + newpr->encmode = pr1->encmode; + newpr->spi = pr2->spi; /* copy my SPI */ + newpr->spi_p = pr1->spi; /* copy peer's SPI */ + newpr->reqid_in = pr2->reqid_in; + newpr->reqid_out = pr2->reqid_out; + + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + newtr->trns_no = tr1->trns_no; + newtr->trns_id = tr1->trns_id; + newtr->encklen = tr1->encklen; + newtr->authtype = tr1->authtype; + + inssatrns(newpr, newtr); + inssaproto(newpp, newpr); + + pr1 = pr1->next; + pr2 = pr2->next; + } + + /* XXX should check if we have visited all items or not */ + if (!ordermatters) { + switch (side) { + case RESPONDER: + if (!pr2) + pr1 = NULL; + break; + case INITIATOR: + if (!pr1) + pr2 = NULL; + break; + } + } + + /* should be matched all protocols in a proposal */ + if (pr1 != NULL || pr2 != NULL) + goto err; + + return newpp; + +err: + flushsaprop(newpp); + return NULL; +} + +/* take a single match between saprop. returns 0 if pp1 equals to pp2. */ +int +cmpsaprop(pp1, pp2) + const struct saprop *pp1, *pp2; +{ + if (pp1->pfs_group != pp2->pfs_group) { + plog(LLV_WARNING, LOCATION, NULL, + "pfs_group mismatch. mine:%d peer:%d\n", + pp1->pfs_group, pp2->pfs_group); + /* FALLTHRU */ + } + + if (pp1->lifetime > pp2->lifetime) { + plog(LLV_WARNING, LOCATION, NULL, + "less lifetime proposed. mine:%d peer:%d\n", + pp1->lifetime, pp2->lifetime); + /* FALLTHRU */ + } + if (pp1->lifebyte > pp2->lifebyte) { + plog(LLV_WARNING, LOCATION, NULL, + "less lifebyte proposed. mine:%d peer:%d\n", + pp1->lifebyte, pp2->lifebyte); + /* FALLTHRU */ + } + + return 0; +} + +/* + * take a single match between satrns. returns 0 if tr1 equals to tr2. + * tr1: peer's satrns + * tr2: my satrns + */ +int +cmpsatrns(tr1, tr2) + const struct satrns *tr1, *tr2; +{ + if (tr1->trns_id != tr2->trns_id) { + plog(LLV_ERROR, LOCATION, NULL, + "trns_id mismatched: " + "my:%d peer:%d\n", + tr2->trns_id, tr1->trns_id); + return 1; + } + if (tr1->authtype != tr2->authtype) { + plog(LLV_ERROR, LOCATION, NULL, + "authtype mismatched: " + "my:%d peer:%d\n", + tr2->authtype, tr1->authtype); + return 1; + } + + /* XXX + * At this moment for interoperability, the responder obey + * the initiator. It should be defined a notify message. + */ + if (tr1->encklen > tr2->encklen) { + plog(LLV_WARNING, LOCATION, NULL, + "less key length proposed, " + "mine:%d peer:%d. Use initiaotr's one.\n", + tr2->encklen, tr1->encklen); + /* FALLTHRU */ + } + + return 0; +} + +int +set_satrnsbysainfo(pr, sainfo) + struct saproto *pr; + struct sainfo *sainfo; +{ + struct sainfoalg *a, *b; + struct satrns *newtr; + int t; + + switch (pr->proto_id) { + case IPSECDOI_PROTO_IPSEC_AH: + if (sainfo->algs[algclass_ipsec_auth] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no auth algorithm found\n"); + goto err; + } + t = 1; + for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) { + + if (a->alg == IPSECDOI_ATTR_AUTH_NONE) + continue; + + /* allocate satrns */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + newtr->trns_no = t++; + newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg); + newtr->authtype = a->alg; + + inssatrns(pr, newtr); + } + break; + case IPSECDOI_PROTO_IPSEC_ESP: + if (sainfo->algs[algclass_ipsec_enc] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no encryption algorithm found\n"); + goto err; + } + t = 1; + for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) { + for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) { + /* allocate satrns */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + newtr->trns_no = t++; + newtr->trns_id = a->alg; + newtr->encklen = a->encklen; + newtr->authtype = b->alg; + + inssatrns(pr, newtr); + } + } + break; + case IPSECDOI_PROTO_IPCOMP: + if (sainfo->algs[algclass_ipsec_comp] == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "no ipcomp algorithm found\n"); + goto err; + } + t = 1; + for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) { + + /* allocate satrns */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + newtr->trns_no = t++; + newtr->trns_id = a->alg; + newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/ + + inssatrns(pr, newtr); + } + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "unknown proto_id (%d).\n", pr->proto_id); + goto err; + } + + /* no proposal found */ + if (pr->head == NULL) { + plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n"); + return -1; + } + + return 0; + +err: + flushsatrns(pr->head); + return -1; +} + +struct saprop * +aproppair2saprop(p0) + struct prop_pair *p0; +{ + struct prop_pair *p, *t; + struct saprop *newpp; + struct saproto *newpr; + struct satrns *newtr; + u_int8_t *spi; + + if (p0 == NULL) + return NULL; + + /* allocate ipsec a sa proposal */ + newpp = newsaprop(); + if (newpp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + return NULL; + } + newpp->prop_no = p0->prop->p_no; + /* lifetime & lifebyte must be updated later */ + + for (p = p0; p; p = p->next) { + + /* allocate ipsec sa protocol */ + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto err; + } + + /* check spi size */ + /* XXX should be handled isakmp cookie */ + if (sizeof(newpr->spi) < p->prop->spi_size) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid spi size %d.\n", p->prop->spi_size); + goto err; + } + + /* + * XXX SPI bits are left-filled, for use with IPComp. + * we should be switching to variable-length spi field... + */ + newpr->proto_id = p->prop->proto_id; + newpr->spisize = p->prop->spi_size; + memset(&newpr->spi, 0, sizeof(newpr->spi)); + spi = (u_int8_t *)&newpr->spi; + spi += sizeof(newpr->spi); + spi -= p->prop->spi_size; + memcpy(spi, p->prop + 1, p->prop->spi_size); + newpr->reqid_in = 0; + newpr->reqid_out = 0; + + for (t = p; t; t = t->tnext) { + + plog(LLV_DEBUG, LOCATION, NULL, + "prop#=%d prot-id=%s spi-size=%d " + "#trns=%d trns#=%d trns-id=%s\n", + t->prop->p_no, + s_ipsecdoi_proto(t->prop->proto_id), + t->prop->spi_size, t->prop->num_t, + t->trns->t_no, + s_ipsecdoi_trns(t->prop->proto_id, + t->trns->t_id)); + + /* allocate ipsec sa transform */ + newtr = newsatrns(); + if (newtr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate satrns.\n"); + goto err; + } + + if (ipsecdoi_t2satrns(t->trns, newpp, newpr, newtr) < 0) { + flushsaprop(newpp); + return NULL; + } + + inssatrns(newpr, newtr); + } + + /* + * If the peer does not specify encryption mode, use + * transport mode by default. This is to conform to + * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies + * that unspecified == transport), as well as RFC2407 + * (unspecified == implementation dependent default). + */ + if (newpr->encmode == 0) + newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS; + + inssaproto(newpp, newpr); + } + + return newpp; + +err: + flushsaprop(newpp); + return NULL; +} + +void +flushsaprop(head) + struct saprop *head; +{ + struct saprop *p, *save; + + for (p = head; p != NULL; p = save) { + save = p->next; + flushsaproto(p->head); + racoon_free(p); + } + + return; +} + +void +flushsaproto(head) + struct saproto *head; +{ + struct saproto *p, *save; + + for (p = head; p != NULL; p = save) { + save = p->next; + flushsatrns(p->head); + vfree(p->keymat); + vfree(p->keymat_p); + racoon_free(p); + } + + return; +} + +void +flushsatrns(head) + struct satrns *head; +{ + struct satrns *p, *save; + + for (p = head; p != NULL; p = save) { + save = p->next; + racoon_free(p); + } + + return; +} + +/* + * print multiple proposals + */ +void +printsaprop(pri, pp) + const int pri; + const struct saprop *pp; +{ + const struct saprop *p; + + if (pp == NULL) { + plog(pri, LOCATION, NULL, "(null)"); + return; + } + + for (p = pp; p; p = p->next) { + printsaprop0(pri, p); + } + + return; +} + +/* + * print one proposal. + */ +void +printsaprop0(pri, pp) + int pri; + const struct saprop *pp; +{ + const struct saproto *p; + + if (pp == NULL) + return; + + for (p = pp->head; p; p = p->next) { + printsaproto(pri, p); + } + + return; +} + +void +printsaproto(pri, pr) + const int pri; + const struct saproto *pr; +{ + struct satrns *tr; + + if (pr == NULL) + return; + + plog(pri, LOCATION, NULL, + " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx " + "encmode=%s reqid=%d:%d)\n", + s_ipsecdoi_proto(pr->proto_id), + pr->spisize, + (unsigned long)ntohl(pr->spi), + (unsigned long)ntohl(pr->spi_p), + s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode), + pr->reqid_in, pr->reqid_out); + + for (tr = pr->head; tr; tr = tr->next) { + printsatrns(pri, pr->proto_id, tr); + } + + return; +} + +void +printsatrns(pri, proto_id, tr) + const int pri; + const int proto_id; + const struct satrns *tr; +{ + if (tr == NULL) + return; + + switch (proto_id) { + case IPSECDOI_PROTO_IPSEC_AH: + plog(pri, LOCATION, NULL, + " (trns_id=%s authtype=%s)\n", + s_ipsecdoi_trns(proto_id, tr->trns_id), + s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype)); + break; + case IPSECDOI_PROTO_IPSEC_ESP: + plog(pri, LOCATION, NULL, + " (trns_id=%s encklen=%d authtype=%s)\n", + s_ipsecdoi_trns(proto_id, tr->trns_id), + tr->encklen, + s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype)); + break; + case IPSECDOI_PROTO_IPCOMP: + plog(pri, LOCATION, NULL, + " (trns_id=%s)\n", + s_ipsecdoi_trns(proto_id, tr->trns_id)); + break; + default: + plog(pri, LOCATION, NULL, + "(unknown proto_id %d)\n", proto_id); + } + + return; +} + +void +print_proppair0(pri, p, level) + int pri; + struct prop_pair *p; + int level; +{ + char spc[21]; + + memset(spc, ' ', sizeof(spc)); + spc[sizeof(spc) - 1] = '\0'; + if (level < 20) { + spc[level] = '\0'; + } + + plog(pri, LOCATION, NULL, + "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext); + if (p->next) + print_proppair0(pri, p->next, level + 1); + if (p->tnext) + print_proppair0(pri, p->tnext, level + 1); +} + +void +print_proppair(pri, p) + int pri; + struct prop_pair *p; +{ + print_proppair0(pri, p, 1); +} + +int +set_proposal_from_policy(iph2, sp_main, sp_sub) + struct ph2handle *iph2; + struct secpolicy *sp_main, *sp_sub; +{ + struct saprop *newpp; + struct ipsecrequest *req; + int encmodesv = IPSEC_MODE_TRANSPORT; /* use only when complex_bundle */ + + newpp = newsaprop(); + if (newpp == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + goto err; + } + newpp->prop_no = 1; + newpp->lifetime = iph2->sainfo->lifetime; + newpp->lifebyte = iph2->sainfo->lifebyte; + newpp->pfs_group = iph2->sainfo->pfs_group; + + if (lcconf->complex_bundle) + goto skip1; + + /* + * decide the encryption mode of this SA bundle. + * the mode becomes tunnel mode when there is even one policy + * of tunnel mode in the SPD. otherwise the mode becomes + * transport mode. + */ + encmodesv = IPSEC_MODE_TRANSPORT; + for (req = sp_main->req; req; req = req->next) { + if (req->saidx.mode == IPSEC_MODE_TUNNEL) { + encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode); + break; + } + } + + skip1: + for (req = sp_main->req; req; req = req->next) { + struct saproto *newpr; + caddr_t paddr = NULL; + + /* + * check if SA bundle ? + * nested SAs negotiation is NOT supported. + * me +--- SA1 ---+ peer1 + * me +--- SA2 --------------+ peer2 + */ + if (req->saidx.src.ss_len && req->saidx.dst.ss_len) { + + /* check the end of ip addresses of SA */ + if (iph2->side == INITIATOR) + paddr = (caddr_t)&req->saidx.dst; + else + paddr = (caddr_t)&req->saidx.src; + + if (memcmp(iph2->dst, paddr, iph2->dst->sa_len)){ + plog(LLV_ERROR, LOCATION, NULL, + "not supported nested SA."); + goto err; + } + } + + /* allocate ipsec sa protocol */ + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto err; + } + + newpr->proto_id = ipproto2doi(req->saidx.proto); + newpr->spisize = 4; + if (lcconf->complex_bundle) + newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode); + else + newpr->encmode = encmodesv; + + newpr->reqid_out = req->saidx.reqid; + + if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get algorithms.\n"); + goto err; + } + + /* set new saproto */ + inssaprotorev(newpp, newpr); + } + + /* get reqid_in from inbound policy */ + if (sp_sub) { + struct saproto *pr; + + req = sp_sub->req; + pr = newpp->head; + while (req && pr) { + pr->reqid_in = req->saidx.reqid; + pr = pr->next; + req = req->next; + } + if (pr || req) { + plog(LLV_NOTIFY, LOCATION, NULL, + "There is a difference " + "between the in/out bound policies in SPD.\n"); + } + } + + iph2->proposal = newpp; + + printsaprop0(LLV_DEBUG, newpp); + + return 0; +err: + return -1; +} + +/* + * generate a policy from peer's proposal. + * this function unconditionally choices first proposal in SA payload + * passed by peer. + */ +int +set_proposal_from_proposal(iph2) + struct ph2handle *iph2; +{ + struct saprop *newpp = NULL, *pp0, *pp_peer; + struct saproto *newpr = NULL, *pr; + struct prop_pair **pair; + int error = -1; + int i; + + /* get proposal pair */ + pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2); + if (pair == NULL) + goto end; + + /* + * make my proposal according as the client proposal. + * XXX assumed there is only one proposal even if it's the SA bundle. + */ + for (i = 0; i < MAXPROPPAIRLEN; i++) { + if (pair[i] == NULL) + continue; + pp_peer = aproppair2saprop(pair[i]); + if (pp_peer == NULL) + goto end; + + pp0 = newsaprop(); + if (pp0 == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saprop.\n"); + goto end; + } + pp0->prop_no = 1; + pp0->lifetime = iph2->sainfo->lifetime; + pp0->lifebyte = iph2->sainfo->lifebyte; + pp0->pfs_group = iph2->sainfo->pfs_group; + + if (pp_peer->next != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "pp_peer is inconsistency, ignore it.\n"); + /*FALLTHROUGH*/ + } + + for (pr = pp_peer->head; pr; pr = pr->next) { + + newpr = newsaproto(); + if (newpr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate saproto.\n"); + goto end; + } + newpr->proto_id = pr->proto_id; + newpr->spisize = pr->spisize; + newpr->encmode = pr->encmode; + newpr->spi = 0; + newpr->spi_p = pr->spi; /* copy peer's SPI */ + newpr->reqid_in = 0; + newpr->reqid_out = 0; + } + + if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get algorithms.\n"); + goto end; + } + + inssaproto(pp0, newpr); + inssaprop(&newpp, pp0); + } + + plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n"); + printsaprop0(LLV_DEBUG, newpp); + + iph2->proposal = newpp; + + error = 0; + +end: + if (error && newpp) + flushsaprop(newpp); + + free_proppair(pair); + return error; +} diff --git a/racoon.tproj/proposal.h b/racoon.tproj/proposal.h new file mode 100644 index 0000000..d1501a7 --- /dev/null +++ b/racoon.tproj/proposal.h @@ -0,0 +1,203 @@ +/* $KAME: proposal.h,v 1.15 2001/04/06 14:23:48 sakane 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. 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. + */ + +#include + +/* + * A. chained list of transform, only for single proto_id + * (this is same as set of transforms in single proposal payload) + * B. proposal. this will point to multiple (A) items (order is important + * here so pointer to (A) must be ordered array, or chained list). + * this covers multiple proposal on a packet if proposal # is the same. + * C. finally, (B) needs to be connected as chained list. + * + * head ---> prop[.......] ---> prop[...] ---> prop[...] ---> ... + * | | | | + * | | | +- proto4 <== must preserve order here + * | | +--- proto3 + * | +----- proto2 + * +------- proto1[trans1, trans2, trans3, ...] + * + * incoming packets needs to be parsed to construct the same structure + * (check "prop_pair" too). + */ +/* SA proposal specification */ +struct saprop { + int prop_no; + time_t lifetime; + int lifebyte; + int pfs_group; /* pfs group */ + int claim; /* flag to send RESPONDER-LIFETIME. */ + /* XXX assumed DOI values are 1 or 2. */ + + struct saproto *head; + struct saprop *next; +}; + +/* SA protocol specification */ +struct saproto { + int proto_id; + size_t spisize; /* spi size */ + int encmode; /* encryption mode */ + + /* XXX should be vchar_t * */ + /* these are network byte order */ + u_int32_t spi; /* inbound. i.e. --SA-> me */ + u_int32_t spi_p; /* outbound. i.e. me -SA-> */ + + vchar_t *keymat; /* KEYMAT */ + vchar_t *keymat_p; /* peer's KEYMAT */ + + int reqid_out; /* request id (outbound) */ + int reqid_in; /* request id (inbound) */ + + int ok; /* if 1, success to set SA in kenrel */ + + struct satrns *head; /* header of transform */ + struct saproto *next; /* next protocol */ +}; + +/* SA algorithm specification */ +struct satrns { + int trns_no; + int trns_id; /* transform id */ + int encklen; /* key length of encryption algorithm */ + int authtype; /* authentication algorithm if ESP */ + + struct satrns *next; /* next transform */ +}; + +/* + * prop_pair: (proposal number, transform number) + * + * (SA (P1 (T1 T2)) (P1' (T1' T2')) (P2 (T1" T2"))) + * + * p[1] p[2] + * top (P1,T1) (P2",T1") + * | |tnext |tnext + * | v v + * | (P1, T2) (P2", T2") + * v next + * (P1', T1') + * |tnext + * v + * (P1', T2') + * + * when we convert it to saprop in prop2saprop(), it should become like: + * + * (next) + * saprop --------------------> saprop + * | (head) | (head) + * +-> saproto +-> saproto + * | | (head) | (head) + * | +-> satrns(P1 T1) +-> satrns(P2" T1") + * | | (next) | (next) + * | v v + * | satrns(P1, T2) satrns(P2", T2") + * v (next) + * saproto + * | (head) + * +-> satrns(P1' T1') + * | (next) + * v + * satrns(P1', T2') + */ +struct prop_pair { + struct isakmp_pl_p *prop; + struct isakmp_pl_t *trns; + struct prop_pair *next; /* next prop_pair with same proposal # */ + /* (bundle case) */ + struct prop_pair *tnext; /* next prop_pair in same proposal payload */ + /* (multiple tranform case) */ +}; +#define MAXPROPPAIRLEN 256 /* It's enough because field size is 1 octet. */ + +/* + * Lifetime length selection refered to the section 4.5.4 of RFC2407. It does + * not completely conform to the description of RFC. There are four types of + * the behavior. If the value of "proposal_check" in "remote" directive is; + * "obey" + * the responder obey the initiator anytime. + * "strict" + * If the responder's length is longer than the initiator's one, the + * responder uses the intitiator's one. Otherwise rejects the proposal. + * If PFS is not required by the responder, the responder obeys the + * proposal. If PFS is required by both sides and if the responder's + * group is not equal to the initiator's one, then the responder reject + * the proposal. + * "claim" + * If the responder's length is longer than the initiator's one, the + * responder use the intitiator's one. If the responder's length is + * shorter than the initiator's one, the responder uses own length + * AND send RESPONDER-LIFETIME notify message to a initiator in the + * case of lifetime. + * About PFS, this directive is same as "strict". + * "exact" + * If the initiator's length is not equal to the responder's one, the + * responder rejects the proposal. + * If PFS is required and if the responder's group is not equal to + * the initiator's one, then the responder reject the proposal. + * XXX should be defined the behavior of key length. + */ +#define PROP_CHECK_OBEY 1 +#define PROP_CHECK_STRICT 2 +#define PROP_CHECK_CLAIM 3 +#define PROP_CHECK_EXACT 4 + +struct sainfo; +struct ph1handle; +struct secpolicy; +extern struct saprop *newsaprop __P((void)); +extern struct saproto *newsaproto __P((void)); +extern void inssaprop __P((struct saprop **, struct saprop *)); +extern void inssaproto __P((struct saprop *, struct saproto *)); +extern void inssaprotorev __P((struct saprop *, struct saproto *)); +extern struct satrns *newsatrns __P((void)); +extern void inssatrns __P((struct saproto *, struct satrns *)); +extern struct saprop *cmpsaprop_alloc __P((struct ph1handle *, + const struct saprop *, const struct saprop *, int)); +extern int cmpsaprop __P((const struct saprop *, const struct saprop *)); +extern int cmpsatrns __P((const struct satrns *, const struct satrns *)); +extern int set_satrnsbysainfo __P((struct saproto *, struct sainfo *)); +extern struct saprop *aproppair2saprop __P((struct prop_pair *)); +extern void free_proppair __P((struct prop_pair **)); +extern void flushsaprop __P((struct saprop *)); +extern void flushsaproto __P((struct saproto *)); +extern void flushsatrns __P((struct satrns *)); +extern void printsaprop __P((const int, const struct saprop *)); +extern void printsaprop0 __P((const int, const struct saprop *)); +extern void printsaproto __P((const int, const struct saproto *)); +extern void printsatrns __P((const int, const int, const struct satrns *)); +extern void print_proppair0 __P((int, struct prop_pair *, int)); +extern void print_proppair __P((int, struct prop_pair *)); +extern int set_proposal_from_policy __P((struct ph2handle *, + struct secpolicy *, struct secpolicy *)); +extern int set_proposal_from_proposal __P((struct ph2handle *)); diff --git a/racoon.tproj/psk.txt b/racoon.tproj/psk.txt new file mode 100644 index 0000000..db42233 --- /dev/null +++ b/racoon.tproj/psk.txt @@ -0,0 +1,10 @@ +# IPv4/v6 addresses +# 10.160.94.3 asecretkeygoeshere +# 172.16.1.133 asecretkeygoeshere +# 3ffe:501:410:ffff:200:86ff:fe05:80fa asecretkeygoeshere +# 3ffe:501:410:ffff:210:4bff:fea2:8baa asecretkeygoeshere + +# USER_FQDN +macuser@localhost somethingsecret +# FQDN +kame hoge diff --git a/racoon.tproj/racoon.8 b/racoon.tproj/racoon.8 new file mode 100644 index 0000000..8c4db9b --- /dev/null +++ b/racoon.tproj/racoon.8 @@ -0,0 +1,140 @@ +.\" $KAME: racoon.8,v 1.28 2001/10/19 05:04:32 sakane 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. 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. +.\" +.Dd November 20, 2000 +.Dt RACOON 8 +.Os KAME +.\" +.Sh NAME +.Nm racoon +.Nd IKE (ISAKMP/Oakley) key management daemon +.\" +.Sh SYNOPSIS +.Nm racoon +.Bk -words +.Op Fl BdFv46 +.Ek +.Bk -words +.Op Fl f Ar configfile +.Ek +.Bk -words +.Op Fl l Ar logfile +.Ek +.Bk -words +.Op Fl p Ar isakmp-port +.Ek +.\" +.Sh DESCRIPTION +.Nm +speaks IKE +.Pq ISAKMP/Oakley +key management protocol, +to establish security association with other hosts. +SPD +.Pq Security Policy Database +in the kernel usually triggers to start +.Nm racoon . +.Nm racoon +usually sends all of informational messages, warnings and error messages to +.Xr syslogd 8 +with the facility LOG_DAEMON, the priority LOG_INFO. +Debugging messages are sent with the priority LOG_DEBUG. +You should configure +.Xr syslog.conf 5 +appropriately to see these messages. +.Bl -tag -width Ds +.It Fl B +Install SA(s) from the file which is specified in +.Xr racoon.conf 5 . +.It Fl d +Increase the debug level. +Multiple +.Fl d +will increase the debug level even more. +.It Fl F +Run +.Nm racoon +in the foreground. +.It Fl f Ar configfile +Use +.Ar configfile +as the configuration file instead of the default. +.It Fl l Ar logfile +Use +.Ar logfile +as the logging file instead of +.Xr syslogd 8 . +.It Fl p Ar isakmp-port +Listen to ISAKMP key exchange on port +.Ar isakmp-port +instead of the default port number, 500. +.It Fl v +The flag causes the packet dump be more verbose, with higher debugging level. +.It Fl 4 +.It Fl 6 +Specifies the default address family for the sockets. +.El +.Pp +.Nm +assumes the presence of kernel random number device +.Xr rnd 4 +at +.Pa /dev/urandom . +Informational messages are labeled +.Em info , +and debugging messages are labeled +.Em debug . +You have to configure +.Xr syslog.conf 5 +if you want to see them in a logging file. +.\" +.Sh FILES +.Bl -tag -width /usr/local/v6/etc/racoon.conf -compact +.It Pa /usr/local/v6/etc/racoon.conf +default configuration file. +.El +.\" +.Sh RETURN VALUES +The command exits with 0 on success, and non-zero on errors. +.\" +.Sh SEE ALSO +.Xr ipsec 4 , +.Xr racoon.conf 5 , +.Xr setkey 8 , +.Xr syslogd 8 +.Xr syslog.conf 5 +.\" +.Sh HISTORY +The +.Nm +command first appeared in +.Dq YIPS +Yokogawa IPsec implementation. +.\" +.\".Sh BUGS diff --git a/racoon.tproj/racoon.conf b/racoon.tproj/racoon.conf new file mode 100644 index 0000000..9487f2a --- /dev/null +++ b/racoon.tproj/racoon.conf @@ -0,0 +1,125 @@ +# $KAME: racoon.conf.in,v 1.17 2001/08/14 12:10:22 sakane Exp $ + +# "path" must be placed before it should be used. +# You can overwrite which you defined, but it should not use due to confusing. +path include "/etc/racoon" ; +#include "remote.conf" ; + +# search this file for pre_shared_key with various ID key. +path pre_shared_key "/etc/racoon/psk.txt" ; + +# racoon will look for certificate file in the directory, +# if the certificate/certificate request payload is received. +path certificate "/etc/cert" ; + +# "log" specifies logging level. It is followed by either "notify", "debug" +# or "debug2". +#log debug; + +# "padding" defines some parameter of padding. You should not touch these. +padding +{ + maximum_length 20; # maximum padding length. + randomize off; # enable randomize length. + strict_check off; # enable strict check. + exclusive_tail off; # extract last one octet. +} + +# if no listen directive is specified, racoon will listen to all +# available interface addresses. +listen +{ + #isakmp ::1 [7000]; + #isakmp 202.249.11.124 [500]; + #admin [7002]; # administrative's port by kmpstat. + #strict_address; # required all addresses must be bound. +} + +# Specification of default various timer. +timer +{ + # These value can be changed per remote node. + counter 5; # maximum trying count to send. + interval 20 sec; # maximum interval to resend. + persend 1; # the number of packets per a send. + + # timer for waiting to complete each phase. + phase1 30 sec; + phase2 15 sec; +} + +remote anonymous +{ + #exchange_mode main,aggressive; + exchange_mode aggressive,main; + doi ipsec_doi; + situation identity_only; + + #my_identifier address; + my_identifier user_fqdn "macuser@localhost"; + peers_identifier user_fqdn "macuser@localhost"; + #certificate_type x509 "mycert" "mypriv"; + + nonce_size 16; + lifetime time 1 min; # sec,min,hour + initial_contact on; + support_mip6 on; + proposal_check obey; # obey, strict or claim + + proposal { + encryption_algorithm 3des; + hash_algorithm sha1; + authentication_method pre_shared_key ; + dh_group 2 ; + } +} + +remote ::1 [8000] +{ + #exchange_mode main,aggressive; + exchange_mode aggressive,main; + doi ipsec_doi; + situation identity_only; + + my_identifier user_fqdn "macuser@localhost"; + peers_identifier user_fqdn "macuser@localhost"; + #certificate_type x509 "mycert" "mypriv"; + + nonce_size 16; + lifetime time 1 min; # sec,min,hour + + proposal { + encryption_algorithm 3des; + hash_algorithm sha1; + authentication_method pre_shared_key ; + dh_group 2 ; + } +} + +sainfo anonymous +{ + pfs_group 1; + lifetime time 30 sec; + encryption_algorithm 3des ; + authentication_algorithm hmac_sha1; + compression_algorithm deflate ; +} + +# sainfo address 203.178.141.209 any address 203.178.141.218 any +# { +# pfs_group 1; +# lifetime time 30 sec; +# encryption_algorithm des ; +# authentication_algorithm hmac_md5; +# compression_algorithm deflate ; +# } + +sainfo address ::1 icmp6 address ::1 icmp6 +{ + pfs_group 1; + lifetime time 60 sec; + encryption_algorithm 3des, cast128, blowfish 448, des ; + authentication_algorithm hmac_sha1, hmac_md5 ; + compression_algorithm deflate ; +} + diff --git a/racoon.tproj/racoon.conf.5 b/racoon.tproj/racoon.conf.5 new file mode 100644 index 0000000..ec8f822 --- /dev/null +++ b/racoon.tproj/racoon.conf.5 @@ -0,0 +1,725 @@ +.\" $KAME: racoon.conf.5,v 1.96 2002/02/21 14:30:21 sakane 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. 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. +.\" +.Dd November 20, 2000 +.Dt RACOON.CONF 5 +.Os KAME +.\" +.Sh NAME +.Nm racoon.conf +.Nd configuration file for racoon +.\" +.\" .Sh SYNOPSIS +.\" +.Sh DESCRIPTION +.Nm +is the configuration file for the +.Xr racoon 8 +ISAKMP daemon. +.Xr racoon 8 +negotiates security associations for itself (ISAKMP SA, or phase 1 SA) +and for kernel IPsec (IPsec SA, or phase 2 SA). +The file consists of a sequence of directives and statements. +Each directive is composed by a tag, and statements are enclosed by +.Ql { +and +.Ql } . +Lines beginning with +.Ql # +are comments. +.\" +.Ss Meta Syntax +Keywords and special characters that the parser expects exactly are +displayed using +.Ic this +font. +Parameters are specified with +.Ar this +font. +Square brackets +.Po +.Ql \*(lB +and +.Ql \*(rB +.Pc +are used to show optional keywords and parameters. +Note that +you have to pay attention when this manual is describing +.Ar port +numbers. +The +.Ar port +number is always enclosed by +.Ql \*(lB +and +.Ql \*(rB . +In this case, the port number is not an optional keyword. +If it is possible to omit +.Ar port +number, +the expression becomes +.Bq Ic Bq Ar port . +The vertical bar +.Pq Ql \*(Ba +is used to indicate +a choice between optional parameters. +Parentheses +.Po +.Ql \*(lP +and +.Ql \*(rP +.Pc +are used to group keywords and parameters when necessary. +Major parameters are listed below. +.Pp +.Bl -tag -width addressx -compact +.It Ar number +means a hexadecimal or a decimal number. +The former must be prefixed with +.Ql Li 0x . +.It Ar string +.It Ar path +.It Ar file +means any string enclosed in +.Ql \&" +.Pq double quote . +.It Ar address +means IPv6 and/or IPv4 address. +.It Ar port +means a TCP/UDP port number. +The port number is always enclosed by +.Ql \*(lB +and +.Ql \*(rB . +.It Ar timeunit +is one of following: +.Ic sec , secs , second , seconds , +.Ic min , mins , minute , minutes , +.Ic hour , hours . +.El +.\" +.Ss Path Specification +.Bl -tag -width Ds -compact +.It Ic path include Ar path ; +specifies a path to include a file. +See +.Sx File Inclusion . +.It Ic path pre_shared_key Ar file ; +specifies a file containing pre-shared key(s) for various ID(s). +See +.Sx Pre-shared key File . +.It Ic path certificate Ar path ; +.Xr racoon 8 +will search this directory if a certificate or certificate request is received. +.It Ic path backupsa Ar file ; +specifies a file to be stored a SA information which is negotiated by racoon. +.Xr racoon 8 +will install SA(s) from the file with a boot option +.Fl B . +The file is increasing because +.Xr racoon 8 +simply add a SA to the file at the moment. +You should maintain the file manually. +.El +.\" +.Ss File Inclusion +.Bl -tag -width Ds -compact +.It Ic include Ar file +other configuration files can be included. +.El +.\" +.Ss Identifier Specification +is obsolete. +It must be defined at each +.Ic remote +directive. +.\" +.Ss Timer Specification +.Bl -tag -width Ds -compact +.It Ic timer { Ar statements Ic } +specifies various timer values. +.Pp +.Bl -tag -width Ds -compact +.It Ic counter Ar number ; +the maximum number of retries to send. +The default is 5. +.It Ic interval Ar number Ar timeunit ; +the interval to resend, in seconds. +The default time is 10 seconds. +.It Ic persend Ar number ; +the number of packets per send. +The default is 1. +.It Ic phase1 Ar number Ar timeunit ; +the maximum time it should take to complete phase 1. +The default time is 15 seconds. +.It Ic phase2 Ar number Ar timeunit ; +the maximum time it should take to complete phase 2. +The default time is 10 seconds. +.El +.El +.\" +.Ss Listening Port Specification +.Bl -tag -width Ds -compact +.It Ic listen { Ar statements Ic } +If no +.Ar listen +directive is specified, +.Xr racoon 8 +will listen on all of the available interface addresses. +The following is the list of valid statements: +.Pp +.Bl -tag -width Ds -compact +.\" How do I express bold brackets; `[' and `]' . +.\" Is the "Bq Ic [ Ar port ] ;" buggy ? +.It Ic isakmp Ar address Bq Bq Ar port ; +If this is specified, +.Xr racoon 8 +will only listen on +.Ar address . +The default port is 500, which is specified by IANA. +You can provide more than one address definition. +.It Ic strict_address ; +require that all addresses for ISAKMP must be bound. +This statement will be ignored if you do not specify any addresses. +.El +.El +.\" +.Ss Remote Nodes Specifications +.Bl -tag -width Ds -compact +.It Xo +.Ic remote ( Ar address \*(Ba Ic anonymous ) +.Bq Bq Ar port +.Ic { Ar statements Ic } +.Xc +specifies the parameters for IKE phase 1 for each remote node. +The default port is 500. +If +.Ic anonymous +is specified, the statements apply to all peers which do not match +any other +.Ic remote +directive. +.Pp +The following are valid statements. +.Pp +.Bl -tag -width Ds -compact +.\" +.It Ic exchange_mode ( main \*(Ba aggressive \*(Ba base ) ; +defines the exchange mode for phase 1 when racoon is the initiator. +Also it means the acceptable exchange mode when racoon is responder. +More than one mode can be specified by separating them with a comma. +All of the modes are acceptable. +The first exchange mode is what racoon uses when it is the initiator. +.\" +.It Ic doi Ic ipsec_doi ; +means to use IPSEC-DOI as specified RFC 2407. +You can omit this statement. +.\" +.It Ic situation Ic identity_only ; +means to use SIT_IDENTITY_ONLY as specified RFC 2407. +You can omit this statement. +.\" +.It Ic identifier Ar idtype ; +is obsolete. +Instead, use +.Ic my_identifier . +.\" +.It Ic my_identifier Ar idtype ... ; +specifies the identifier sent to the remote host +and the type to use in the phase 1 negotiation. +.Ic address, fqdn , user_fqdn , keyid and asn1dn +can be used as an +.Ar idtype . +they are used like: +.Bl -tag -width Ds -compact +.It Ic my_identifier Ic address Bq Ar address ; +the type is the IP address. +This is the default type if you do not specify an identifier to use. +.It Ic my_identifier Ic user_fqdn Ar string ; +the type is a USER_FQDN (user fully-qualified domain name). +.It Ic my_identifier Ic fqdn Ar string ; +the type is a FQDN (fully-qualified domain name). +.It Ic my_identifier Ic keyid Ar file ; +the type is a KEY_ID. +.It Ic my_identifier Ic asn1dn Bq Ar string ; +the type is an ASN.1 distinguished name. +If +.Ar string +is omitted, +.Xr racoon 8 +will get DN from Subject field in the certificate. +.El +.\" +.It Ic peers_identifier Ar idtype ... ; +specifies the peer's identifier to be received. +If it is not defined then +.Xr racoon 8 +will not verify the peer's identifier in ID payload transmitted from the peer. +If it is defined, the behavior of the verification depends on the flag of +.Ic verify_identifier . +The usage of +.Ar idtype +is same to +.Ic my_identifier . +.\" +.It Ic verify_identifier (on \(ba off) ; +If you want to verify the peer's identifier, +set this to on. +In this case, if the value defined by +.Ic peers_identifier +is not same to the peer's identifier in the ID payload, +the negotiation will failed. +The default is off. +.\" +.It Ic certificate_type Ar certspec ; +specifies a certificate specification. +.Ar certspec +is one of followings: +.Bl -tag -width Ds -compact +.It Ic x509 Ar certfile Ar privkeyfile; +.Ar certfile +means a file name of certificate. +.Ar privkeyfile +means a file name of secret key. +.El +.\" +.It Ic peers_certfile ( dnssec \*(Ba Ar certfile ) ; +If +.Ic dnssec +is defined, +.Xr racoon 8 +will ignore the CERT payload from the peer, +and try to get the peer's certificate from DNS instead. +If +.Ar certfile +is defined, +.Xr racoon 8 +will ignore the CERT payload from the peer, +and will use this certificate as the peer's certificate. +.\" +.It Ic send_cert (on \(ba off) ; +If you do not want to send a certificate for some reason, set this to off. +The default is on. +.\" +.It Ic send_cr (on \(ba off) ; +If you do not want to send a certificate request for some reason, set this to off. +The default is on. +.\" +.It Ic verify_cert (on \(ba off) ; +If you do not want to verify the peer's certificate for some reason, +set this to off. +The default is on. +.\" +.It Ic lifetime time Ar number Ar timeunit ; +define a lifetime of a certain time +which will be proposed in the phase 1 negotiations. +Any proposal will be accepted, and the attribute(s) will be not proposed to +the peer if you do not specify it(them). +They can be individually specified in each proposal. +.\" +.It Ic initial_contact (on \(ba off) ; +enable this to send an INITIAL-CONTACT message. +The default value is +.Ic on . +This message is useful only when +the implementation of the responder choices an old SA when there are multiple +SAs which are different established time, and the initiator reboots. +If racoon did not use the message, +the responder would use an old SA even when an new SA was established. +The KAME stack has the switch in the system wide value, +net.key.preferred_oldsa. +when the value is zero, the stack always use an new SA. +.\" +.It Ic passive (on \(ba off) ; +If you do not want to initiate the negotiation, set this to on. +The default value is +.Ic off . +It is useful for a server. +.\" +.It Ic proposal_check Ar level ; +specifies the action of lifetime length and PFS of the phase 2 +selection on the responder side. +The default level is +.Ic strict . +If the +.Ar level +is; +.Bl -tag -width Ds -compact +.It Ic obey +the responder will obey the initiator anytime. +.It Ic strict +If the responder's length is longer than the initiator's one, the +responder uses the initiator's one. +Otherwise it rejects the proposal. +If PFS is not required by the responder, the responder will obey the proposal. +If PFS is required by both sides and if the responder's group is not equal to +the initiator's one, then the responder will reject the proposal. +.It Ic claim +If the responder's length is longer than the initiator's one, the +responder will use the initiator's one. +If the responder's length is +shorter than the initiator's one, the responder uses its own length +AND sends a RESPONDER-LIFETIME notify message to an initiator in the +case of lifetime. +About PFS, this directive is same as +.Ic strict . +.It Ic exact +If the initiator's length is not equal to the responder's one, the +responder will reject the proposal. +If PFS is required by both sides and if the responder's group is not equal to +the initiator's one, then the responder will reject the proposal. +.El +.\" +.It Ic support_mip6 (on \(ba off) ; +If this value is set on then both values of ID payloads in phase 2 exchange +are always used as the addresses of end-point of IPsec-SAs. +The default is off. +.\" +.It Ic generate_policy (on \(ba off) ; +This directive is for the responder. +Therefore you should set +.Ic passive +on in order that +.Xr racoon 8 +only becomes a responder. +If the responder does not have any policy in SPD during phase 2 negotiation, +and the directive is set on, then +.Xr racoon 8 +will choice the first proposal in the +SA payload from the initiator, and generate policy entries from the proposal. +It is useful to negotiate with the client which is allocated IP address +dynamically. +Note that inappropriate policy might be installed by the initiator +because the responder just installs policies as the initiator proposes. +So that other communication might fail if such policies installed. +This directive is ignored in the initiator case. +The default value is +.Ic off . +.\" +.It Ic nonce_size Ar number ; +define the byte size of nonce value. +Racoon can send any value although +RFC2409 specifies that the value MUST be between 8 and 256 bytes. +The default size is 16 bytes. +.\" +.It Xo +.Ic proposal { Ar sub-substatements Ic } +.Xc +.Bl -tag -width Ds -compact +.\" +.It Ic encryption_algorithm Ar algorithm ; +specify the encryption algorithm used for the phase 1 negotiation. +This directive must be defined. +.Ar algorithm +is one of following: +.Ic des , 3des , blowfish , cast128 +.\".Ic rc5 , idea +for oakley. +For other transforms, this statement should not be used. +.\" +.It Ic hash_algorithm Ar algorithm; +define the hash algorithm used for the phase 1 negotiation. +This directive must be defined. +.Ar algorithm +is one of following: +.Ic md5, sha1 +for oakley. +.\" +.It Ic authentication_method Ar type ; +defines the authentication method used for the phase 1 negotiation. +This directive must be defined. +.Ar type +is one of: +.Ic pre_shared_key, rsasig , gssapi_krb . +.\" +.It Ic dh_group Ar group ; +define the group used for the Diffie-Hellman exponentiations. +This directive must be defined. +.Ar group +is one of following: +.Ic modp768 , modp1024 , modp1536 . +Or you can define 1, 2, or 5 as the DH group number. +When you want to use aggressive mode, +you must define same DH group in each proposal. +.It Ic lifetime time Ar number Ar timeunit ; +define lifetime of the phase 1 SA proposal. +Refer to the description of +.Ic lifetime +directive immediately defined in +.Ic remote +directive. +.It Ic gssapi_id Ar string ; +define the GSS-API endpoint name, to be included as an attribute in the SA, +if the +.Ic gssapi_krb +authentication method is used. If this is not defined, the default value of +.Ql ike/hostname +is used, where hostname is the FQDN of the interface being used. +.El +.El +.El +.\" +.Ss Policy Specifications +The policy directive is obsolete, policies are now in the SPD. +.Xr racoon 8 +will obey the policy configured into the kernel by +.Xr setkey 8 , +and will construct phase 2 proposals by combining +.Ic sainfo +specifications in +.Nm Ns , +and policies in the kernel. +.\" +.Ss Sainfo Specifications +.Bl -tag -width Ds -compact +.It Xo +.Ic sainfo ( Ar source_id destination_id \*(Ba Ic anonymous ) +.Ic { Ar statements Ic } +.Xc +defines the parameters of the IKE phase 2 (IPsec-SA establishment). +.Ar source_id +and +.Ar destination_id +are constructed like: +.Pp +.Ic address Ar address +.Bq Ic / Ar prefix +.Bq Ic [ Ar port ] +.Ar ul_proto +.Pp +or +.Pp +.Ar idtype Ar string +.Pp +It means exactly the content of ID payload. +This is not like a filter rule. +For example, if you define 3ffe:501:4819::/48 as +.Ar source_id . +3ffe:501:4819:1000:/64 will not match. +.Pp +.Bl -tag -width Ds -compact +.\" +.It Ic pfs_group Ar group ; +define the group of Diffie-Hellman exponentiations. +If you do not require PFS then you can omit this directive. +Any proposal will be accepted if you do not specify one. +.Ar group +is one of following: +.Ic modp768 , modp1024 , modp1536 . +Or you can define 1, 2, or 5 as the DH group number. +.\" +.It Ic lifetime time Ar number Ar timeunit ; +define the lifetime of amount of time +which are to be used IPsec-SA. +Any proposal will be accepted, and no attribute(s) will be proposed to +the peer if you do not specify it(them). +See the +.Ic proposal_check +directive. +.\" +.It Ic my_identifier Ar idtype ... ; +is obsolete. +It does not make sense to specify a identifier in the phase 2. +.El +.\" +.Pp +.Xr racoon 8 +does not have the list of security protocols to be negotiated. +The list of security protocols are passed by SPD in the kernel. +Therefore you have to define all of the potential algorithms +in the phase 2 proposals even if there is a algorithm which will not be used. +These algorithms are define by using the following three directives, +and they are lined with single comma as the separator. +For algorithms that can take variable-length keys, algorithm names +can be followed by a key length, like +.Dq Li blowfish 448 . +.Xr racoon 8 +will compute the actual phase 2 proposals by computing +the permutation of the specified algorithms, +and then combining them with the security protocol specified by the SPD. +For example, if +.Ic des, 3des, hmac_md5, +and +.Ic hmac_sha1 +are specified as algorithms, we have four combinations for use with ESP, +and two for AH. +Then, based on the SPD settings, +.Xr racoon 8 +will construct the actual proposals. +If the SPD entry asks for ESP only, there will be 4 proposals. +If it asks for both AH and ESP, there will be 8 proposals. +Note that the kernel may not support the algorithm you have specified. +.\" +.Bl -tag -width Ds -compact +.It Ic encryption_algorithm Ar algorithms ; +.Ic des , 3des , des_iv64 , des_iv32 , +.Ic rc5 , rc4 , idea , 3idea , +.Ic cast128 , blowfish , null_enc , +.Ic twofish , rijndael +.Pq used with ESP +.\" +.It Ic authentication_algorithm Ar algorithms ; +.Ic des , 3des , des_iv64 , des_iv32 , +.Ic hmac_md5 , hmac_sha1 , non_auth +.Pq used with ESP authentication and AH +.\" +.It Ic compression_algorithm Ar algorithms ; +.Ic deflate +.Pq used with IPComp +.El +.El +.\" +.Ss Logging level +.Bl -tag -width Ds -compact +.It Ic log Ar level ; +define logging level. +.Ar level +is one of following: +.Ic notify , debug +and +.Ic debug2 . +The default is +.Ic notify . +If you put too high logging level on slower machines, +IKE negotiation can fail due to timing constraint changes. +.El +.\" +.Ss Specifying the way to pad +.Bl -tag -width Ds -compact +.It Ic padding { Ar statements Ic } +specified padding format. +The following are valid statements: +.Bl -tag -width Ds -compact +.It Ic randomize (on \(ba off) ; +enable using a randomized value for padding. +The default is on. +.It Ic randomize_length (on \(ba off) ; +the pad length is random. +The default is off. +.It Ic maximum_length Ar number ; +define a maximum padding length. +If +.Ic randomize_length is off, this is ignored. +The default is 20 bytes. +.It Ic exclusive_tail (on \(ba off) ; +means to put the number of pad bytes minus one into last part of the padding. +The default is on. +.It Ic strict_check (on \(ba off) ; +means to be constrained the peer to set the number of pad bytes. +The default is off. +.El +.El +.Ss Special directives +.Bl -tag -width Ds -compact +.It Ic complex_bundle (on \(ba off) ; +defines the interpretation of proposal in the case of SA bundle. +Normally +.Dq IP AH ESP IP payload +is proposed as +.Dq AH tunnel and ESP tunnel . +The interpretation is more common to other IKE implementations, however, +it allows very limited set of combinations for proposals. +With the option enabled, it will be proposed as +.Dq AH transport and ESP tunnel . +The default value is +.Ic off . +.El +.\" +.Ss Pre-shared key File +Pre-shared key file defines a pair of the identifier and the shared secret key +which are used at Pre-shared key authentication method in phase 1. +The pair in each lines are separated by some number of blanks and/or tab +characters like +.Xr hosts 5 . +Key can be included any blanks because all of the words after 2nd column +are interpreted as a secret key. +Lines start with +.Ql # +are ignored. +Keys which start with +.Ql 0x +are hexa-decimal strings. +Note that the file must be owned by the user ID running +.Xr racoon 8 +.Pq usually the privileged user , +and must not be accessible by others. +.\" +.Sh EXAMPLE +The following shows how the remote directive should be configured. +.Bd -literal -offset +path pre_shared_key "/usr/local/v6/etc/psk.txt" ; +remote anonymous +{ + exchange_mode aggressive,main,base; + lifetime time 24 hour; + proposal { + encryption_algorithm 3des; + hash_algorithm sha1; + authentication_method pre_shared_key; + dh_group 2; + } +} + +sainfo anonymous +{ + pfs_group 2; + lifetime time 12 hour ; + encryption_algorithm 3des, blowfish 448, twofish, rijndael ; + authentication_algorithm hmac_sha1, hmac_md5 ; + compression_algorithm deflate ; +} +.Ed + +The following is a sample of the file defined pre-shared key. +.Bd -literal -offset +10.160.94.3 mekmitasdigoat +172.16.1.133 0x12345678 +194.100.55.1 whatcertificatereally +3ffe:501:410:ffff:200:86ff:fe05:80fa mekmitasdigoat +3ffe:501:410:ffff:210:4bff:fea2:8baa mekmitasdigoat +foo@kame.net mekmitasdigoat +foo.kame.net hoge +.Ed +.\" +.Sh SEE ALSO +.\".Xr racoonctl 8 , +.Xr racoon 8 , +.Xr setkey 8 +.\" +.Sh HISTORY +The +.Nm +configuration file first appeared in +.Dq YIPS +Yokogawa IPsec implementation. +.\" +.Sh BUGS +Some statements may not be handled by +.Xr racoon 8 +yet. diff --git a/racoon.tproj/remoteconf.c b/racoon.tproj/remoteconf.c new file mode 100644 index 0000000..0908976 --- /dev/null +++ b/racoon.tproj/remoteconf.c @@ -0,0 +1,317 @@ +/* $KAME: remoteconf.c,v 1.28 2001/10/02 03:46:41 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include + +#ifdef IPV6_INRIA_VERSION +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "remoteconf.h" +#include "localconf.h" +#include "grabmyaddr.h" +#include "proposal.h" +#include "vendorid.h" +#include "gcmalloc.h" + +static LIST_HEAD(_rmtree, remoteconf) rmtree; + +/*%%%*/ +/* + * search remote configuration. + * don't use port number to search if its value is either IPSEC_PORT_ANY. + * If matching anonymous entry, then new entry is copied from anonymous entry. + * If no anonymous entry found, then return NULL. + * OUT: NULL: NG + * Other: remote configuration entry. + */ +struct remoteconf * +getrmconf(remote) + struct sockaddr *remote; +{ + struct remoteconf *p; + struct remoteconf *anon = NULL; + int withport; + char buf[NI_MAXHOST + NI_MAXSERV + 10]; + char addr[NI_MAXHOST], port[NI_MAXSERV]; + + withport = 0; + + switch (remote->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)remote)->sin_port != IPSEC_PORT_ANY) + withport = 1; + break; +#ifdef INET6 + case AF_INET6: + if (((struct sockaddr_in6 *)remote)->sin6_port != IPSEC_PORT_ANY) + withport = 1; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", remote->sa_family); + exit(1); + } + + GETNAMEINFO(remote, addr, port); + snprintf(buf, sizeof(buf), "%s%s%s%s", addr, + withport ? "[" : "", + withport ? port : "", + withport ? "]" : ""); + + LIST_FOREACH(p, &rmtree, chain) { + if ((!withport && cmpsaddrwop(remote, p->remote) == 0) + || (withport && cmpsaddrstrict(remote, p->remote) == 0)) { + plog(LLV_DEBUG, LOCATION, NULL, + "configuration found for %s.\n", buf); + return p; + } + + /* save the pointer to the anonymous configuration */ + if (p->remote->sa_family == AF_UNSPEC) + anon = p; + } + + if (anon != NULL) { + plog(LLV_DEBUG, LOCATION, NULL, + "anonymous configuration selected for %s.\n", buf); + return anon; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "no remote configuration found.\n"); + return NULL; +} + +struct remoteconf * +newrmconf() +{ + struct remoteconf *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + new->proposal = NULL; + + /* set default */ + new->doitype = IPSEC_DOI; + new->sittype = IPSECDOI_SIT_IDENTITY_ONLY; + new->idvtype = IDTYPE_ADDRESS; + new->idvtype_p = IDTYPE_ADDRESS; + new->nonce_size = DEFAULT_NONCE_SIZE; + new->keepalive = FALSE; + new->passive = FALSE; + new->ini_contact = TRUE; + new->pcheck_level = PROP_CHECK_STRICT; + new->verify_identifier = FALSE; + new->verify_cert = TRUE; + new->getcert_method = ISAKMP_GETCERT_PAYLOAD; + new->send_cert = TRUE; + new->send_cr = TRUE; + new->support_mip6 = FALSE; + new->gen_policy = FALSE; + new->retry_counter = lcconf->retry_counter; + new->retry_interval = lcconf->retry_interval; + + return new; +} + +void +delrmconf(rmconf) + struct remoteconf *rmconf; +{ + if (rmconf->etypes) + deletypes(rmconf->etypes); + if (rmconf->dhgrp) + oakley_dhgrp_free(rmconf->dhgrp); + if (rmconf->proposal) + delisakmpsa(rmconf->proposal); + racoon_free(rmconf); +} + +void +delisakmpsa(sa) + struct isakmpsa *sa; +{ + if (sa->dhgrp) + oakley_dhgrp_free(sa->dhgrp); + if (sa->next) + delisakmpsa(sa->next); +#ifdef HAVE_GSSAPI + if (sa->gssid) + vfree(sa->gssid); +#endif + racoon_free(sa); +} + +void +deletypes(e) + struct etypes *e; +{ + if (e->next) + deletypes(e->next); + racoon_free(e); +} + +/* + * insert into head of list. + */ +void +insrmconf(new) + struct remoteconf *new; +{ + LIST_INSERT_HEAD(&rmtree, new, chain); +} + +void +remrmconf(rmconf) + struct remoteconf *rmconf; +{ + LIST_REMOVE(rmconf, chain); +} + +void +flushrmconf() +{ + struct remoteconf *p, *next; + + for (p = LIST_FIRST(&rmtree); p; p = next) { + next = LIST_NEXT(p, chain); + remrmconf(p); + delrmconf(p); + } +} + +void +initrmconf() +{ + LIST_INIT(&rmtree); +} + +/* check exchange type to be acceptable */ +struct etypes * +check_etypeok(rmconf, etype) + struct remoteconf *rmconf; + u_int8_t etype; +{ + struct etypes *e; + + for (e = rmconf->etypes; e != NULL; e = e->next) { + if (e->type == etype) + break; + } + + return e; +} + +/*%%%*/ +struct isakmpsa * +newisakmpsa() +{ + struct isakmpsa *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + /* + * Just for sanity, make sure this is initialized. This is + * filled in for real when the ISAKMP proposal is configured. + */ + new->vendorid = VENDORID_UNKNOWN; + + new->next = NULL; + new->rmconf = NULL; +#ifdef HAVE_GSSAPI + new->gssid = NULL; +#endif + + return new; +} + +/* + * insert into tail of list. + */ +void +insisakmpsa(new, rmconf) + struct isakmpsa *new; + struct remoteconf *rmconf; +{ + struct isakmpsa *p; + + new->rmconf = rmconf; + + if (rmconf->proposal == NULL) { + rmconf->proposal = new; + return; + } + + for (p = rmconf->proposal; p->next != NULL; p = p->next) + ; + p->next = new; + + return; +} + +const char * +rm2str(rmconf) + const struct remoteconf *rmconf; +{ + if (rmconf->remote->sa_family == AF_UNSPEC) + return "anonymous"; + return saddr2str(rmconf->remote); +} diff --git a/racoon.tproj/remoteconf.h b/racoon.tproj/remoteconf.h new file mode 100644 index 0000000..dcccbe9 --- /dev/null +++ b/racoon.tproj/remoteconf.h @@ -0,0 +1,122 @@ +/* $KAME: remoteconf.h,v 1.26 2001/09/26 05:30:35 sakane 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. 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. + */ + +/* remote configuration */ + +#include + +struct etypes { + int type; + struct etypes *next; +}; + +struct remoteconf { + struct sockaddr *remote; /* remote IP address */ + /* if family is AF_UNSPEC, that is + * for anonymous configuration. */ + + struct etypes *etypes; /* exchange type list. the head + * is a type to be sent first. */ + int doitype; /* doi type */ + int sittype; /* situation type */ + + int idvtype; /* my identifier type */ + vchar_t *idv; /* my identifier */ + int idvtype_p; /* peer's identifier type */ + vchar_t *idv_p; /* peer's identifier */ + + int certtype; /* certificate type if need */ + char *mycertfile; /* file name of my certificate */ + char *myprivfile; /* file name of my private key file */ + char *peerscertfile; /* file name of peer's certifcate */ + int getcert_method; /* the way to get peer's certificate */ + int send_cert; /* send to CERT or not */ + int send_cr; /* send to CR or not */ + int verify_cert; /* verify a CERT strictly */ + int verify_identifier; /* vefify the peer's identifier */ + int nonce_size; /* the number of bytes of nonce */ + int keepalive; /* XXX may not use */ + int passive; /* never initiate */ + int support_mip6; /* support mip6 */ + int gen_policy; /* generate policy if no policy found */ + int ini_contact; /* initial contact */ + int pcheck_level; /* level of propocl checking */ + + int dh_group; /* use it when only aggressive mode */ + struct dhgroup *dhgrp; /* use it when only aggressive mode */ + /* avobe two cann't be defined by user*/ + + int retry_counter; /* times to retry. */ + int retry_interval; /* interval each retry. */ + /* above 2 values are copied from localconf. */ + + struct isakmpsa *proposal; /* proposal list */ + LIST_ENTRY(remoteconf) chain; /* next remote conf */ +}; + +struct dhgroup; + +/* ISAKMP SA specification */ +struct isakmpsa { + int prop_no; + int trns_no; + time_t lifetime; + int lifebyte; + int enctype; + int encklen; + int authmethod; + int hashtype; + int vendorid; +#ifdef HAVE_GSSAPI + vchar_t *gssid; +#endif + int dh_group; /* don't use it if aggressive mode */ + struct dhgroup *dhgrp; /* don't use it if aggressive mode */ + + struct isakmpsa *next; /* next transform */ + struct remoteconf *rmconf; /* backpointer to remoteconf */ +}; + +struct remoteconf *getrmconf __P((struct sockaddr *)); +extern struct remoteconf *newrmconf __P((void)); +extern void delrmconf __P((struct remoteconf *)); +extern void delisakmpsa __P((struct isakmpsa *)); +extern void deletypes __P((struct etypes *)); +extern void insrmconf __P((struct remoteconf *)); +extern void remrmconf __P((struct remoteconf *)); +extern void flushrmconf __P((void)); +extern void initrmconf __P((void)); +extern struct etypes *check_etypeok + __P((struct remoteconf *, u_int8_t)); + +extern struct isakmpsa *newisakmpsa __P((void)); +extern void insisakmpsa __P((struct isakmpsa *, struct remoteconf *)); +extern const char *rm2str __P((const struct remoteconf *)); diff --git a/racoon.tproj/rijndael-alg-fst.c b/racoon.tproj/rijndael-alg-fst.c new file mode 100644 index 0000000..19f0651 --- /dev/null +++ b/racoon.tproj/rijndael-alg-fst.c @@ -0,0 +1,492 @@ +/* $KAME: rijndael-alg-fst.c,v 1.9 2001/06/19 15:21:05 itojun Exp $ */ + +/* + * rijndael-alg-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.3: Paulo Barreto + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef _KERNEL +#include +#else +#include +#endif +#include +#include + +#include + +#include +#define bcopy(a, b, c) memcpy((b), (a), (c)) +#define bzero(a, b) memset((a), 0, (b)) +#define panic(a) err(1, (a)) + +int rijndaelKeySched(word8 k[MAXKC][4], word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + /* Calculate the necessary round keys + * The number of calculations depends on keyBits and blockBits + */ + int j, r, t, rconpointer = 0; + union { + word8 x8[MAXKC][4]; + word32 x32[MAXKC]; + } xtk; +#define tk xtk.x8 + int KC = ROUNDS - 6; + + for (j = KC-1; j >= 0; j--) { + *((word32*)tk[j]) = *((word32*)k[j]); + } + r = 0; + t = 0; + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + + while (r < ROUNDS + 1) { /* while not enough round key material calculated */ + /* calculate new values */ + tk[0][0] ^= S[tk[KC-1][1]]; + tk[0][1] ^= S[tk[KC-1][2]]; + tk[0][2] ^= S[tk[KC-1][3]]; + tk[0][3] ^= S[tk[KC-1][0]]; + tk[0][0] ^= rcon[rconpointer++]; + + if (KC != 8) { + for (j = 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } else { + for (j = 1; j < KC/2; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; + tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; + tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; + tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; + for (j = KC/2 + 1; j < KC; j++) { + *((word32*)tk[j]) ^= *((word32*)tk[j-1]); + } + } + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((word32*)W[r][t]) = *((word32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + } + return 0; +#undef tk +} + +int rijndaelKeyEncToDec(word8 W[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + word8 *w; + + for (r = 1; r < ROUNDS; r++) { + w = W[r][0]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][1]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][2]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + + w = W[r][3]; + *((word32*)w) = + *((const word32*)U1[w[0]]) + ^ *((const word32*)U2[w[1]]) + ^ *((const word32*)U3[w[2]]) + ^ *((const word32*)U4[w[3]]); + } + return 0; +} + +/** + * Encrypt a single block. + */ +int rijndaelEncrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[0][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[0][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[0][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[0][3]); + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + for (r = 1; r < ROUNDS-1; r++) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + + *((word32*)(b )) = *((const word32*)T1[temp[0][0]]) + ^ *((const word32*)T2[temp[1][1]]) + ^ *((const word32*)T3[temp[2][2]]) + ^ *((const word32*)T4[temp[3][3]]); + *((word32*)(b + 4)) = *((const word32*)T1[temp[1][0]]) + ^ *((const word32*)T2[temp[2][1]]) + ^ *((const word32*)T3[temp[3][2]]) + ^ *((const word32*)T4[temp[0][3]]); + *((word32*)(b + 8)) = *((const word32*)T1[temp[2][0]]) + ^ *((const word32*)T2[temp[3][1]]) + ^ *((const word32*)T3[temp[0][2]]) + ^ *((const word32*)T4[temp[1][3]]); + *((word32*)(b +12)) = *((const word32*)T1[temp[3][0]]) + ^ *((const word32*)T2[temp[0][1]]) + ^ *((const word32*)T3[temp[1][2]]) + ^ *((const word32*)T4[temp[2][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[ROUNDS-1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[ROUNDS-1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[ROUNDS-1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[ROUNDS-1][3]); + b[ 0] = T1[temp[0][0]][1]; + b[ 1] = T1[temp[1][1]][1]; + b[ 2] = T1[temp[2][2]][1]; + b[ 3] = T1[temp[3][3]][1]; + b[ 4] = T1[temp[1][0]][1]; + b[ 5] = T1[temp[2][1]][1]; + b[ 6] = T1[temp[3][2]][1]; + b[ 7] = T1[temp[0][3]][1]; + b[ 8] = T1[temp[2][0]][1]; + b[ 9] = T1[temp[3][1]][1]; + b[10] = T1[temp[0][2]][1]; + b[11] = T1[temp[1][3]][1]; + b[12] = T1[temp[3][0]][1]; + b[13] = T1[temp[0][1]][1]; + b[14] = T1[temp[1][2]][1]; + b[15] = T1[temp[2][3]][1]; + *((word32*)(b )) ^= *((word32*)rk[ROUNDS][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[ROUNDS][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[ROUNDS][2]); + *((word32*)(b+12)) ^= *((word32*)rk[ROUNDS][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Encrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + */ +int rijndaelEncryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r; + word8 temp[4][4]; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + + *((word32*)a[0]) = *((word32*)a[0]) ^ *((word32*)rk[0][0]); + *((word32*)a[1]) = *((word32*)a[1]) ^ *((word32*)rk[0][1]); + *((word32*)a[2]) = *((word32*)a[2]) ^ *((word32*)rk[0][2]); + *((word32*)a[3]) = *((word32*)a[3]) ^ *((word32*)rk[0][3]); + + for (r = 1; (r <= rounds) && (r < ROUNDS); r++) { + *((word32*)temp[0]) = *((const word32*)T1[a[0][0]]) + ^ *((const word32*)T2[a[1][1]]) + ^ *((const word32*)T3[a[2][2]]) + ^ *((const word32*)T4[a[3][3]]); + *((word32*)temp[1]) = *((const word32*)T1[a[1][0]]) + ^ *((const word32*)T2[a[2][1]]) + ^ *((const word32*)T3[a[3][2]]) + ^ *((const word32*)T4[a[0][3]]); + *((word32*)temp[2]) = *((const word32*)T1[a[2][0]]) + ^ *((const word32*)T2[a[3][1]]) + ^ *((const word32*)T3[a[0][2]]) + ^ *((const word32*)T4[a[1][3]]); + *((word32*)temp[3]) = *((const word32*)T1[a[3][0]]) + ^ *((const word32*)T2[a[0][1]]) + ^ *((const word32*)T3[a[1][2]]) + ^ *((const word32*)T4[a[2][3]]); + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[r][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[r][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[r][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[r][3]); + } + if (rounds == ROUNDS) { + /* last round is special */ + temp[0][0] = T1[a[0][0]][1]; + temp[0][1] = T1[a[1][1]][1]; + temp[0][2] = T1[a[2][2]][1]; + temp[0][3] = T1[a[3][3]][1]; + temp[1][0] = T1[a[1][0]][1]; + temp[1][1] = T1[a[2][1]][1]; + temp[1][2] = T1[a[3][2]][1]; + temp[1][3] = T1[a[0][3]][1]; + temp[2][0] = T1[a[2][0]][1]; + temp[2][1] = T1[a[3][1]][1]; + temp[2][2] = T1[a[0][2]][1]; + temp[2][3] = T1[a[1][3]][1]; + temp[3][0] = T1[a[3][0]][1]; + temp[3][1] = T1[a[0][1]][1]; + temp[3][2] = T1[a[1][2]][1]; + temp[3][3] = T1[a[2][3]][1]; + *((word32*)a[0]) = *((word32*)temp[0]) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)a[1]) = *((word32*)temp[1]) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)a[2]) = *((word32*)temp[2]) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)a[3]) = *((word32*)temp[3]) ^ *((word32*)rk[ROUNDS][3]); + } + + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ + +/** + * Decrypt a single block. + */ +int rijndaelDecrypt(word8 in[16], word8 out[16], word8 rk[MAXROUNDS+1][4][4], int ROUNDS) { + int r; + union { + word8 x8[16]; + word32 x32[4]; + } xa, xb; +#define a xa.x8 +#define b xb.x8 + union { + word8 x8[4][4]; + word32 x32[4]; + } xtemp; +#define temp xtemp.x8 + + memcpy(a, in, sizeof a); + + *((word32*)temp[0]) = *((word32*)(a )) ^ *((word32*)rk[ROUNDS][0]); + *((word32*)temp[1]) = *((word32*)(a+ 4)) ^ *((word32*)rk[ROUNDS][1]); + *((word32*)temp[2]) = *((word32*)(a+ 8)) ^ *((word32*)rk[ROUNDS][2]); + *((word32*)temp[3]) = *((word32*)(a+12)) ^ *((word32*)rk[ROUNDS][3]); + + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + for (r = ROUNDS-1; r > 1; r--) { + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[r][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[r][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[r][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[r][3]); + *((word32*)(b )) = *((const word32*)T5[temp[0][0]]) + ^ *((const word32*)T6[temp[3][1]]) + ^ *((const word32*)T7[temp[2][2]]) + ^ *((const word32*)T8[temp[1][3]]); + *((word32*)(b+ 4)) = *((const word32*)T5[temp[1][0]]) + ^ *((const word32*)T6[temp[0][1]]) + ^ *((const word32*)T7[temp[3][2]]) + ^ *((const word32*)T8[temp[2][3]]); + *((word32*)(b+ 8)) = *((const word32*)T5[temp[2][0]]) + ^ *((const word32*)T6[temp[1][1]]) + ^ *((const word32*)T7[temp[0][2]]) + ^ *((const word32*)T8[temp[3][3]]); + *((word32*)(b+12)) = *((const word32*)T5[temp[3][0]]) + ^ *((const word32*)T6[temp[2][1]]) + ^ *((const word32*)T7[temp[1][2]]) + ^ *((const word32*)T8[temp[0][3]]); + } + /* last round is special */ + *((word32*)temp[0]) = *((word32*)(b )) ^ *((word32*)rk[1][0]); + *((word32*)temp[1]) = *((word32*)(b+ 4)) ^ *((word32*)rk[1][1]); + *((word32*)temp[2]) = *((word32*)(b+ 8)) ^ *((word32*)rk[1][2]); + *((word32*)temp[3]) = *((word32*)(b+12)) ^ *((word32*)rk[1][3]); + b[ 0] = S5[temp[0][0]]; + b[ 1] = S5[temp[3][1]]; + b[ 2] = S5[temp[2][2]]; + b[ 3] = S5[temp[1][3]]; + b[ 4] = S5[temp[1][0]]; + b[ 5] = S5[temp[0][1]]; + b[ 6] = S5[temp[3][2]]; + b[ 7] = S5[temp[2][3]]; + b[ 8] = S5[temp[2][0]]; + b[ 9] = S5[temp[1][1]]; + b[10] = S5[temp[0][2]]; + b[11] = S5[temp[3][3]]; + b[12] = S5[temp[3][0]]; + b[13] = S5[temp[2][1]]; + b[14] = S5[temp[1][2]]; + b[15] = S5[temp[0][3]]; + *((word32*)(b )) ^= *((word32*)rk[0][0]); + *((word32*)(b+ 4)) ^= *((word32*)rk[0][1]); + *((word32*)(b+ 8)) ^= *((word32*)rk[0][2]); + *((word32*)(b+12)) ^= *((word32*)rk[0][3]); + + memcpy(out, b, sizeof b /* XXX out */); + + return 0; +#undef a +#undef b +#undef temp +} + + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * Decrypt only a certain number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * Operations rearranged such that the intermediate values + * of decryption correspond with the intermediate values + * of encryption. + */ +int rijndaelDecryptRound(word8 a[4][4], word8 rk[MAXROUNDS+1][4][4], int ROUNDS, int rounds) { + int r, i; + word8 temp[4], shift; + + /* make number of rounds sane */ + if (rounds > ROUNDS) { + rounds = ROUNDS; + } + /* first round is special: */ + *(word32 *)a[0] ^= *(word32 *)rk[ROUNDS][0]; + *(word32 *)a[1] ^= *(word32 *)rk[ROUNDS][1]; + *(word32 *)a[2] ^= *(word32 *)rk[ROUNDS][2]; + *(word32 *)a[3] ^= *(word32 *)rk[ROUNDS][3]; + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + /* ROUNDS-1 ordinary rounds */ + for (r = ROUNDS-1; r > rounds; r--) { + *(word32 *)a[0] ^= *(word32 *)rk[r][0]; + *(word32 *)a[1] ^= *(word32 *)rk[r][1]; + *(word32 *)a[2] ^= *(word32 *)rk[r][2]; + *(word32 *)a[3] ^= *(word32 *)rk[r][3]; + + *((word32*)a[0]) = + *((const word32*)U1[a[0][0]]) + ^ *((const word32*)U2[a[0][1]]) + ^ *((const word32*)U3[a[0][2]]) + ^ *((const word32*)U4[a[0][3]]); + + *((word32*)a[1]) = + *((const word32*)U1[a[1][0]]) + ^ *((const word32*)U2[a[1][1]]) + ^ *((const word32*)U3[a[1][2]]) + ^ *((const word32*)U4[a[1][3]]); + + *((word32*)a[2]) = + *((const word32*)U1[a[2][0]]) + ^ *((const word32*)U2[a[2][1]]) + ^ *((const word32*)U3[a[2][2]]) + ^ *((const word32*)U4[a[2][3]]); + + *((word32*)a[3]) = + *((const word32*)U1[a[3][0]]) + ^ *((const word32*)U2[a[3][1]]) + ^ *((const word32*)U3[a[3][2]]) + ^ *((const word32*)U4[a[3][3]]); + for (i = 0; i < 4; i++) { + a[i][0] = Si[a[i][0]]; + a[i][1] = Si[a[i][1]]; + a[i][2] = Si[a[i][2]]; + a[i][3] = Si[a[i][3]]; + } + for (i = 1; i < 4; i++) { + shift = (4 - i) & 3; + temp[0] = a[(0 + shift) & 3][i]; + temp[1] = a[(1 + shift) & 3][i]; + temp[2] = a[(2 + shift) & 3][i]; + temp[3] = a[(3 + shift) & 3][i]; + a[0][i] = temp[0]; + a[1][i] = temp[1]; + a[2][i] = temp[2]; + a[3][i] = temp[3]; + } + } + if (rounds == 0) { + /* End with the extra key addition */ + *(word32 *)a[0] ^= *(word32 *)rk[0][0]; + *(word32 *)a[1] ^= *(word32 *)rk[0][1]; + *(word32 *)a[2] ^= *(word32 *)rk[0][2]; + *(word32 *)a[3] ^= *(word32 *)rk[0][3]; + } + return 0; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/racoon.tproj/rijndael-alg-fst.h b/racoon.tproj/rijndael-alg-fst.h new file mode 100644 index 0000000..4f02543 --- /dev/null +++ b/racoon.tproj/rijndael-alg-fst.h @@ -0,0 +1,33 @@ +/* $KAME: rijndael-alg-fst.h,v 1.4 2000/10/02 17:14:26 itojun Exp $ */ + +/* + * rijndael-alg-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_ALG_FST_H +#define __RIJNDAEL_ALG_FST_H + +#define RIJNDAEL_MAXKC (256/32) +#define RIJNDAEL_MAXROUNDS 14 + +int rijndaelKeySched(u_int8_t k[RIJNDAEL_MAXKC][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelKeyEncToDec(u_int8_t W[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +int rijndaelEncrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelEncryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +int rijndaelDecrypt(u_int8_t a[16], u_int8_t b[16], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndaelDecryptRound(u_int8_t a[4][4], u_int8_t rk[RIJNDAEL_MAXROUNDS+1][4][4], int ROUNDS, int rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_ALG_FST_H */ diff --git a/racoon.tproj/rijndael-api-fst.c b/racoon.tproj/rijndael-api-fst.c new file mode 100644 index 0000000..a3104c2 --- /dev/null +++ b/racoon.tproj/rijndael-api-fst.c @@ -0,0 +1,495 @@ +/* $KAME: rijndael-api-fst.c,v 1.1.1.1 2001/08/08 09:56:23 sakane Exp $ */ + +/* + * rijndael-api-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.1: Vincent Rijmen + * v2.2: Vincent Rijmen + * v2.3: Paulo Barreto + * v2.4: Vincent Rijmen + * + * This code is placed in the public domain. + */ + +#include +#include +#ifdef _KERNEL +#include +#include +#else +#include +#endif +#include +#include +#include + +#include +#define bcopy(a, b, c) memcpy(b, a, c) +#define bzero(a, b) memset(a, 0, b) +#define panic(a) err(1, (a)) + +int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) { + word8 k[MAXKC][4]; + int i; + char *keyMat; + + if (key == NULL) { + return BAD_KEY_INSTANCE; + } + + if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) { + key->direction = direction; + } else { + return BAD_KEY_DIR; + } + + if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) { + key->keyLen = keyLen; + } else { + return BAD_KEY_MAT; + } + + if (keyMaterial != NULL) { + bcopy(keyMaterial, key->keyMaterial, keyLen/8); + } + + key->ROUNDS = keyLen/32 + 6; + + /* initialize key schedule: */ + keyMat = key->keyMaterial; + for (i = 0; i < key->keyLen/8; i++) { + k[i >> 2][i & 3] = (word8)keyMat[i]; + } + rijndaelKeySched(k, key->keySched, key->ROUNDS); + if (direction == DIR_DECRYPT) { + rijndaelKeyEncToDec(key->keySched, key->ROUNDS); + } + + return TRUE; +} + +int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) { + if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) { + cipher->mode = mode; + } else { + return BAD_CIPHER_MODE; + } + if (IV != NULL) { + bcopy(IV, cipher->IV, MAX_IV_SIZE); + } else { + bzero(cipher->IV, MAX_IV_SIZE); + } + return TRUE; +} + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 0 /*STRICT_ALIGN*/ + bcopy(cipher->IV, block, 16); + bcopy(input, iv, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)cipher->IV)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)cipher->IV)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)cipher->IV)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)cipher->IV)[3] ^ ((word32*)input)[3]; +#endif + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + for (i = numBlocks - 1; i > 0; i--) { +#if 0 /*STRICT_ALIGN*/ + bcopy(outBuffer, block, 16); + ((word32*)block)[0] ^= ((word32*)iv)[0]; + ((word32*)block)[1] ^= ((word32*)iv)[1]; + ((word32*)block)[2] ^= ((word32*)iv)[2]; + ((word32*)block)[3] ^= ((word32*)iv)[3]; +#else + ((word32*)block)[0] = ((word32*)outBuffer)[0] ^ ((word32*)input)[0]; + ((word32*)block)[1] = ((word32*)outBuffer)[1] ^ ((word32*)input)[1]; + ((word32*)block)[2] = ((word32*)outBuffer)[2] ^ ((word32*)input)[2]; + ((word32*)block)[3] = ((word32*)outBuffer)[3] ^ ((word32*)input)[3]; +#endif + outBuffer += 16; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + input += 16; + } + break; + + case MODE_CFB1: +#if 0 /*STRICT_ALIGN*/ + bcopy(cipher->IV, iv, 16); +#else /* !STRICT_ALIGN */ + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif /* ?STRICT_ALIGN */ + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((outBuffer[k/8] >> (7-(k&7))) & 1); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +/** + * Encrypt data partitioned in octets, using RFC 2040-like padding. + * + * @param input data to be encrypted (octet sequence) + * @param inputOctets input length in octets (not bits) + * @param outBuffer encrypted output data + * + * @return length in octets (not bits) of the encrypted output buffer. + */ +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16], *iv, *cp; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_DECRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + padLen = 16 - (inputOctets - 16*numBlocks); + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(ECB)"); + bcopy(input, block, 16 - padLen); + for (cp = block + 16 - padLen; cp < block + 16; cp++) + *cp = padLen; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + case MODE_CBC: + iv = cipher->IV; + for (i = numBlocks; i > 0; i--) { + ((word32*)block)[0] = ((word32*)input)[0] ^ ((word32*)iv)[0]; + ((word32*)block)[1] = ((word32*)input)[1] ^ ((word32*)iv)[1]; + ((word32*)block)[2] = ((word32*)input)[2] ^ ((word32*)iv)[2]; + ((word32*)block)[3] = ((word32*)input)[3] ^ ((word32*)iv)[3]; + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + iv = outBuffer; + input += 16; + outBuffer += 16; + } +#if 0 /*XXX i'm not sure that is correct. sakane@kame.net */ + padLen = 16 - (inputOctets - 16*numBlocks); +#else + padLen = 16 - inputOctets % 16; + if (padLen == 16) + padLen = 0; +#endif + if (padLen > 0 && padLen <= 16) + panic("rijndael_padEncrypt(CBC)"); + for (i = 0; i < 16 - padLen; i++) { + block[i] = input[i] ^ iv[i]; + } + for (i = 16 - padLen; i < 16; i++) { + block[i] = (BYTE)padLen ^ iv[i]; + } + rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*(numBlocks + 1); +} + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer) { + int i, k, numBlocks; + word8 block[16], iv[4][4]; + + if (cipher == NULL || + key == NULL || + (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputLen <= 0) { + return 0; /* nothing to do */ + } + + numBlocks = inputLen/128; + + switch (cipher->mode) { + case MODE_ECB: + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + break; + + case MODE_CBC: +#if 0 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV )); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= *((word32*)iv[0]); + ((word32*)block)[1] ^= *((word32*)iv[1]); + ((word32*)block)[2] ^= *((word32*)iv[2]); + ((word32*)block)[3] ^= *((word32*)iv[3]); +#if 0 /*STRICT_ALIGN*/ + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); +#else + *((word32*)iv[0]) = ((word32*)input)[0]; ((word32*)outBuffer)[0] = ((word32*)block)[0]; + *((word32*)iv[1]) = ((word32*)input)[1]; ((word32*)outBuffer)[1] = ((word32*)block)[1]; + *((word32*)iv[2]) = ((word32*)input)[2]; ((word32*)outBuffer)[2] = ((word32*)block)[2]; + *((word32*)iv[3]) = ((word32*)input)[3]; ((word32*)outBuffer)[3] = ((word32*)block)[3]; +#endif + input += 16; + outBuffer += 16; + } + break; + + case MODE_CFB1: +#if 0 /*STRICT_ALIGN */ + bcopy(cipher->IV, iv, 16); +#else + *((word32*)iv[0]) = *((word32*)(cipher->IV)); + *((word32*)iv[1]) = *((word32*)(cipher->IV+ 4)); + *((word32*)iv[2]) = *((word32*)(cipher->IV+ 8)); + *((word32*)iv[3]) = *((word32*)(cipher->IV+12)); +#endif + for (i = numBlocks; i > 0; i--) { + for (k = 0; k < 128; k++) { + *((word32*) block ) = *((word32*)iv[0]); + *((word32*)(block+ 4)) = *((word32*)iv[1]); + *((word32*)(block+ 8)) = *((word32*)iv[2]); + *((word32*)(block+12)) = *((word32*)iv[3]); + rijndaelEncrypt(block, block, key->keySched, key->ROUNDS); + iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7); + iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7); + iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7); + iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7); + iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7); + iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7); + iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7); + iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7); + iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7); + iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7); + iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7); + iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7); + iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7); + iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7); + iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7); + iv[3][3] = (iv[3][3] << 1) | ((input[k/8] >> (7-(k&7))) & 1); + outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7); + } + } + break; + + default: + return BAD_CIPHER_STATE; + } + + return 128*numBlocks; +} + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputOctets, BYTE *outBuffer) { + int i, numBlocks, padLen; + word8 block[16]; + word32 iv[4]; + + if (cipher == NULL || + key == NULL || + key->direction == DIR_ENCRYPT) { + return BAD_CIPHER_STATE; + } + if (input == NULL || inputOctets <= 0) { + return 0; /* nothing to do */ + } + if (inputOctets % 16 != 0) { + return BAD_DATA; + } + + numBlocks = inputOctets/16; + + switch (cipher->mode) { + case MODE_ECB: + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + padLen = block[15]; + if (padLen >= 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + case MODE_CBC: + bcopy(cipher->IV, iv, 16); + /* all blocks but last */ + for (i = numBlocks - 1; i > 0; i--) { + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + bcopy(input, iv, 16); + bcopy(block, outBuffer, 16); + input += 16; + outBuffer += 16; + } + /* last block */ + rijndaelDecrypt(input, block, key->keySched, key->ROUNDS); + ((word32*)block)[0] ^= iv[0]; + ((word32*)block)[1] ^= iv[1]; + ((word32*)block)[2] ^= iv[2]; + ((word32*)block)[3] ^= iv[3]; + padLen = block[15]; + if (padLen <= 0 || padLen > 16) { + return BAD_DATA; + } + for (i = 16 - padLen; i < 16; i++) { + if (block[i] != padLen) { + return BAD_DATA; + } + } + bcopy(block, outBuffer, 16 - padLen); + break; + + default: + return BAD_CIPHER_STATE; + } + + return 16*numBlocks - padLen; +} + +#ifdef INTERMEDIATE_VALUE_KAT +/** + * cipherUpdateRounds: + * + * Encrypts/Decrypts exactly one full block a specified number of rounds. + * Only used in the Intermediate Value Known Answer Test. + * + * Returns: + * TRUE - on success + * BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized) + */ +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + BYTE *input, int inputLen, BYTE *outBuffer, int rounds) { + int j; + word8 block[4][4]; + + if (cipher == NULL || key == NULL) { + return BAD_CIPHER_STATE; + } + + for (j = 3; j >= 0; j--) { + /* parse input stream into rectangular array */ + *((word32*)block[j]) = *((word32*)(input+4*j)); + } + + switch (key->direction) { + case DIR_ENCRYPT: + rijndaelEncryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + case DIR_DECRYPT: + rijndaelDecryptRound(block, key->keySched, key->ROUNDS, rounds); + break; + + default: + return BAD_KEY_DIR; + } + + for (j = 3; j >= 0; j--) { + /* parse rectangular array into output ciphertext bytes */ + *((word32*)(outBuffer+4*j)) = *((word32*)block[j]); + } + + return TRUE; +} +#endif /* INTERMEDIATE_VALUE_KAT */ diff --git a/racoon.tproj/rijndael-api-fst.h b/racoon.tproj/rijndael-api-fst.h new file mode 100644 index 0000000..75b99c3 --- /dev/null +++ b/racoon.tproj/rijndael-api-fst.h @@ -0,0 +1,103 @@ +/* $KAME: rijndael-api-fst.h,v 1.6 2001/05/27 00:23:23 itojun Exp $ */ + +/* + * rijndael-api-fst.h v2.3 April '2000 + * + * Optimised ANSI C code + * + * #define INTERMEDIATE_VALUE_KAT to generate the Intermediate Value Known Answer Test. + */ + +#ifndef __RIJNDAEL_API_FST_H +#define __RIJNDAEL_API_FST_H + +#include + +/* Defines: + Add any additional defines you need +*/ + +#define DIR_ENCRYPT 0 /* Are we encrpyting? */ +#define DIR_DECRYPT 1 /* Are we decrpyting? */ +#define MODE_ECB 1 /* Are we ciphering in ECB mode? */ +#define MODE_CBC 2 /* Are we ciphering in CBC mode? */ +#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ +#define TRUE 1 +#define FALSE 0 +#define BITSPERBLOCK 128 /* Default number of bits in a cipher block */ + +/* Error Codes - CHANGE POSSIBLE: inclusion of additional error codes */ +#define BAD_KEY_DIR -1 /* Key direction is invalid, e.g., unknown value */ +#define BAD_KEY_MAT -2 /* Key material not of correct length */ +#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ +#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */ +#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ +#define BAD_BLOCK_LENGTH -6 +#define BAD_CIPHER_INSTANCE -7 +#define BAD_DATA -8 /* Data contents are invalid, e.g., invalid padding */ +#define BAD_OTHER -9 /* Unknown error */ + +/* CHANGE POSSIBLE: inclusion of algorithm specific defines */ +#define MAX_KEY_SIZE 64 /* # of ASCII char's needed to represent a key */ +#define MAX_IV_SIZE 16 /* # bytes needed to represent an IV */ + +/* Typedefs: + + Typedef'ed data storage elements. Add any algorithm specific +parameters at the bottom of the structs as appropriate. +*/ + +/* The structure for key information */ +typedef struct { + u_int8_t direction; /* Key used for encrypting or decrypting? */ + int keyLen; /* Length of the key */ + char keyMaterial[MAX_KEY_SIZE+1]; /* Raw key data in ASCII, e.g., user input or KAT values */ + /* The following parameters are algorithm dependent, replace or add as necessary */ + int ROUNDS; /* key-length-dependent number of rounds */ + int blockLen; /* block length */ + union { + u_int8_t xkS8[RIJNDAEL_MAXROUNDS+1][4][4]; /* key schedule */ + u_int32_t xkS32[RIJNDAEL_MAXROUNDS+1][4]; /* key schedule */ + } xKeySched; +#define keySched xKeySched.xkS8 +} keyInstance; + +/* The structure for cipher information */ +typedef struct { /* changed order of the components */ + u_int8_t mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ + u_int8_t IV[MAX_IV_SIZE]; /* A possible Initialization Vector for ciphering */ + /* Add any algorithm specific parameters needed here */ + int blockLen; /* Sample: Handles non-128 bit block sizes (if available) */ +} cipherInstance; + +/* Function prototypes */ +/* CHANGED: nothing + TODO: implement the following extensions to setup 192-bit and 256-bit block lengths: + makeKeyEx(): parameter blockLen added + -- this parameter is absolutely necessary if you want to + setup the round keys in a variable block length setting + cipherInitEx(): parameter blockLen added (for obvious reasons) + */ + +int rijndael_makeKey(keyInstance *key, u_int8_t direction, int keyLen, char *keyMaterial); + +int rijndael_cipherInit(cipherInstance *cipher, u_int8_t mode, char *IV); + +int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer); + +int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputOctets, u_int8_t *outBuffer); + +#ifdef INTERMEDIATE_VALUE_KAT +int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key, + u_int8_t *input, int inputLen, u_int8_t *outBuffer, int Rounds); +#endif /* INTERMEDIATE_VALUE_KAT */ + +#endif /* __RIJNDAEL_API_FST_H */ diff --git a/racoon.tproj/rijndael.h b/racoon.tproj/rijndael.h new file mode 100644 index 0000000..26a5c54 --- /dev/null +++ b/racoon.tproj/rijndael.h @@ -0,0 +1,3 @@ +/* $KAME: rijndael.h,v 1.2 2000/10/02 17:14:27 itojun Exp $ */ + +#include diff --git a/racoon.tproj/rijndael_local.h b/racoon.tproj/rijndael_local.h new file mode 100644 index 0000000..240e3ff --- /dev/null +++ b/racoon.tproj/rijndael_local.h @@ -0,0 +1,10 @@ +/* $KAME: rijndael_local.h,v 1.3 2000/10/02 17:14:27 itojun Exp $ */ + +/* the file should not be used from outside */ +typedef u_int8_t BYTE; +typedef u_int8_t word8; +typedef u_int16_t word16; +typedef u_int32_t word32; + +#define MAXKC RIJNDAEL_MAXKC +#define MAXROUNDS RIJNDAEL_MAXROUNDS diff --git a/racoon.tproj/safefile.c b/racoon.tproj/safefile.c new file mode 100644 index 0000000..e59ca11 --- /dev/null +++ b/racoon.tproj/safefile.c @@ -0,0 +1,89 @@ +/* $KAME: safefile.c,v 1.4 2000/12/15 13:43:57 sakane Exp $ */ + +/* + * Copyright (C) 2000 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. 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. + */ + +#include +#include +#include +#include +#include + +#include "plog.h" +#include "debug.h" +#include "misc.h" +#include "safefile.h" + +int +safefile(path, secret) + const char *path; + int secret; +{ + struct stat s; + uid_t me; + + /* no setuid */ + if (getuid() != geteuid()) { + plog(LLV_ERROR, LOCATION, NULL, + "setuid'ed execution not allowed\n"); + return -1; + } + + if (stat(path, &s) != 0) + return -1; + + /* the file must be owned by the running uid */ + me = getuid(); + if (s.st_uid != me) { + plog(LLV_ERROR, LOCATION, NULL, + "%s has invalid owner uid\n", path); + return -1; + } + + switch (s.st_mode & S_IFMT) { + case S_IFREG: + break; + default: + plog(LLV_ERROR, LOCATION, NULL, + "%s is an invalid file type 0x%x\n", path, + (s.st_mode & S_IFMT)); + return -1; + } + + /* secret file should not be read by others */ + if (secret) { + if ((s.st_mode & S_IRWXG) != 0 || (s.st_mode & S_IRWXO) != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "%s has weak file permission\n", path); + return -1; + } + } + + return 0; +} diff --git a/racoon.tproj/safefile.h b/racoon.tproj/safefile.h new file mode 100644 index 0000000..54a3ce6 --- /dev/null +++ b/racoon.tproj/safefile.h @@ -0,0 +1,34 @@ +/* $KAME$ */ + +/* $KAME: safefile.h,v 1.1 2000/06/13 05:01:41 itojun Exp $ */ + +/* + * Copyright (C) 2000 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. 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. + */ + +extern int safefile __P((const char *, int)); diff --git a/racoon.tproj/sainfo.c b/racoon.tproj/sainfo.c new file mode 100644 index 0000000..32bc20e --- /dev/null +++ b/racoon.tproj/sainfo.c @@ -0,0 +1,224 @@ +/* $KAME: sainfo.c,v 1.14 2001/04/03 15:51:56 thorpej 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" + +#include "localconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "handler.h" +#include "algorithm.h" +#include "sainfo.h" +#include "gcmalloc.h" + +static LIST_HEAD(_sitree, sainfo) sitree; + +/* %%% + * modules for ipsec sa info + */ +/* + * return matching entry. + * no matching entry found and if there is anonymous entry, return it. + * else return NULL. + * XXX by each data type, should be changed to compare the buffer. + */ +struct sainfo * +getsainfo(src, dst) + const vchar_t *src, *dst; +{ + struct sainfo *s = NULL; + struct sainfo *anonymous = NULL; + + LIST_FOREACH(s, &sitree, chain) { + if (s->idsrc == NULL) { + anonymous = s; + continue; + } + + /* anonymous ? */ + if (src == NULL) { + if (anonymous != NULL) + break; + continue; + } + + if (memcmp(src->v, s->idsrc->v, s->idsrc->l) == 0 + && memcmp(dst->v, s->iddst->v, s->iddst->l) == 0) + return s; + } + + if (anonymous) { + plog(LLV_DEBUG, LOCATION, NULL, + "anonymous sainfo selected.\n"); + } + return anonymous; +} + +struct sainfo * +newsainfo() +{ + struct sainfo *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + new->idvtype = IDTYPE_ADDRESS; + new->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT; + new->lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX; + + return new; +} + +void +delsainfo(si) + struct sainfo *si; +{ + int i; + + for (i = 0; i < MAXALGCLASS; i++) + delsainfoalg(si->algs[i]); + + if (si->idsrc) + vfree(si->idsrc); + if (si->iddst) + vfree(si->iddst); + + racoon_free(si); +} + +void +inssainfo(new) + struct sainfo *new; +{ + LIST_INSERT_HEAD(&sitree, new, chain); +} + +void +remsainfo(si) + struct sainfo *si; +{ + LIST_REMOVE(si, chain); +} + +void +flushsainfo() +{ + struct sainfo *s, *next; + + for (s = LIST_FIRST(&sitree); s; s = next) { + next = LIST_NEXT(s, chain); + remsainfo(s); + delsainfo(s); + } +} + +void +initsainfo() +{ + LIST_INIT(&sitree); +} + +struct sainfoalg * +newsainfoalg() +{ + struct sainfoalg *new; + + new = racoon_calloc(1, sizeof(*new)); + if (new == NULL) + return NULL; + + return new; +} + +void +delsainfoalg(alg) + struct sainfoalg *alg; +{ + struct sainfoalg *a, *next; + + for (a = alg; a; a = next) { + next = a->next; + racoon_free(a); + } +} + +void +inssainfoalg(head, new) + struct sainfoalg **head; + struct sainfoalg *new; +{ + struct sainfoalg *a; + + for (a = *head; a && a->next; a = a->next) + ; + if (a) + a->next = new; + else + *head = new; +} + +const char * +sainfo2str(si) + const struct sainfo *si; +{ + static char buf[256]; + + if (si->idsrc == NULL) + return "anonymous"; + + snprintf(buf, sizeof(buf), "%s", ipsecdoi_id2str(si->idsrc)); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + " %s", ipsecdoi_id2str(si->iddst)); + + return buf; +} diff --git a/racoon.tproj/sainfo.h b/racoon.tproj/sainfo.h new file mode 100644 index 0000000..1d27ad5 --- /dev/null +++ b/racoon.tproj/sainfo.h @@ -0,0 +1,71 @@ +/* $KAME: sainfo.h,v 1.6 2000/10/04 17:41:03 itojun 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. 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. + */ + +#include + +/* SA info */ +struct sainfo { + vchar_t *idsrc; + vchar_t *iddst; + /* + * idsrc and iddst are constructed body of ID payload. + * that is (struct ipsecdoi_id_b) + ID value. + * If idsrc == NULL, that is anonymous entry. + */ + + time_t lifetime; + int lifebyte; + int pfs_group; /* only use when pfs is required. */ + int idvtype; /* my identifier type */ + vchar_t *idv; /* my identifier */ + struct sainfoalg *algs[MAXALGCLASS]; + + LIST_ENTRY(sainfo) chain; +}; + +/* algorithm type */ +struct sainfoalg { + int alg; + int encklen; /* key length if encryption algorithm */ + struct sainfoalg *next; +}; + +extern struct sainfo *getsainfo __P((const vchar_t *, const vchar_t *)); +extern struct sainfo *newsainfo __P((void)); +extern void delsainfo __P((struct sainfo *)); +extern void inssainfo __P((struct sainfo *)); +extern void remsainfo __P((struct sainfo *)); +extern void flushsainfo __P((void)); +extern void initsainfo __P((void)); +extern struct sainfoalg *newsainfoalg __P((void)); +extern void delsainfoalg __P((struct sainfoalg *)); +extern void inssainfoalg __P((struct sainfoalg **, struct sainfoalg *)); +extern const char * sainfo2str __P((const struct sainfo *)); diff --git a/racoon.tproj/schedule.c b/racoon.tproj/schedule.c new file mode 100644 index 0000000..7b4a2fb --- /dev/null +++ b/racoon.tproj/schedule.c @@ -0,0 +1,358 @@ +/* $KAME: schedule.c,v 1.18 2001/10/08 23:58:22 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "misc.h" +#include "plog.h" +#include "schedule.h" +#include "var.h" +#include "gcmalloc.h" + +#define FIXY2038PROBLEM + +#ifndef TAILQ_FOREACH +#define TAILQ_FOREACH(elm, head, field) \ + for (elm = TAILQ_FIRST(head); elm; elm = TAILQ_NEXT(elm, field)) +#endif + +static struct timeval timeout; + +#ifdef FIXY2038PROBLEM +#define Y2038TIME_T 0x7fffffff +static time_t launched; /* time when the program launched. */ +static time_t deltaY2038; +#endif + +static TAILQ_HEAD(_schedtree, sched) sctree; + +static void sched_add __P((struct sched *)); +static time_t current_time __P((void)); + +/* + * schedule handler + * OUT: + * time to block until next event. + * if no entry, NULL returned. + */ +struct timeval * +schedular() +{ + time_t now, delta; + struct sched *p, *next = NULL; + + now = current_time(); + + for (p = TAILQ_FIRST(&sctree); p; p = next) { + /* if the entry has been daed, remove it */ + if (p->dead) + goto next_schedule; + + /* if the time hasn't come, proceed to the next entry */ + if (now < p->xtime) { + next = TAILQ_NEXT(p, chain); + continue; + } + + /* mark it with dead. and call the function. */ + p->dead = 1; + if (p->func != NULL) + (p->func)(p->param); + + next_schedule: + next = TAILQ_NEXT(p, chain); + TAILQ_REMOVE(&sctree, p, chain); + racoon_free(p); + } + + p = TAILQ_FIRST(&sctree); + if (p == NULL) + return NULL; + + now = current_time(); + + delta = p->xtime - now; + timeout.tv_sec = delta < 0 ? 0 : delta; + timeout.tv_usec = 0; + + return &timeout; +} + +/* + * add new schedule to schedule table. + */ +struct sched * +sched_new(tick, func, param) + time_t tick; + void (*func) __P((void *)); + void *param; +{ + static long id = 1; + struct sched *new; + + new = (struct sched *)racoon_malloc(sizeof(*new)); + if (new == NULL) + return NULL; + + memset(new, 0, sizeof(*new)); + new->func = func; + new->param = param; + + new->id = id++; + time(&new->created); + new->tick = tick; + + new->xtime = current_time() + tick; + new->dead = 0; + + /* add to schedule table */ + sched_add(new); + + return(new); +} + +/* add new schedule to schedule table */ +static void +sched_add(sc) + struct sched *sc; +{ + struct sched *p; + + TAILQ_FOREACH(p, &sctree, chain) { + if (sc->xtime < p->xtime) { + TAILQ_INSERT_BEFORE(p, sc, chain); + return; + } + } + if (p == NULL) + TAILQ_INSERT_TAIL(&sctree, sc, chain); + + return; +} + +/* get current time. + * if defined FIXY2038PROBLEM, base time is the time when called sched_init(). + * Otherwise, conform to time(3). + */ +static time_t +current_time() +{ + time_t n; +#ifdef FIXY2038PROBLEM + time_t t; + + time(&n); + t = n - launched; + if (t < 0) + t += deltaY2038; + + return t; +#else + return time(&n); +#endif +} + +void +sched_kill(sc) + struct sched *sc; +{ + sc->dead = 1; + + return; +} + +/* XXX this function is probably unnecessary. */ +void +sched_scrub_param(param) + void *param; +{ + struct sched *sc; + + TAILQ_FOREACH(sc, &sctree, chain) { + if (sc->param == param) { + if (!sc->dead) { + plog(LLV_DEBUG, LOCATION, NULL, + "an undead schedule has been deleted.\n"); + } + sched_kill(sc); + } + } +} + +/* + * for debug + */ +int +sched_dump(buf, len) + caddr_t *buf; + int *len; +{ + caddr_t new; + struct sched *p; + struct scheddump *dst; + int cnt = 0; + + /* initialize */ + *len = 0; + *buf = NULL; + + TAILQ_FOREACH(p, &sctree, chain) + cnt++; + + /* no entry */ + if (cnt == 0) + return -1; + + *len = cnt * sizeof(*dst); + + new = racoon_malloc(*len); + if (new == NULL) + return -1; + dst = (struct scheddump *)new; + + p = TAILQ_FIRST(&sctree); + while (p) { + dst->xtime = p->xtime; + dst->id = p->id; + dst->created = p->created; + dst->tick = p->tick; + + p = TAILQ_NEXT(p, chain); + if (p == NULL) + break; + dst++; + } + + *buf = new; + + return 0; +} + +/* initialize schedule table */ +void +sched_init() +{ +#ifdef FIXY2038PROBLEM + time(&launched); + + deltaY2038 = Y2038TIME_T - launched; +#endif + + TAILQ_INIT(&sctree); + + return; +} + +#ifdef STEST +#include +#include +#include +#include + +void +test(tick) + int *tick; +{ + printf("execute %d\n", *tick); + racoon_free(tick); +} + +void +getstdin() +{ + int *tick; + char buf[16]; + + read(0, buf, sizeof(buf)); + if (buf[0] == 'd') { + struct scheddump *scbuf, *p; + int len; + sched_dump((caddr_t *)&scbuf, &len); + if (buf == NULL) + return; + for (p = scbuf; len; p++) { + printf("xtime=%ld\n", p->xtime); + len -= sizeof(*p); + } + racoon_free(scbuf); + return; + } + + tick = (int *)racoon_malloc(sizeof(*tick)); + *tick = atoi(buf); + printf("new queue tick = %d\n", *tick); + sched_new(*tick, test, tick); +} + +int +main() +{ + static fd_set mask0; + int nfds = 0; + fd_set rfds; + struct timeval *timeout; + int error; + + FD_ZERO(&mask0); + FD_SET(0, &mask0); + nfds = 1; + + /* initialize */ + sched_init(); + + while (1) { + rfds = mask0; + + timeout = schedular(); + + error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); + if (error < 0) { + switch (errno) { + case EINTR: continue; + default: + err(1, "select"); + } + /*NOTREACHED*/ + } + + if (FD_ISSET(0, &rfds)) + getstdin(); + } +} +#endif diff --git a/racoon.tproj/schedule.h b/racoon.tproj/schedule.h new file mode 100644 index 0000000..94e7932 --- /dev/null +++ b/racoon.tproj/schedule.h @@ -0,0 +1,75 @@ +/* $KAME: schedule.h,v 1.11 2000/10/04 17:41:03 itojun 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. 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. + */ + +#include + +/* scheduling table */ +/* the head is the nearest event. */ +struct sched { + time_t xtime; /* event time which is as time(3). */ + /* + * if defined FIXY2038PROBLEM, this time + * is from the time when called sched_init(). + */ + void (*func) __P((void *)); /* call this function when timeout. */ + void *param; /* pointer to parameter */ + + int dead; /* dead or alive */ + long id; /* for debug */ + time_t created; /* for debug */ + time_t tick; /* for debug */ + + TAILQ_ENTRY(sched) chain; +}; + +/* cancel schedule */ +#define SCHED_KILL(s) \ +do { \ + sched_kill(s); \ + s = NULL; \ +} while(0) + +/* must be called after it's called from scheduler. */ +#define SCHED_INIT(s) (s) = NULL + +struct scheddump { + time_t xtime; + long id; + time_t created; + time_t tick; +}; + +struct timeval *schedular __P((void)); +struct sched *sched_new __P((time_t, void (*func) __P((void *)), void *)); +void sched_kill __P((struct sched *)); +int sched_dump __P((caddr_t *, int *)); +void sched_init __P((void)); +void sched_scrub_param __P((void *)); diff --git a/racoon.tproj/session.c b/racoon.tproj/session.c new file mode 100644 index 0000000..a6c9e78 --- /dev/null +++ b/racoon.tproj/session.c @@ -0,0 +1,400 @@ +/* $KAME: session.c,v 1.27 2001/11/16 04:34:57 sakane 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. 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. + */ + +#include +#include +#include +#include +#if HAVE_SYS_WAIT_H +# include +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(s) ((unsigned)(s) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(s) (((s) & 255) == 0) +#endif + +#ifdef IPV6_INRIA_VERSION +#include +#else +#include +#endif + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "libpfkey.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "schedule.h" +#include "session.h" +#include "grabmyaddr.h" +#include "cfparse.h" +#include "isakmp_var.h" +#include "admin_var.h" +#include "oakley.h" +#include "pfkey.h" +#include "handler.h" +#include "localconf.h" +#include "remoteconf.h" +#include "backupsa.h" + +static void close_session __P((void)); +static void check_rtsock __P((void *)); +static void initfds __P((void)); +static void init_signal __P((void)); +static int set_signal __P((int sig, RETSIGTYPE (*func) __P((int)))); +static void check_sigreq __P((void)); +static void check_flushsa_stub __P((void *)); +static void check_flushsa __P((void)); +static int close_sockets __P((void)); + +static fd_set mask0; +static int nfds = 0; +static int sigreq = 0; + +int +session(void) +{ + fd_set rfds; + struct timeval *timeout; + int error; + struct myaddrs *p; + + /* initialize schedular */ + sched_init(); + + init_signal(); + +#ifdef ENABLE_ADMINPORT + /* debug port has no authentication, do not open it */ + if (admin_init() < 0) + exit(1); +#endif + + initmyaddr(); + + if (isakmp_init() < 0) + exit(1); + + initfds(); + + sigreq = 0; + while (1) { + rfds = mask0; + + /* + * asynchronous requests via signal. + * make sure to reset sigreq to 0. + */ + check_sigreq(); + + /* scheduling */ + timeout = schedular(); + + error = select(nfds, &rfds, (fd_set *)0, (fd_set *)0, timeout); + if (error < 0) { + switch (errno) { + case EINTR: + continue; + default: + plog(LLV_ERROR, LOCATION, NULL, + "failed to select (%s)\n", + strerror(errno)); + return -1; + } + /*NOTREACHED*/ + } + +#ifdef ENABLE_ADMINPORT + if (FD_ISSET(lcconf->sock_admin, &rfds)) + admin_handler(); +#endif + + for (p = lcconf->myaddrs; p; p = p->next) { + if (!p->addr) + continue; + if (FD_ISSET(p->sock, &rfds)) + isakmp_handler(p->sock); + } + + if (FD_ISSET(lcconf->sock_pfkey, &rfds)) + pfkey_handler(); + + if (FD_ISSET(lcconf->rtsock, &rfds)) { + if (update_myaddrs() && lcconf->autograbaddr) + sched_new(5, check_rtsock, NULL); + initfds(); + } + } +} + +/* clear all status and exit program. */ +static void +close_session() +{ + flushph1(); + close_sockets(); + backupsa_clean(); + + plog(LLV_INFO, LOCATION, NULL, "racoon shutdown\n"); + exit(0); +} + +static void +check_rtsock(p) + void *p; +{ + isakmp_close(); + grab_myaddrs(); + autoconf_myaddrsport(); + isakmp_open(); + + /* initialize socket list again */ + initfds(); +} + +static void +initfds() +{ + struct myaddrs *p; + + nfds = 0; + + FD_ZERO(&mask0); + +#ifdef ENABLE_ADMINPORT + FD_SET(lcconf->sock_admin, &mask0); + nfds = (nfds > lcconf->sock_admin ? nfds : lcconf->sock_admin); +#endif + FD_SET(lcconf->sock_pfkey, &mask0); + nfds = (nfds > lcconf->sock_pfkey ? nfds : lcconf->sock_pfkey); + FD_SET(lcconf->rtsock, &mask0); + nfds = (nfds > lcconf->rtsock ? nfds : lcconf->rtsock); + + for (p = lcconf->myaddrs; p; p = p->next) { + if (!p->addr) + continue; + FD_SET(p->sock, &mask0); + nfds = (nfds > p->sock ? nfds : p->sock); + } + nfds++; +} + +static int signals[] = { + SIGHUP, + SIGINT, + SIGTERM, + SIGUSR1, + SIGUSR2, + SIGCHLD, + 0 +}; + +/* + * asynchronous requests will actually dispatched in the + * main loop in session(). + */ +RETSIGTYPE +signal_handler(sig) + int sig; +{ + switch (sig) { + case SIGCHLD: + { + pid_t pid; + int s; + + pid = wait(&s); + } + break; + +#ifdef DEBUG_RECORD_MALLOCATION + case SIGUSR2: + DRM_dump(); + break; +#endif + default: + /* XXX should be blocked any signal ? */ + sigreq = sig; + break; + } +} + +static void +check_sigreq() +{ + switch (sigreq) { + case 0: + return; + + case SIGHUP: + if (cfreparse()) { + plog(LLV_ERROR, LOCATION, NULL, + "configuration read failed\n"); + exit(1); + } + sigreq = 0; + break; + + default: + plog(LLV_INFO, LOCATION, NULL, "caught signal %d\n", sigreq); + pfkey_send_flush(lcconf->sock_pfkey, SADB_SATYPE_UNSPEC); + sched_new(1, check_flushsa_stub, NULL); + sigreq = 0; + break; + } +} + +/* + * waiting the termination of processing until sending DELETE message + * for all inbound SA will complete. + */ +static void +check_flushsa_stub(p) + void *p; +{ + + check_flushsa(); +} + +static void +check_flushsa() +{ + vchar_t *buf; + struct sadb_msg *msg, *end, *next; + struct sadb_sa *sa; + caddr_t mhp[SADB_EXT_MAX + 1]; + int n; + + buf = pfkey_dump_sadb(SADB_SATYPE_UNSPEC); + + msg = (struct sadb_msg *)buf->v; + end = (struct sadb_msg *)(buf->v + buf->l); + + /* counting SA except of dead one. */ + n = 0; + while (msg < end) { + if (PFKEY_UNUNIT64(msg->sadb_msg_len) < sizeof(*msg)) + break; + next = (struct sadb_msg *)((caddr_t)msg + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (msg->sadb_msg_type != SADB_DUMP) { + msg = next; + continue; + } + + if (pfkey_align(msg, mhp) || pfkey_check(mhp)) { + plog(LLV_ERROR, LOCATION, NULL, + "pfkey_check (%s)\n", ipsec_strerror()); + msg = next; + continue; + } + + sa = (struct sadb_sa *)(mhp[SADB_EXT_SA]); + if (!sa) { + msg = next; + continue; + } + + if (sa->sadb_sa_state != SADB_SASTATE_DEAD) { + n++; + msg = next; + continue; + } + + msg = next; + } + + if (n) { + sched_new(1, check_flushsa_stub, NULL); + return; + } + + close_session(); +} + +static void +init_signal() +{ + int i; + + for (i = 0; signals[i] != 0; i++) + if (set_signal(signals[i], signal_handler) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to set_signal (%s)\n", + strerror(errno)); + exit(1); + } +} + +static int +set_signal(sig, func) + int sig; + RETSIGTYPE (*func) __P((int)); +{ + struct sigaction sa; + + memset((caddr_t)&sa, 0, sizeof(sa)); + sa.sa_handler = func; + sa.sa_flags = SA_RESTART; + + if (sigemptyset(&sa.sa_mask) < 0) + return -1; + + if (sigaction(sig, &sa, (struct sigaction *)0) < 0) + return(-1); + + return 0; +} + +static int +close_sockets() +{ + isakmp_close(); + pfkey_close(lcconf->sock_pfkey); +#ifdef ENABLE_ADMINPORT + (void)admin_close(); +#endif + return 0; +} + diff --git a/racoon.tproj/session.h b/racoon.tproj/session.h new file mode 100644 index 0000000..ecd4ab5 --- /dev/null +++ b/racoon.tproj/session.h @@ -0,0 +1,33 @@ +/* $KAME: session.h,v 1.3 2000/09/13 04:50:29 itojun 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. 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. + */ + +extern int session __P((void)); +extern RETSIGTYPE signal_handler __P((int)); diff --git a/racoon.tproj/sha2.c b/racoon.tproj/sha2.c new file mode 100644 index 0000000..80deb6a --- /dev/null +++ b/racoon.tproj/sha2.c @@ -0,0 +1,1102 @@ +/* $KAME: sha2.c,v 1.4 2001/09/02 08:59:55 itojun Exp $ */ + +/* + * sha2.c + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. 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. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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. + * + */ + + +#include +#include +#include +#include +#include + +#include +#include +#define bcopy(a, b, c) memcpy((b), (a), (c)) +#define bzero(a, b) memset((a), 0, (b)) +#define panic(a) err(1, (a)) + +/* + * ASSERT NOTE: + * Some sanity checking code is included using assert(). On my FreeBSD + * system, this additional code can be removed by compiling with NDEBUG + * defined. Check your own systems manpage on assert() to see how to + * compile WITHOUT the sanity checking code on your system. + * + * UNROLLED TRANSFORM LOOP NOTE: + * You can define SHA2_UNROLL_TRANSFORM to use the unrolled transform + * loop version for the hash transform rounds (defined using macros + * later in this file). Either define on the command line, for example: + * + * cc -DSHA2_UNROLL_TRANSFORM -o sha2 sha2.c sha2prog.c + * + * or define below: + * + * #define SHA2_UNROLL_TRANSFORM + * + */ + +#define assert(x) + + +/*** SHA-256/384/512 Machine Architecture Definitions *****************/ +/* + * BYTE_ORDER NOTE: + * + * Please make sure that your system defines BYTE_ORDER. If your + * architecture is little-endian, make sure it also defines + * LITTLE_ENDIAN and that the two (BYTE_ORDER and LITTLE_ENDIAN) are + * equivilent. + * + * If your system does not define the above, then you can do so by + * hand like this: + * + * #define LITTLE_ENDIAN 1234 + * #define BIG_ENDIAN 4321 + * + * And for little-endian machines, add: + * + * #define BYTE_ORDER LITTLE_ENDIAN + * + * Or for big-endian machines: + * + * #define BYTE_ORDER BIG_ENDIAN + * + * The FreeBSD machine this was written on defines BYTE_ORDER + * appropriately by including (which in turn includes + * where the appropriate definitions are actually + * made). + */ +#if !defined(BYTE_ORDER) || (BYTE_ORDER != LITTLE_ENDIAN && BYTE_ORDER != BIG_ENDIAN) +#error Define BYTE_ORDER to be equal to either LITTLE_ENDIAN or BIG_ENDIAN +#endif + +/* + * Define the followingsha2_* types to types of the correct length on + * the native archtecture. Most BSD systems and Linux define u_intXX_t + * types. Machines with very recent ANSI C headers, can use the + * uintXX_t definintions from inttypes.h by defining SHA2_USE_INTTYPES_H + * during compile or in the sha.h header file. + * + * Machines that support neither u_intXX_t nor inttypes.h's uintXX_t + * will need to define these three typedefs below (and the appropriate + * ones in sha.h too) by hand according to their system architecture. + * + * Thank you, Jun-ichiro itojun Hagino, for suggesting using u_intXX_t + * types and pointing out recent ANSI C support for uintXX_t in inttypes.h. + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +#else /* SHA2_USE_INTTYPES_H */ + +typedef u_int8_t sha2_byte; /* Exactly 1 byte */ +typedef u_int32_t sha2_word32; /* Exactly 4 bytes */ +typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ + +#endif /* SHA2_USE_INTTYPES_H */ + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +/* NOTE: Most of these are in sha2.h */ +#define SHA256_SHORT_BLOCK_LENGTH (SHA256_BLOCK_LENGTH - 8) +#define SHA384_SHORT_BLOCK_LENGTH (SHA384_BLOCK_LENGTH - 16) +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + +/*** ENDIAN REVERSAL MACROS *******************************************/ +#if BYTE_ORDER == LITTLE_ENDIAN +#define REVERSE32(w,x) { \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \ +} +#define REVERSE64(w,x) { \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \ + ((tmp & 0x00ff00ff00ff00ffULL) << 8); \ + (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \ + ((tmp & 0x0000ffff0000ffffULL) << 16); \ +} +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + +/*** THE SIX LOGICAL FUNCTIONS ****************************************/ +/* + * Bit shifting and rotation (used by the six SHA-XYZ logical functions: + * + * NOTE: The naming of R and S appears backwards here (R is a SHIFT and + * S is a ROTATION) because the SHA-256/384/512 description document + * (see http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf) uses this + * same "backwards" definition. + */ +/* Shift-right (used in SHA-256, SHA-384, and SHA-512): */ +#define R(b,x) ((x) >> (b)) +/* 32-bit Rotate-right (used in SHA-256): */ +#define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b)))) +/* 64-bit Rotate-right (used in SHA-384 and SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + +/* Two of six logical functions used in SHA-256, SHA-384, and SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +/* Four of six logical functions used in SHA-256: */ +#define Sigma0_256(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x))) +#define Sigma1_256(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x))) +#define sigma0_256(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x))) +#define sigma1_256(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x))) + +/* Four of six logical functions used in SHA-384 and SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +/*** INTERNAL FUNCTION PROTOTYPES *************************************/ +/* NOTE: These should not be accessed directly from outside this + * library -- they are intended for private internal visibility/use + * only. + */ +void SHA512_Last(SHA512_CTX*); +void SHA256_Transform(SHA256_CTX*, const sha2_word32*); +void SHA512_Transform(SHA512_CTX*, const sha2_word64*); + + +/*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ +/* Hash constant words K for SHA-256: */ +const static sha2_word32 K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; + +/* Initial hash value H for SHA-256: */ +const static sha2_word32 sha256_initial_hash_value[8] = { + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const static sha2_word64 K512[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 +}; + +/* Initial hash value H for SHA-384 */ +const static sha2_word64 sha384_initial_hash_value[8] = { + 0xcbbb9d5dc1059ed8ULL, + 0x629a292a367cd507ULL, + 0x9159015a3070dd17ULL, + 0x152fecd8f70e5939ULL, + 0x67332667ffc00b31ULL, + 0x8eb44a8768581511ULL, + 0xdb0c2e0d64f98fa7ULL, + 0x47b5481dbefa4fa4ULL +}; + +/* Initial hash value H for SHA-512 */ +const static sha2_word64 sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ +static const char *sha2_hex_digits = "0123456789abcdef"; + + +/*** SHA-256: *********************************************************/ +void SHA256_Init(SHA256_CTX* context) { + if (context == (SHA256_CTX*)0) { + return; + } + bcopy(sha256_initial_hash_value, context->state, SHA256_DIGEST_LENGTH); + bzero(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-256 round macros: */ + +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + W256[j]; \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND256(a,b,c,d,e,f,g,h) \ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA256_Transform(context, (const sha2_word32*)data); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA256_Final(sha2_byte digest[], SHA256_CTX* context) { + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + bzero(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + *(sha2_word64*)&context->buffer[SHA256_SHORT_BLOCK_LENGTH] = context->bitcount; + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA256_DIGEST_LENGTH); +#endif + } + + /* Clean up state data: */ + bzero(context, sizeof(context)); + usedspace = 0; +} + +char *SHA256_End(SHA256_CTX* context, char buffer[]) { + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA256_DIGEST_LENGTH); + return buffer; +} + +char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { + SHA256_CTX context; + + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); +} + + +/*** SHA-512: *********************************************************/ +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + bcopy(sha512_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +#ifdef SHA2_UNROLL_TRANSFORM + +/* Unrolled SHA-512 round macros: */ +#if BYTE_ORDER == LITTLE_ENDIAN + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + W512[j]; \ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ + + +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + K512[j] + (W512[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#define ROUND512(a,b,c,d,e,f,g,h) \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; +} + +#else /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; +#else /* BYTE_ORDER == LITTLE_ENDIAN */ + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + +#endif /* SHA2_UNROLL_TRANSFORM */ + +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (const sha2_word64*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +void SHA512_Last(SHA512_CTX* context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; +#if BYTE_ORDER == LITTLE_ENDIAN + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); +#endif + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(sha2_word64*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); +} + +void SHA512_Final(sha2_byte digest[], SHA512_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA512_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA512_End(SHA512_CTX* context, char buffer[]) { + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA512_DIGEST_LENGTH); + return buffer; +} + +char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); +} + + +/*** SHA-384: *********************************************************/ +void SHA384_Init(SHA384_CTX* context) { + if (context == (SHA384_CTX*)0) { + return; + } + bcopy(sha384_initial_hash_value, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + +void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { + SHA512_Update((SHA512_CTX*)context, data, len); +} + +void SHA384_Final(sha2_byte digest[], SHA384_CTX* context) { + sha2_word64 *d = (sha2_word64*)digest; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); + + /* Save the hash data for output: */ +#if BYTE_ORDER == LITTLE_ENDIAN + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } +#else + bcopy(context->state, d, SHA384_DIGEST_LENGTH); +#endif + } + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +char *SHA384_End(SHA384_CTX* context, char buffer[]) { + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + bzero(context, sizeof(context)); + } + bzero(digest, SHA384_DIGEST_LENGTH); + return buffer; +} + +char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { + SHA384_CTX context; + + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); +} + +/*glue*/ +static struct env_md_st sha2_256_md = { + 0, /*NID_sha1*/ + 0, /*NID_sha1WithRSAEncryption*/ + SHA256_DIGEST_LENGTH, + SHA256_Init, + SHA256_Update, + SHA256_Final, + NULL, NULL, {0, 0, 0, 0}, + SHA256_BLOCK_LENGTH, + sizeof(struct env_md_st *) + sizeof(SHA256_CTX), +}; + +struct env_md_st *EVP_sha2_256(void) +{ + return(&sha2_256_md); +} + +static struct env_md_st sha2_384_md = { + 0, /*NID_sha1*/ + 0, /*NID_sha1WithRSAEncryption*/ + SHA384_DIGEST_LENGTH, + SHA384_Init, + SHA384_Update, + SHA384_Final, + NULL, NULL, {0, 0, 0, 0}, + SHA384_BLOCK_LENGTH, + sizeof(struct env_md_st *) + sizeof(SHA384_CTX), +}; + +struct env_md_st *EVP_sha2_384(void) +{ + return(&sha2_384_md); +} + +static struct env_md_st sha2_512_md = { + 0, /*NID_sha1*/ + 0, /*NID_sha1WithRSAEncryption*/ + SHA512_DIGEST_LENGTH, + SHA512_Init, + SHA512_Update, + SHA512_Final, + NULL, NULL, {0, 0, 0, 0}, /*EVP_PKEY_RSA_method*/ + SHA512_BLOCK_LENGTH, + sizeof(struct env_md_st *) + sizeof(SHA512_CTX), +}; + +struct env_md_st *EVP_sha2_512(void) +{ + return(&sha2_512_md); +} diff --git a/racoon.tproj/sha2.h b/racoon.tproj/sha2.h new file mode 100644 index 0000000..65f1d45 --- /dev/null +++ b/racoon.tproj/sha2.h @@ -0,0 +1,144 @@ +/* $KAME: sha2.h,v 1.1.1.1 2001/08/08 09:56:28 sakane Exp $ */ + +/* + * sha2.h + * + * Version 1.0.0beta1 + * + * Written by Aaron D. Gifford + * + * Copyright 2000 Aaron D. Gifford. 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. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTOR(S) ``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(S) OR CONTRIBUTOR(S) 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. + * + */ + +#ifndef __SHA2_H__ +#define __SHA2_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +/*** SHA-256/384/512 Various Length Definitions ***********************/ +#define SHA256_BLOCK_LENGTH 64 +#define SHA256_DIGEST_LENGTH 32 +#define SHA256_DIGEST_STRING_LENGTH (SHA256_DIGEST_LENGTH * 2 + 1) +#define SHA384_BLOCK_LENGTH 128 +#define SHA384_DIGEST_LENGTH 48 +#define SHA384_DIGEST_STRING_LENGTH (SHA384_DIGEST_LENGTH * 2 + 1) +#define SHA512_BLOCK_LENGTH 128 +#define SHA512_DIGEST_LENGTH 64 +#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1) + + +/*** SHA-256/384/512 Context Structures *******************************/ +/* NOTE: If your architecture does not define either u_intXX_t types or + * uintXX_t (from inttypes.h), you may need to define things by hand + * for your system: + */ +#if 0 +typedef unsigned char u_int8_t; /* 1-byte (8-bits) */ +typedef unsigned int u_int32_t; /* 4-bytes (32-bits) */ +typedef unsigned long long u_int64_t; /* 8-bytes (64-bits) */ +#endif +/* + * Most BSD systems already define u_intXX_t types, as does Linux. + * Some systems, however, like Compaq's Tru64 Unix instead can use + * uintXX_t types defined by very recent ANSI C standards and included + * in the file: + * + * #include + * + * If you choose to use then please define: + * + * #define SHA2_USE_INTTYPES_H + * + * Or on the command line during compile: + * + * cc -DSHA2_USE_INTTYPES_H ... + */ +#if 0 /*def SHA2_USE_INTTYPES_H*/ + +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#else /* SHA2_USE_INTTYPES_H */ + +typedef struct _SHA256_CTX { + u_int32_t state[8]; + u_int64_t bitcount; + u_int8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + u_int64_t state[8]; + u_int64_t bitcount[2]; + u_int8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +#endif /* SHA2_USE_INTTYPES_H */ + +typedef SHA512_CTX SHA384_CTX; + + +/*** SHA-256/384/512 Function Prototypes ******************************/ + +void SHA256_Init __P((SHA256_CTX *)); +void SHA256_Update __P((SHA256_CTX*, const u_int8_t*, size_t)); +void SHA256_Final __P((u_int8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*)); +char* SHA256_End __P((SHA256_CTX*, char[SHA256_DIGEST_STRING_LENGTH])); +char* SHA256_Data __P((const u_int8_t*, size_t, char[SHA256_DIGEST_STRING_LENGTH])); + +void SHA384_Init __P((SHA384_CTX*)); +void SHA384_Update __P((SHA384_CTX*, const u_int8_t*, size_t)); +void SHA384_Final __P((u_int8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*)); +char* SHA384_End __P((SHA384_CTX*, char[SHA384_DIGEST_STRING_LENGTH])); +char* SHA384_Data __P((const u_int8_t*, size_t, char[SHA384_DIGEST_STRING_LENGTH])); + +void SHA512_Init __P((SHA512_CTX*)); +void SHA512_Update __P((SHA512_CTX*, const u_int8_t*, size_t)); +void SHA512_Final __P((u_int8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*)); +char* SHA512_End __P((SHA512_CTX*, char[SHA512_DIGEST_STRING_LENGTH])); +char* SHA512_Data __P((const u_int8_t*, size_t, char[SHA512_DIGEST_STRING_LENGTH])); + +struct env_md_st *EVP_sha2_256 __P((void)); +struct env_md_st *EVP_sha2_384 __P((void)); +struct env_md_st *EVP_sha2_512 __P((void)); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SHA2_H__ */ + diff --git a/racoon.tproj/sockmisc.c b/racoon.tproj/sockmisc.c new file mode 100644 index 0000000..15883ba --- /dev/null +++ b/racoon.tproj/sockmisc.c @@ -0,0 +1,785 @@ +/* $KAME: sockmisc.c,v 1.34 2001/12/07 21:35:46 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#ifdef IPV6_INRIA_VERSION +#include +#define IPV6_RECVDSTADDR IP_RECVDSTADDR +#else +#include +#endif +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "var.h" +#include "misc.h" +#include "plog.h" +#include "sockmisc.h" +#include "debug.h" +#include "gcmalloc.h" + +const int niflags = 0; + +/* + * compare two sockaddr without port number. + * OUT: 0: equal. + * 1: not equal. + */ +int +cmpsaddrwop(addr1, addr2) + struct sockaddr *addr1; + struct sockaddr *addr2; +{ + caddr_t sa1, sa2; + + if (addr1 == 0 && addr2 == 0) + return 0; + if (addr1 == 0 || addr2 == 0) + return 1; + + if (addr1->sa_len != addr2->sa_len + || addr1->sa_family != addr2->sa_family) + return 1; + + switch (addr1->sa_family) { + case AF_INET: + sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr; + if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0) + return 1; + break; +#ifdef INET6 + case AF_INET6: + sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr; + if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0) + return 1; + if (((struct sockaddr_in6 *)addr1)->sin6_scope_id != + ((struct sockaddr_in6 *)addr2)->sin6_scope_id) + return 1; + break; +#endif + default: + return 1; + } + + return 0; +} + +/* + * compare two sockaddr with port, taking care wildcard. + * addr1 is a subject address, addr2 is in a database entry. + * OUT: 0: equal. + * 1: not equal. + */ +int +cmpsaddrwild(addr1, addr2) + struct sockaddr *addr1; + struct sockaddr *addr2; +{ + caddr_t sa1, sa2; + u_short port1, port2; + + if (addr1 == 0 && addr2 == 0) + return 0; + if (addr1 == 0 || addr2 == 0) + return 1; + + if (addr1->sa_len != addr2->sa_len + || addr1->sa_family != addr2->sa_family) + return 1; + + switch (addr1->sa_family) { + case AF_INET: + sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr; + port1 = ((struct sockaddr_in *)addr1)->sin_port; + port2 = ((struct sockaddr_in *)addr2)->sin_port; + if (!(port1 == IPSEC_PORT_ANY || + port2 == IPSEC_PORT_ANY || + port1 == port2)) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0) + return 1; + break; +#ifdef INET6 + case AF_INET6: + sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr; + port1 = ((struct sockaddr_in6 *)addr1)->sin6_port; + port2 = ((struct sockaddr_in6 *)addr2)->sin6_port; + if (!(port1 == IPSEC_PORT_ANY || + port2 == IPSEC_PORT_ANY || + port1 == port2)) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0) + return 1; + if (((struct sockaddr_in6 *)addr1)->sin6_scope_id != + ((struct sockaddr_in6 *)addr2)->sin6_scope_id) + return 1; + break; +#endif + default: + return 1; + } + + return 0; +} + +/* + * compare two sockaddr with strict match on port. + * OUT: 0: equal. + * 1: not equal. + */ +int +cmpsaddrstrict(addr1, addr2) + struct sockaddr *addr1; + struct sockaddr *addr2; +{ + caddr_t sa1, sa2; + u_short port1, port2; + + if (addr1 == 0 && addr2 == 0) + return 0; + if (addr1 == 0 || addr2 == 0) + return 1; + + if (addr1->sa_len != addr2->sa_len + || addr1->sa_family != addr2->sa_family) + return 1; + + switch (addr1->sa_family) { + case AF_INET: + sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr; + sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr; + port1 = ((struct sockaddr_in *)addr1)->sin_port; + port2 = ((struct sockaddr_in *)addr2)->sin_port; + if (port1 != port2) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0) + return 1; + break; +#ifdef INET6 + case AF_INET6: + sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr; + sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr; + port1 = ((struct sockaddr_in6 *)addr1)->sin6_port; + port2 = ((struct sockaddr_in6 *)addr2)->sin6_port; + if (port1 != port2) + return 1; + if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0) + return 1; + if (((struct sockaddr_in6 *)addr1)->sin6_scope_id != + ((struct sockaddr_in6 *)addr2)->sin6_scope_id) + return 1; + break; +#endif + default: + return 1; + } + + return 0; +} + +/* get local address against the destination. */ +struct sockaddr * +getlocaladdr(remote) + struct sockaddr *remote; +{ + struct sockaddr *local; + int local_len = sizeof(struct sockaddr_storage); + int s; /* for dummy connection */ + + /* allocate buffer */ + if ((local = racoon_calloc(1, local_len)) == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to get address buffer.\n"); + goto err; + } + + /* get real interface received packet */ + if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket (%s)\n", strerror(errno)); + goto err; + } + + if (connect(s, remote, remote->sa_len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "connect (%s)\n", strerror(errno)); + close(s); + goto err; + } + + if (getsockname(s, local, &local_len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getsockname (%s)\n", strerror(errno)); + close(s); + return NULL; + } + + close(s); + return local; + + err: + if (local != NULL) + racoon_free(local); + return NULL; +} + +/* + * Receive packet, with src/dst information. It is assumed that necessary + * setsockopt() have already performed on socket. + */ +int +recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen) + int s; + void *buf; + size_t buflen; + int flags; + struct sockaddr *from; + int *fromlen; + struct sockaddr *to; + int *tolen; +{ + int otolen; + int len; + struct sockaddr_storage ss; + struct msghdr m; + struct cmsghdr *cm; + struct iovec iov[2]; + u_char cmsgbuf[256]; +#if defined(INET6) && defined(ADVAPI) + struct in6_pktinfo *pi; +#endif /*ADVAPI*/ + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + len = sizeof(ss); + if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getsockname (%s)\n", strerror(errno)); + return -1; + } + + m.msg_name = (caddr_t)from; + m.msg_namelen = *fromlen; + iov[0].iov_base = (caddr_t)buf; + iov[0].iov_len = buflen; + m.msg_iov = iov; + m.msg_iovlen = 1; + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + cm = (struct cmsghdr *)cmsgbuf; + m.msg_control = (caddr_t)cm; + m.msg_controllen = sizeof(cmsgbuf); + if ((len = recvmsg(s, &m, flags)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "recvmsg (%s)\n", strerror(errno)); + return -1; + } + *fromlen = m.msg_namelen; + + otolen = *tolen; + *tolen = 0; + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m); + m.msg_controllen != 0 && cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) { +#if 0 + plog(LLV_ERROR, LOCATION, NULL, + "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);) +#endif +#if defined(INET6) && defined(ADVAPI) + if (ss.ss_family == AF_INET6 + && cm->cmsg_level == IPPROTO_IPV6 + && cm->cmsg_type == IPV6_PKTINFO + && otolen >= sizeof(*sin6)) { + pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); + *tolen = sizeof(*sin6); + sin6 = (struct sockaddr_in6 *)to; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); + memcpy(&sin6->sin6_addr, &pi->ipi6_addr, + sizeof(sin6->sin6_addr)); + /* XXX other cases, such as site-local? */ + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + sin6->sin6_scope_id = pi->ipi6_ifindex; + else + sin6->sin6_scope_id = 0; + sin6->sin6_port = + ((struct sockaddr_in6 *)&ss)->sin6_port; + otolen = -1; /* "to" already set */ + continue; + } +#endif +#if defined(INET6) && defined(IPV6_RECVDSTADDR) + if (ss.ss_family == AF_INET6 + && cm->cmsg_level == IPPROTO_IPV6 + && cm->cmsg_type == IPV6_RECVDSTADDR + && otolen >= sizeof(*sin6)) { + *tolen = sizeof(*sin6); + sin6 = (struct sockaddr_in6 *)to; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); + memcpy(&sin6->sin6_addr, CMSG_DATA(cm), + sizeof(sin6->sin6_addr)); + sin6->sin6_port = + ((struct sockaddr_in6 *)&ss)->sin6_port; + otolen = -1; /* "to" already set */ + continue; + } +#endif + if (ss.ss_family == AF_INET + && cm->cmsg_level == IPPROTO_IP + && cm->cmsg_type == IP_RECVDSTADDR + && otolen >= sizeof(*sin)) { + *tolen = sizeof(*sin); + sin = (struct sockaddr_in *)to; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + memcpy(&sin->sin_addr, CMSG_DATA(cm), + sizeof(sin->sin_addr)); + sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port; + otolen = -1; /* "to" already set */ + continue; + } + } + + return len; +} + +/* send packet, with fixing src/dst address pair. */ +int +sendfromto(s, buf, buflen, src, dst, cnt) + int s, cnt; + const void *buf; + size_t buflen; + struct sockaddr *src; + struct sockaddr *dst; +{ + struct sockaddr_storage ss; + int len; + int i; + + if (src->sa_family != dst->sa_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch\n"); + return -1; + } + + len = sizeof(ss); + if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getsockname (%s)\n", strerror(errno)); + return -1; + } + + plog(LLV_DEBUG, LOCATION, NULL, + "sockname %s\n", saddr2str((struct sockaddr *)&ss)); + plog(LLV_DEBUG, LOCATION, NULL, + "send packet from %s\n", saddr2str(src)); + plog(LLV_DEBUG, LOCATION, NULL, + "send packet to %s\n", saddr2str(dst)); + + if (src->sa_family != ss.ss_family) { + plog(LLV_ERROR, LOCATION, NULL, + "address family mismatch\n"); + return -1; + } + + switch (src->sa_family) { +#if defined(INET6) && defined(ADVAPI) && !defined(IPV6_INRIA_VERSION) + case AF_INET6: + { + struct msghdr m; + struct cmsghdr *cm; + struct iovec iov[2]; + u_char cmsgbuf[256]; + struct in6_pktinfo *pi; + int ifindex; + struct sockaddr_in6 src6, dst6; + + memcpy(&src6, src, sizeof(src6)); + memcpy(&dst6, dst, sizeof(dst6)); + + /* XXX take care of other cases, such as site-local */ + ifindex = 0; + if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr) + || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) { + ifindex = src6.sin6_scope_id; /*???*/ + } + + /* XXX some sanity check on dst6.sin6_scope_id */ + + /* flowinfo for IKE? mmm, maybe useful but for now make it 0 */ + src6.sin6_flowinfo = dst6.sin6_flowinfo = 0; + + memset(&m, 0, sizeof(m)); + m.msg_name = (caddr_t)&dst6; + m.msg_namelen = sizeof(dst6); + iov[0].iov_base = (char *)buf; + iov[0].iov_len = buflen; + m.msg_iov = iov; + m.msg_iovlen = 1; + + memset(cmsgbuf, 0, sizeof(cmsgbuf)); + cm = (struct cmsghdr *)cmsgbuf; + m.msg_control = (caddr_t)cm; + m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + pi = (struct in6_pktinfo *)CMSG_DATA(cm); + memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr)); + pi->ipi6_ifindex = ifindex; + + plog(LLV_DEBUG, LOCATION, NULL, + "src6 %s %d\n", + saddr2str((struct sockaddr *)&src6), + src6.sin6_scope_id); + plog(LLV_DEBUG, LOCATION, NULL, + "dst6 %s %d\n", + saddr2str((struct sockaddr *)&dst6), + dst6.sin6_scope_id); + + for (i = 0; i < cnt; i++) { + len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/); + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "sendmsg (%s)\n", strerror(errno)); + return -1; + } + plog(LLV_DEBUG, LOCATION, NULL, + "%d times of %d bytes message will be sent " + "to %s\n", + i + 1, len, saddr2str(src)); + } + plogdump(LLV_DEBUG, (char *)buf, buflen); + + return len; + } +#endif + default: + { + int needclose = 0; + int sendsock; + + if (ss.ss_family == src->sa_family && memcmp(&ss, src, src->sa_len) == 0) { + sendsock = s; + needclose = 0; + } else { + int yes = 1; + /* + * Use newly opened socket for sending packets. + * NOTE: this is unsafe, because if the peer is quick enough + * the packet from the peer may be queued into sendsock. + * Better approach is to prepare bind'ed udp sockets for + * each of the interface addresses. + */ + sendsock = socket(src->sa_family, SOCK_DGRAM, 0); + if (sendsock < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "socket (%s)\n", strerror(errno)); + return -1; + } + if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEPORT, + (void *)&yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", strerror(errno)); + return -1; + } +#ifdef IPV6_USE_MIN_MTU + if (src->sa_family == AF_INET6 && + setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + (void *)&yes, sizeof(yes)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", strerror(errno)); + return -1; + } +#endif + if (setsockopt_bypass(sendsock, src->sa_family) < 0) + return -1; + + if (bind(sendsock, (struct sockaddr *)src, src->sa_len) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "bind 1 (%s)\n", strerror(errno)); + return -1; + } + needclose = 1; + } + + for (i = 0; i < cnt; i++) { + len = sendto(sendsock, buf, buflen, 0, dst, dst->sa_len); + if (len < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "sendto (%s)\n", strerror(errno)); + return len; + } + plog(LLV_DEBUG, LOCATION, NULL, + "%d times of %d bytes message will be sent " + "to %s\n", + i + 1, len, saddr2str(src)); + } + plogdump(LLV_DEBUG, (char *)buf, buflen); + + if (needclose) + close(sendsock); + + return len; + } + } +} + +int +setsockopt_bypass(so, family) + int so, family; +{ + int level; + char *buf; + char *policy; + + switch (family) { + case AF_INET: + level = IPPROTO_IP; + break; +#ifdef INET6 + case AF_INET6: + level = IPPROTO_IPV6; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "unsupported address family %d\n", family); + return -1; + } + + policy = "in bypass"; + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "ipsec_set_policy (%s)\n", + ipsec_strerror()); + return -1; + } + if (setsockopt(so, level, + (level == IPPROTO_IP ? + IP_IPSEC_POLICY : IPV6_IPSEC_POLICY), + buf, ipsec_get_policylen(buf)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", + strerror(errno)); + return -1; + } + racoon_free(buf); + + policy = "out bypass"; + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "ipsec_set_policy (%s)\n", + ipsec_strerror()); + return -1; + } + if (setsockopt(so, level, + (level == IPPROTO_IP ? + IP_IPSEC_POLICY : IPV6_IPSEC_POLICY), + buf, ipsec_get_policylen(buf)) < 0) { + plog(LLV_ERROR, LOCATION, NULL, + "setsockopt (%s)\n", + strerror(errno)); + return -1; + } + racoon_free(buf); + + return 0; +} + +struct sockaddr * +newsaddr(len) + int len; +{ + struct sockaddr *new; + + new = racoon_calloc(1, len); + if (new == NULL) + plog(LLV_ERROR, LOCATION, NULL, + "%s\n", strerror(errno)); + + /* initial */ + new->sa_len = len; + + return new; +} + +struct sockaddr * +dupsaddr(src) + struct sockaddr *src; +{ + struct sockaddr *dst; + + dst = racoon_calloc(1, src->sa_len); + if (dst == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "%s\n", strerror(errno)); + return NULL; + } + + memcpy(dst, src, src->sa_len); + + return dst; +} + +char * +saddr2str(saddr) + const struct sockaddr *saddr; +{ + static char buf[NI_MAXHOST + NI_MAXSERV + 10]; + char addr[NI_MAXHOST], port[NI_MAXSERV]; + + if (saddr == NULL) + return NULL; + + GETNAMEINFO(saddr, addr, port); + snprintf(buf, sizeof(buf), "%s[%s]", addr, port); + + return buf; +} + +char * +saddrwop2str(saddr) + struct sockaddr *saddr; +{ + static char buf[NI_MAXHOST + NI_MAXSERV + 10]; + char addr[NI_MAXHOST]; + + if (saddr == NULL) + return NULL; + + GETNAMEINFO(saddr, addr, NULL); + snprintf(buf, sizeof(buf), "%s", addr); + + return buf; +} + +struct sockaddr * +str2saddr(host, port) + char *host; + char *port; +{ + struct addrinfo hints, *res; + struct sockaddr *saddr; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(host, port, &hints, &res); + if (error != 0) { + plog(LLV_ERROR, LOCATION, NULL, + "getaddrinfo(%s%s%s): %s", + host, port ? "," : "", port ? port : "", + gai_strerror(error)); + return NULL; + } + if (res->ai_next != NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "getaddrinfo(%s%s%s): " + "resolved to multiple address, " + "taking the first one", + host, port ? "," : "", port ? port : ""); + } + saddr = racoon_malloc(res->ai_addrlen); + if (saddr == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "failed to allocate buffer.\n"); + freeaddrinfo(res); + return NULL; + } + memcpy(saddr, res->ai_addr, res->ai_addrlen); + + return saddr; +} + +void +mask_sockaddr(a, b, l) + struct sockaddr *a; + const struct sockaddr *b; + size_t l; +{ + size_t i; + u_int8_t *p, alen; + + switch (b->sa_family) { + case AF_INET: + alen = sizeof(struct in_addr); + p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr; + break; +#ifdef INET6 + case AF_INET6: + alen = sizeof(struct in6_addr); + p = (u_int8_t *)&((struct sockaddr_in6 *)a)->sin6_addr; + break; +#endif + default: + plog(LLV_ERROR, LOCATION, NULL, + "invalid family: %d\n", b->sa_family); + exit(1); + } + + if ((alen << 3) < l) { + plog(LLV_ERROR, LOCATION, NULL, + "unexpected inconsistency: %d %d\n", b->sa_family, l); + exit(1); + } + + memcpy(a, b, b->sa_len); + p[l / 8] &= (0xff00 >> (l % 8)) & 0xff; + for (i = l / 8 + 1; i < alen; i++) + p[i] = 0x00; +} diff --git a/racoon.tproj/sockmisc.h b/racoon.tproj/sockmisc.h new file mode 100644 index 0000000..22d5b4f --- /dev/null +++ b/racoon.tproj/sockmisc.h @@ -0,0 +1,53 @@ +/* $KAME: sockmisc.h,v 1.11 2001/08/16 14:37:29 itojun 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. 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. + */ + +extern const int niflags; + +extern int cmpsaddrwop __P((struct sockaddr *, struct sockaddr *)); +extern int cmpsaddrwild __P((struct sockaddr *, struct sockaddr *)); +extern int cmpsaddrstrict __P((struct sockaddr *, struct sockaddr *)); + +extern struct sockaddr *getlocaladdr __P((struct sockaddr *)); + +extern int recvfromto __P((int, void *, size_t, int, + struct sockaddr *, int *, struct sockaddr *, int *)); +extern int sendfromto __P((int, const void *, size_t, + struct sockaddr *, struct sockaddr *, int)); + +extern int setsockopt_bypass __P((int, int)); + +extern struct sockaddr *newsaddr __P((int)); +extern struct sockaddr *dupsaddr __P((struct sockaddr *)); +extern char *saddr2str __P((const struct sockaddr *)); +extern char *saddrwop2str __P((struct sockaddr *)); +extern struct sockaddr *str2saddr __P((char *, char *)); +extern void mask_sockaddr __P((struct sockaddr *, const struct sockaddr *, + size_t)); diff --git a/racoon.tproj/str2val.c b/racoon.tproj/str2val.c new file mode 100644 index 0000000..72aee51 --- /dev/null +++ b/racoon.tproj/str2val.c @@ -0,0 +1,122 @@ +/* $KAME: str2val.c,v 1.10 2001/04/03 15:51:57 thorpej 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. 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. + */ + +#include +#include +#include + +#include +#include + +#include "str2val.h" +#include "gcmalloc.h" + +/* + * exchange a value to a hex string. + * must free buffer allocated later. + */ +caddr_t +val2str(buf, mlen) + const char *buf; + size_t mlen; +{ + caddr_t new; + size_t len = (mlen * 2) + mlen / 8 + 10; + size_t i, j; + + if ((new = racoon_malloc(len)) == 0) return(0); + + for (i = 0, j = 0; i < mlen; i++) { + snprintf(&new[j], len - j, "%02x", (u_char)buf[i]); + j += 2; + if (i % 8 == 7) { + new[j++] = ' '; + new[j] = '\0'; + } + } + new[j] = '\0'; + + return(new); +} + +/* + * exchange a string based "base" to a value. + */ +char * +str2val(str, base, len) + const char *str; + int base; + size_t *len; +{ + int f; + size_t i; + char *dst; + char *rp; + const char *p; + char b[3]; + + i = 0; + for (p = str; *p != '\0'; p++) { + if (isxdigit(*p)) + i++; + else if (isspace(*p)) + ; + else + return NULL; + } + if (i == 0 || (i % 2) != 0) + return NULL; + i /= 2; + + if ((dst = racoon_malloc(i)) == NULL) + return NULL; + + i = 0; + f = 0; + for (rp = dst, p = str; *p != '\0'; p++) { + if (isxdigit(*p)) { + if (!f) { + b[0] = *p; + f = 1; + } else { + b[1] = *p; + b[2] = '\0'; + *rp++ = (char)strtol(b, NULL, base); + i++; + f = 0; + } + } + } + + *len = i; + + return(dst); +} diff --git a/racoon.tproj/str2val.h b/racoon.tproj/str2val.h new file mode 100644 index 0000000..15f5245 --- /dev/null +++ b/racoon.tproj/str2val.h @@ -0,0 +1,33 @@ +/* $KAME: str2val.h,v 1.5 2000/10/04 17:41:04 itojun 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. 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. + */ + +extern caddr_t val2str __P((const char *, size_t)); +extern char *str2val __P((const char *, int, size_t *)); diff --git a/racoon.tproj/strnames.c b/racoon.tproj/strnames.c new file mode 100644 index 0000000..10c6094 --- /dev/null +++ b/racoon.tproj/strnames.c @@ -0,0 +1,832 @@ +/* $KAME: strnames.c,v 1.22 2001/11/16 04:12:59 sakane 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. 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. + */ + +#include +#include +#include + +#include +#include + +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" + +#include "isakmp_var.h" +#include "isakmp.h" +#include "ipsec_doi.h" +#include "oakley.h" +#include "handler.h" +#include "pfkey.h" +#include "strnames.h" +#include "algorithm.h" + +struct ksmap { + int key; + char *str; + char *(*f) __P((int)); +}; + +static char *num2str __P((int n)); + +static char * +num2str(n) + int n; +{ + static char buf[20]; + + snprintf(buf, sizeof(buf), "%d", n); + + return buf; +} + +/* isakmp.h */ +char * +s_isakmp_state(t, d, s) + int t, d, s; +{ + switch (t) { + case ISAKMP_ETYPE_AGG: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE1ST_MSG1SENT: + return "agg I msg1"; + case PHASE1ST_ESTABLISHED: + return "agg I msg2"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE1ST_MSG1SENT: + return "agg R msg1"; + default: + break; + } + } + break; + case ISAKMP_ETYPE_BASE: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE1ST_MSG1SENT: + return "base I msg1"; + case PHASE1ST_MSG2SENT: + return "base I msg2"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE1ST_MSG1SENT: + return "base R msg1"; + case PHASE1ST_ESTABLISHED: + return "base R msg2"; + default: + break; + } + } + break; + case ISAKMP_ETYPE_IDENT: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE1ST_MSG1SENT: + return "ident I msg1"; + case PHASE1ST_MSG2SENT: + return "ident I msg2"; + case PHASE1ST_MSG3SENT: + return "ident I msg3"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE1ST_MSG1SENT: + return "ident R msg1"; + case PHASE1ST_MSG2SENT: + return "ident R msg2"; + case PHASE1ST_ESTABLISHED: + return "ident R msg3"; + default: + break; + } + } + break; + case ISAKMP_ETYPE_QUICK: + switch (d) { + case INITIATOR: + switch (s) { + case PHASE2ST_MSG1SENT: + return "quick I msg1"; + case PHASE2ST_ADDSA: + return "quick I msg2"; + default: + break; + } + case RESPONDER: + switch (s) { + case PHASE2ST_MSG1SENT: + return "quick R msg1"; + case PHASE2ST_COMMIT: + return "quick R msg2"; + default: + break; + } + } + break; + default: + case ISAKMP_ETYPE_NONE: + case ISAKMP_ETYPE_AUTH: + case ISAKMP_ETYPE_INFO: + case ISAKMP_ETYPE_NEWGRP: + case ISAKMP_ETYPE_ACKINFO: + break; + } + /*NOTREACHED*/ + + return "???"; +} + +static struct ksmap name_isakmp_certtype[] = { +{ ISAKMP_CERT_NONE, "NONE", NULL }, +{ ISAKMP_CERT_PKCS7, "PKCS #7 wrapped X.509 certificate", NULL }, +{ ISAKMP_CERT_PGP, "PGP Certificate", NULL }, +{ ISAKMP_CERT_DNS, "DNS Signed Key", NULL }, +{ ISAKMP_CERT_X509SIGN, "X.509 Certificate Signature", NULL }, +{ ISAKMP_CERT_X509KE, "X.509 Certificate Key Exchange", NULL }, +{ ISAKMP_CERT_KERBEROS, "Kerberos Tokens", NULL }, +{ ISAKMP_CERT_CRL, "Certificate Revocation List (CRL)", NULL }, +{ ISAKMP_CERT_ARL, "Authority Revocation List (ARL)", NULL }, +{ ISAKMP_CERT_SPKI, "SPKI Certificate", NULL }, +{ ISAKMP_CERT_X509ATTR, "X.509 Certificate Attribute", NULL }, +}; + +char * +s_isakmp_certtype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_certtype); i++) + if (name_isakmp_certtype[i].key == k) + return name_isakmp_certtype[i].str; + return num2str(k); +} + +static struct ksmap name_isakmp_etype[] = { +{ ISAKMP_ETYPE_NONE, "None", NULL }, +{ ISAKMP_ETYPE_BASE, "Base", NULL }, +{ ISAKMP_ETYPE_IDENT, "Identity Protection", NULL }, +{ ISAKMP_ETYPE_AUTH, "Authentication Only", NULL }, +{ ISAKMP_ETYPE_AGG, "Aggressive", NULL }, +{ ISAKMP_ETYPE_INFO, "Informational", NULL }, +{ ISAKMP_ETYPE_QUICK, "Quick", NULL }, +{ ISAKMP_ETYPE_NEWGRP, "New Group", NULL }, +{ ISAKMP_ETYPE_ACKINFO, "Acknowledged Informational", NULL }, +}; + +char * +s_isakmp_etype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_etype); i++) + if (name_isakmp_etype[i].key == k) + return name_isakmp_etype[i].str; + return num2str(k); +} + +static struct ksmap name_isakmp_notify_msg[] = { +{ ISAKMP_NTYPE_INVALID_PAYLOAD_TYPE, "INVALID-PAYLOAD-TYPE", NULL }, +{ ISAKMP_NTYPE_DOI_NOT_SUPPORTED, "DOI-NOT-SUPPORTED", NULL }, +{ ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED, "SITUATION-NOT-SUPPORTED", NULL }, +{ ISAKMP_NTYPE_INVALID_COOKIE, "INVALID-COOKIE", NULL }, +{ ISAKMP_NTYPE_INVALID_MAJOR_VERSION, "INVALID-MAJOR-VERSION", NULL }, +{ ISAKMP_NTYPE_INVALID_MINOR_VERSION, "INVALID-MINOR-VERSION", NULL }, +{ ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE, "INVALID-EXCHANGE-TYPE", NULL }, +{ ISAKMP_NTYPE_INVALID_FLAGS, "INVALID-FLAGS", NULL }, +{ ISAKMP_NTYPE_INVALID_MESSAGE_ID, "INVALID-MESSAGE-ID", NULL }, +{ ISAKMP_NTYPE_INVALID_PROTOCOL_ID, "INVALID-PROTOCOL-ID", NULL }, +{ ISAKMP_NTYPE_INVALID_SPI, "INVALID-SPI", NULL }, +{ ISAKMP_NTYPE_INVALID_TRANSFORM_ID, "INVALID-TRANSFORM-ID", NULL }, +{ ISAKMP_NTYPE_ATTRIBUTES_NOT_SUPPORTED, "ATTRIBUTES-NOT-SUPPORTED", NULL }, +{ ISAKMP_NTYPE_NO_PROPOSAL_CHOSEN, "NO-PROPOSAL-CHOSEN", NULL }, +{ ISAKMP_NTYPE_BAD_PROPOSAL_SYNTAX, "BAD-PROPOSAL-SYNTAX", NULL }, +{ ISAKMP_NTYPE_PAYLOAD_MALFORMED, "PAYLOAD-MALFORMED", NULL }, +{ ISAKMP_NTYPE_INVALID_KEY_INFORMATION, "INVALID-KEY-INFORMATION", NULL }, +{ ISAKMP_NTYPE_INVALID_ID_INFORMATION, "INVALID-ID-INFORMATION", NULL }, +{ ISAKMP_NTYPE_INVALID_CERT_ENCODING, "INVALID-CERT-ENCODING", NULL }, +{ ISAKMP_NTYPE_INVALID_CERTIFICATE, "INVALID-CERTIFICATE", NULL }, +{ ISAKMP_NTYPE_BAD_CERT_REQUEST_SYNTAX, "BAD-CERT-REQUEST-SYNTAX", NULL }, +{ ISAKMP_NTYPE_INVALID_CERT_AUTHORITY, "INVALID-CERT-AUTHORITY", NULL }, +{ ISAKMP_NTYPE_INVALID_HASH_INFORMATION, "INVALID-HASH-INFORMATION", NULL }, +{ ISAKMP_NTYPE_AUTHENTICATION_FAILED, "AUTHENTICATION-FAILED", NULL }, +{ ISAKMP_NTYPE_INVALID_SIGNATURE, "INVALID-SIGNATURE", NULL }, +{ ISAKMP_NTYPE_ADDRESS_NOTIFICATION, "ADDRESS-NOTIFICATION", NULL }, +{ ISAKMP_NTYPE_NOTIFY_SA_LIFETIME, "NOTIFY-SA-LIFETIME", NULL }, +{ ISAKMP_NTYPE_CERTIFICATE_UNAVAILABLE, "CERTIFICATE-UNAVAILABLE", NULL }, +{ ISAKMP_NTYPE_UNSUPPORTED_EXCHANGE_TYPE, "UNSUPPORTED-EXCHANGE-TYPE", NULL }, +{ ISAKMP_NTYPE_UNEQUAL_PAYLOAD_LENGTHS, "UNEQUAL-PAYLOAD-LENGTHS", NULL }, +{ ISAKMP_NTYPE_CONNECTED, "CONNECTED", NULL }, +{ ISAKMP_NTYPE_RESPONDER_LIFETIME, "RESPONDER-LIFETIME", NULL }, +{ ISAKMP_NTYPE_REPLAY_STATUS, "REPLAY-STATUS", NULL }, +{ ISAKMP_NTYPE_INITIAL_CONTACT, "INITIAL-CONTACT", NULL }, +{ ISAKMP_LOG_RETRY_LIMIT_REACHED, "RETRY-LIMIT-REACHED", NULL }, +}; + +char * +s_isakmp_notify_msg(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_notify_msg); i++) + if (name_isakmp_notify_msg[i].key == k) + return name_isakmp_notify_msg[i].str; + + return num2str(k); +} + +static struct ksmap name_isakmp_nptype[] = { +{ ISAKMP_NPTYPE_NONE, "none", NULL }, +{ ISAKMP_NPTYPE_SA, "sa", NULL }, +{ ISAKMP_NPTYPE_P, "prop", NULL }, +{ ISAKMP_NPTYPE_T, "trns", NULL }, +{ ISAKMP_NPTYPE_KE, "ke", NULL }, +{ ISAKMP_NPTYPE_ID, "id", NULL }, +{ ISAKMP_NPTYPE_CERT, "cert", NULL }, +{ ISAKMP_NPTYPE_CR, "cr", NULL }, +{ ISAKMP_NPTYPE_HASH, "hash", NULL }, +{ ISAKMP_NPTYPE_SIG, "sig", NULL }, +{ ISAKMP_NPTYPE_NONCE, "nonce", NULL }, +{ ISAKMP_NPTYPE_N, "notify", NULL }, +{ ISAKMP_NPTYPE_D, "delete", NULL }, +{ ISAKMP_NPTYPE_VID, "vid", NULL }, +{ ISAKMP_NPTYPE_GSS, "gss id", NULL }, +}; + +char * +s_isakmp_nptype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_isakmp_nptype); i++) + if (name_isakmp_nptype[i].key == k) + return name_isakmp_nptype[i].str; + return num2str(k); +} + +/* ipsec_doi.h */ +static struct ksmap name_ipsecdoi_proto[] = { +{ IPSECDOI_PROTO_ISAKMP, "ISAKMP", s_ipsecdoi_trns_isakmp }, +{ IPSECDOI_PROTO_IPSEC_AH, "AH", s_ipsecdoi_trns_ah }, +{ IPSECDOI_PROTO_IPSEC_ESP, "ESP", s_ipsecdoi_trns_esp }, +{ IPSECDOI_PROTO_IPCOMP, "IPCOMP", s_ipsecdoi_trns_ipcomp }, +}; + +char * +s_ipsecdoi_proto(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_proto); i++) + if (name_ipsecdoi_proto[i].key == k) + return name_ipsecdoi_proto[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_isakmp[] = { +{ IPSECDOI_KEY_IKE, "IKE", NULL }, +}; + +char * +s_ipsecdoi_trns_isakmp(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_isakmp); i++) + if (name_ipsecdoi_trns_isakmp[i].key == k) + return name_ipsecdoi_trns_isakmp[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_ah[] = { +{ IPSECDOI_AH_MD5, "MD5", NULL }, +{ IPSECDOI_AH_SHA, "SHA", NULL }, +{ IPSECDOI_AH_DES, "DES", NULL }, +}; + +char * +s_ipsecdoi_trns_ah(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_ah); i++) + if (name_ipsecdoi_trns_ah[i].key == k) + return name_ipsecdoi_trns_ah[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_esp[] = { +{ IPSECDOI_ESP_DES_IV64, "DES_IV64", NULL }, +{ IPSECDOI_ESP_DES, "DES", NULL }, +{ IPSECDOI_ESP_3DES, "3DES", NULL }, +{ IPSECDOI_ESP_RC5, "RC5", NULL }, +{ IPSECDOI_ESP_IDEA, "IDEA", NULL }, +{ IPSECDOI_ESP_CAST, "CAST", NULL }, +{ IPSECDOI_ESP_BLOWFISH, "BLOWFISH", NULL }, +{ IPSECDOI_ESP_3IDEA, "3IDEA", NULL }, +{ IPSECDOI_ESP_DES_IV32, "DES_IV32", NULL }, +{ IPSECDOI_ESP_RC4, "RC4", NULL }, +{ IPSECDOI_ESP_NULL, "NULL", NULL }, +{ IPSECDOI_ESP_RIJNDAEL, "RIJNDAEL", NULL }, +{ IPSECDOI_ESP_TWOFISH, "TWOFISH", NULL }, +}; + +char * +s_ipsecdoi_trns_esp(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_esp); i++) + if (name_ipsecdoi_trns_esp[i].key == k) + return name_ipsecdoi_trns_esp[i].str; + return num2str(k); +} + +static struct ksmap name_ipsecdoi_trns_ipcomp[] = { +{ IPSECDOI_IPCOMP_OUI, "OUI", NULL}, +{ IPSECDOI_IPCOMP_DEFLATE, "DEFLATE", NULL}, +{ IPSECDOI_IPCOMP_LZS, "LZS", NULL}, +}; + +char * +s_ipsecdoi_trns_ipcomp(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_trns_ipcomp); i++) + if (name_ipsecdoi_trns_ipcomp[i].key == k) + return name_ipsecdoi_trns_ipcomp[i].str; + return num2str(k); +} + +char * +s_ipsecdoi_trns(proto, trns) + int proto, trns; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_proto); i++) + if (name_ipsecdoi_proto[i].key == proto + && name_ipsecdoi_proto[i].f) + return (name_ipsecdoi_proto[i].f)(trns); + return num2str(trns); +} + +static struct ksmap name_attr_ipsec[] = { +{ IPSECDOI_ATTR_SA_LD_TYPE, "SA Life Type", s_ipsecdoi_ltype }, +{ IPSECDOI_ATTR_SA_LD, "SA Life Duration", NULL }, +{ IPSECDOI_ATTR_GRP_DESC, "Group Description", NULL }, +{ IPSECDOI_ATTR_ENC_MODE, "Encription Mode", s_ipsecdoi_encmode }, +{ IPSECDOI_ATTR_AUTH, "Authentication Algorithm", s_ipsecdoi_auth }, +{ IPSECDOI_ATTR_KEY_LENGTH, "Key Length", NULL }, +{ IPSECDOI_ATTR_KEY_ROUNDS, "Key Rounds", NULL }, +{ IPSECDOI_ATTR_COMP_DICT_SIZE, "Compression Dictionary Size", NULL }, +{ IPSECDOI_ATTR_COMP_PRIVALG, "Compression Private Algorithm", NULL }, +}; + +char * +s_ipsecdoi_attr(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec); i++) + if (name_attr_ipsec[i].key == k) + return name_attr_ipsec[i].str; + return num2str(k); +} + +static struct ksmap name_attr_ipsec_ltype[] = { +{ IPSECDOI_ATTR_SA_LD_TYPE_SEC, "seconds", NULL }, +{ IPSECDOI_ATTR_SA_LD_TYPE_KB, "kilobytes", NULL }, +}; + +char * +s_ipsecdoi_ltype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec_ltype); i++) + if (name_attr_ipsec_ltype[i].key == k) + return name_attr_ipsec_ltype[i].str; + return num2str(k); +} + +static struct ksmap name_attr_ipsec_encmode[] = { +{ IPSECDOI_ATTR_ENC_MODE_ANY, "Any", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_TUNNEL, "Tunnel", NULL }, +{ IPSECDOI_ATTR_ENC_MODE_TRNS, "Transport", NULL }, +}; + +char * +s_ipsecdoi_encmode(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec_encmode); i++) + if (name_attr_ipsec_encmode[i].key == k) + return name_attr_ipsec_encmode[i].str; + return num2str(k); +} + +static struct ksmap name_attr_ipsec_auth[] = { +{ IPSECDOI_ATTR_AUTH_HMAC_MD5, "hmac-md5", NULL }, +{ IPSECDOI_ATTR_AUTH_HMAC_SHA1, "hmac-sha", NULL }, +{ IPSECDOI_ATTR_AUTH_DES_MAC, "des-mac", NULL }, +{ IPSECDOI_ATTR_AUTH_KPDK, "kpdk", NULL }, +}; + +char * +s_ipsecdoi_auth(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_ipsec_auth); i++) + if (name_attr_ipsec_auth[i].key == k) + return name_attr_ipsec_auth[i].str; + return num2str(k); +} + +char * +s_ipsecdoi_attr_v(type, val) + int type, val; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_proto); i++) + if (name_attr_ipsec[i].key == type + && name_attr_ipsec[i].f) + return (name_attr_ipsec[i].f)(val); + return num2str(val); +} + +static struct ksmap name_ipsecdoi_ident[] = { +{ IPSECDOI_ID_IPV4_ADDR, "IPv4_address", NULL }, +{ IPSECDOI_ID_FQDN, "FQDN", NULL }, +{ IPSECDOI_ID_USER_FQDN, "User_FQDN", NULL }, +{ IPSECDOI_ID_IPV4_ADDR_SUBNET, "IPv4_subnet", NULL }, +{ IPSECDOI_ID_IPV6_ADDR, "IPv6_address", NULL }, +{ IPSECDOI_ID_IPV6_ADDR_SUBNET, "IPv6_subnet", NULL }, +{ IPSECDOI_ID_IPV4_ADDR_RANGE, "IPv4_address_range", NULL }, +{ IPSECDOI_ID_IPV6_ADDR_RANGE, "IPv6_address_range", NULL }, +{ IPSECDOI_ID_DER_ASN1_DN, "DER_ASN1_DN", NULL }, +{ IPSECDOI_ID_DER_ASN1_GN, "DER_ASN1_GN", NULL }, +{ IPSECDOI_ID_KEY_ID, "KEY_ID", NULL }, +}; + +char * +s_ipsecdoi_ident(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsecdoi_ident); i++) + if (name_ipsecdoi_ident[i].key == k) + return name_ipsecdoi_ident[i].str; + return num2str(k); +} + +/* oakley.h */ +static struct ksmap name_oakley_attr[] = { +{ OAKLEY_ATTR_ENC_ALG, "Encryption Algorithm", s_attr_isakmp_enc }, +{ OAKLEY_ATTR_HASH_ALG, "Hash Algorithm", s_attr_isakmp_hash }, +{ OAKLEY_ATTR_AUTH_METHOD, "Authentication Method", s_oakley_attr_method }, +{ OAKLEY_ATTR_GRP_DESC, "Group Description", s_attr_isakmp_desc }, +{ OAKLEY_ATTR_GRP_TYPE, "Group Type", s_attr_isakmp_group }, +{ OAKLEY_ATTR_GRP_PI, "Group Prime/Irreducible Polynomial", NULL }, +{ OAKLEY_ATTR_GRP_GEN_ONE, "Group Generator One", NULL }, +{ OAKLEY_ATTR_GRP_GEN_TWO, "Group Generator Two", NULL }, +{ OAKLEY_ATTR_GRP_CURVE_A, "Group Curve A", NULL }, +{ OAKLEY_ATTR_GRP_CURVE_B, "Group Curve B", NULL }, +{ OAKLEY_ATTR_SA_LD_TYPE, "Life Type", s_attr_isakmp_ltype }, +{ OAKLEY_ATTR_SA_LD, "Life Duration", NULL }, +{ OAKLEY_ATTR_PRF, "PRF", NULL }, +{ OAKLEY_ATTR_KEY_LEN, "Key Length", NULL }, +{ OAKLEY_ATTR_FIELD_SIZE, "Field Size", NULL }, +{ OAKLEY_ATTR_GRP_ORDER, "Group Order", NULL }, +{ OAKLEY_ATTR_BLOCK_SIZE, "Block Size", NULL }, +{ OAKLEY_ATTR_GSS_ID, "GSS-API endpoint name",NULL }, +}; + +char * +s_oakley_attr(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_oakley_attr); i++) + if (name_oakley_attr[i].key == k) + return name_oakley_attr[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_enc[] = { +{ OAKLEY_ATTR_ENC_ALG_DES, "DES-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_IDEA, "IDEA-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_BLOWFISH, "Blowfish-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_RC5, "RC5-R16-B64-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_3DES, "3DES-CBC", NULL }, +{ OAKLEY_ATTR_ENC_ALG_CAST, "CAST-CBC", NULL }, +}; + +char * +s_attr_isakmp_enc(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_enc); i++) + if (name_attr_isakmp_enc[i].key == k) + return name_attr_isakmp_enc[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_hash[] = { +{ OAKLEY_ATTR_HASH_ALG_MD5, "MD5", NULL }, +{ OAKLEY_ATTR_HASH_ALG_SHA, "SHA", NULL }, +{ OAKLEY_ATTR_HASH_ALG_TIGER, "Tiger", NULL }, +}; + +char * +s_attr_isakmp_hash(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_hash); i++) + if (name_attr_isakmp_hash[i].key == k) + return name_attr_isakmp_hash[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_method[] = { +{ OAKLEY_ATTR_AUTH_METHOD_PSKEY, "pre-shared key", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_DSSSIG, "DSS signatures", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_RSASIG, "RSA signatures", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_RSAENC, "Encryption with RSA", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_RSAREV, "Revised encryption with RSA", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_EGENC, "Encryption with El-Gamal", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_EGREV, "Revised encryption with El-Gamal", NULL }, +{ OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB, "GSS-API on Kerberos 5", NULL }, +}; + +char * +s_oakley_attr_method(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_method); i++) + if (name_attr_isakmp_method[i].key == k) + return name_attr_isakmp_method[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_desc[] = { +{ OAKLEY_ATTR_GRP_DESC_MODP768, "768-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP1024, "1024-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_EC2N155, "EC2N group on GP[2^155]", NULL }, +{ OAKLEY_ATTR_GRP_DESC_EC2N185, "EC2N group on GP[2^185]", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP1536, "1536-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP2048, "2048-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP3072, "3072-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP4096, "4096-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP6144, "6144-bit MODP group", NULL }, +{ OAKLEY_ATTR_GRP_DESC_MODP8192, "8192-bit MODP group", NULL }, +}; + +char * +s_attr_isakmp_desc(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_desc); i++) + if (name_attr_isakmp_desc[i].key == k) + return name_attr_isakmp_desc[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_group[] = { +{ OAKLEY_ATTR_GRP_TYPE_MODP, "MODP", NULL }, +{ OAKLEY_ATTR_GRP_TYPE_ECP, "ECP", NULL }, +{ OAKLEY_ATTR_GRP_TYPE_EC2N, "EC2N", NULL }, +}; + +char * +s_attr_isakmp_group(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_group); i++) + if (name_attr_isakmp_group[i].key == k) + return name_attr_isakmp_group[i].str; + return num2str(k); +} + +static struct ksmap name_attr_isakmp_ltype[] = { +{ OAKLEY_ATTR_SA_LD_TYPE_SEC, "seconds", NULL }, +{ OAKLEY_ATTR_SA_LD_TYPE_KB, "kilobytes", NULL }, +}; + +char * +s_attr_isakmp_ltype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_attr_isakmp_ltype); i++) + if (name_attr_isakmp_ltype[i].key == k) + return name_attr_isakmp_ltype[i].str; + return num2str(k); +} + +char * +s_oakley_attr_v(type, val) + int type, val; +{ + int i; + for (i = 0; i < ARRAYLEN(name_oakley_attr); i++) + if (name_oakley_attr[i].key == type + && name_oakley_attr[i].f) + return (name_oakley_attr[i].f)(val); + return num2str(val); +} + +/* netinet6/ipsec.h */ +static struct ksmap name_ipsec_level[] = { +{ IPSEC_LEVEL_USE, "use", NULL }, +{ IPSEC_LEVEL_REQUIRE, "require", NULL }, +{ IPSEC_LEVEL_UNIQUE, "unique", NULL }, +}; + +char * +s_ipsec_level(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_ipsec_level); i++) + if (name_ipsec_level[i].key == k) + return name_ipsec_level[i].str; + return num2str(k); +} + +static struct ksmap name_algclass[] = { +{ algclass_ipsec_enc, "ipsec enc", s_ipsecdoi_trns_esp }, +{ algclass_ipsec_auth, "ipsec auth", s_ipsecdoi_trns_ah }, +{ algclass_ipsec_comp, "ipsec comp", s_ipsecdoi_trns_ipcomp }, +{ algclass_isakmp_enc, "isakmp enc", s_attr_isakmp_enc }, +{ algclass_isakmp_hash, "isakmp hash", s_attr_isakmp_hash }, +{ algclass_isakmp_dh, "isakmp dh", s_attr_isakmp_desc }, +{ algclass_isakmp_ameth, "isakmp auth method", s_oakley_attr_method }, +}; + +char * +s_algclass(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_algclass); i++) + if (name_algclass[i].key == k) + return name_algclass[i].str; + return num2str(k); +} + +char * +s_algtype(class, n) + int class, n; +{ + int i; + for (i = 0; i < ARRAYLEN(name_algclass); i++) + if (name_algclass[i].key == class + && name_algclass[i].f) + return (name_algclass[i].f)(n); + return num2str(n); +} + +/* pfkey.h */ +static struct ksmap name_pfkey_type[] = { +{ SADB_GETSPI, "GETSPI", NULL }, +{ SADB_UPDATE, "UPDATE", NULL }, +{ SADB_ADD, "ADD", NULL }, +{ SADB_DELETE, "DELETE", NULL }, +{ SADB_GET, "GET", NULL }, +{ SADB_ACQUIRE, "ACQUIRE", NULL }, +{ SADB_REGISTER, "REGISTER", NULL }, +{ SADB_EXPIRE, "EXPIRE", NULL }, +{ SADB_FLUSH, "FLUSH", NULL }, +{ SADB_DUMP, "DUMP", NULL }, +{ SADB_X_PROMISC, "X_PRIMISC", NULL }, +{ SADB_X_PCHANGE, "X_PCHANGE", NULL }, +{ SADB_X_SPDUPDATE, "X_SPDUPDATE", NULL }, +{ SADB_X_SPDADD, "X_SPDADD", NULL }, +{ SADB_X_SPDDELETE, "X_SPDDELETE", NULL }, +{ SADB_X_SPDGET, "X_SPDGET", NULL }, +{ SADB_X_SPDACQUIRE, "X_SPDACQUIRE", NULL }, +{ SADB_X_SPDDUMP, "X_SPDDUMP", NULL }, +{ SADB_X_SPDFLUSH, "X_SPDFLUSH", NULL }, +{ SADB_X_SPDSETIDX, "X_SPDSETIDX", NULL }, +{ SADB_X_SPDEXPIRE, "X_SPDEXPIRE", NULL }, +{ SADB_X_SPDDELETE2, "X_SPDDELETE2", NULL }, +}; + +char * +s_pfkey_type(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_pfkey_type); i++) + if (name_pfkey_type[i].key == k) + return name_pfkey_type[i].str; + return num2str(k); +} + +static struct ksmap name_pfkey_satype[] = { +{ SADB_SATYPE_UNSPEC, "UNSPEC", NULL }, +{ SADB_SATYPE_AH, "AH", NULL }, +{ SADB_SATYPE_ESP, "ESP", NULL }, +{ SADB_SATYPE_RSVP, "RSVP", NULL }, +{ SADB_SATYPE_OSPFV2, "OSPFV2", NULL }, +{ SADB_SATYPE_RIPV2, "RIPV2", NULL }, +{ SADB_SATYPE_MIP, "MIP", NULL }, +{ SADB_X_SATYPE_IPCOMP, "IPCOMP", NULL }, +}; + +char * +s_pfkey_satype(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_pfkey_satype); i++) + if (name_pfkey_satype[i].key == k) + return name_pfkey_satype[i].str; + return num2str(k); +} + +static struct ksmap name_direction[] = { +{ IPSEC_DIR_INBOUND, "in", NULL }, +{ IPSEC_DIR_OUTBOUND, "out", NULL }, +}; + +char * +s_direction(k) + int k; +{ + int i; + for (i = 0; i < ARRAYLEN(name_direction); i++) + if (name_direction[i].key == k) + return name_direction[i].str; + return num2str(k); +} + +char * +s_proto(k) + int k; +{ + switch (k) { + case IPPROTO_ICMP: + return "icmp"; + case IPPROTO_TCP: + return "tcp"; + case IPPROTO_UDP: + return "udp"; + case IPPROTO_ICMPV6: + return "icmpv6"; + case IPSEC_ULPROTO_ANY: + return "any"; + } + + return num2str(k); +} diff --git a/racoon.tproj/strnames.h b/racoon.tproj/strnames.h new file mode 100644 index 0000000..e84666f --- /dev/null +++ b/racoon.tproj/strnames.h @@ -0,0 +1,63 @@ +/* $KAME: strnames.h,v 1.11 2001/07/14 14:06:40 sakane 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. 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. + */ + +extern char * s_isakmp_state __P((int, int, int)); +extern char *s_isakmp_certtype __P((int)); +extern char *s_isakmp_etype __P((int)); +extern char *s_isakmp_notify_msg __P((int)); +extern char *s_isakmp_nptype __P((int)); +extern char *s_ipsecdoi_proto __P((int)); +extern char *s_ipsecdoi_trns_isakmp __P((int)); +extern char *s_ipsecdoi_trns_ah __P((int)); +extern char *s_ipsecdoi_trns_esp __P((int)); +extern char *s_ipsecdoi_trns_ipcomp __P((int)); +extern char *s_ipsecdoi_trns __P((int, int)); +extern char *s_ipsecdoi_attr __P((int)); +extern char *s_ipsecdoi_ltype __P((int)); +extern char *s_ipsecdoi_encmode __P((int)); +extern char *s_ipsecdoi_auth __P((int)); +extern char *s_ipsecdoi_attr_v __P((int, int)); +extern char *s_ipsecdoi_ident __P((int)); +extern char *s_oakley_attr __P((int)); +extern char *s_attr_isakmp_enc __P((int)); +extern char *s_attr_isakmp_hash __P((int)); +extern char *s_oakley_attr_method __P((int)); +extern char *s_attr_isakmp_desc __P((int)); +extern char *s_attr_isakmp_group __P((int)); +extern char *s_attr_isakmp_ltype __P((int)); +extern char *s_oakley_attr_v __P((int, int)); +extern char *s_ipsec_level __P((int)); +extern char *s_algclass __P((int)); +extern char *s_algtype __P((int, int)); +extern char *s_pfkey_type __P((int)); +extern char *s_pfkey_satype __P((int)); +extern char *s_direction __P((int)); +extern char *s_proto __P((int)); diff --git a/racoon.tproj/var.h b/racoon.tproj/var.h new file mode 100644 index 0000000..a4b4ff2 --- /dev/null +++ b/racoon.tproj/var.h @@ -0,0 +1,93 @@ +/* $KAME: var.h,v 1.11 2001/07/14 05:48:33 sakane 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. 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. + */ + +#if !defined(_VAR_H_) +#define _VAR_H_ + +#define MAX3(a, b, c) (a > b ? (a > c ? a : c) : (b > c ? b : c)) + +#define ISSET(exp, bit) (((exp) & (bit)) == (bit)) + +#define ATOX(c) \ + (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) + +#define LALIGN(a) \ + ((a) > 0 ? ((a) &~ (sizeof(long) - 1)) : sizeof(long)) + +#define RNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +#define ARRAYLEN(a) (sizeof(a)/sizeof(a[0])) + +#define BUFSIZE 5120 + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#ifdef ENABLE_STATS +#include +#endif +#include + +/* + * XXX use of GETNAMEINFO(x, y, NULL) is not politically correct, + * as sizeof(NULL) would be 4, not 0. + */ +#include +#include + +/* var.h is used from non-racoon code (like eaytest), so we can't use niflags */ +#define NIFLAGS (NI_NUMERICHOST | NI_NUMERICSERV) + +#define GETNAMEINFO(x, y, z) \ +do { \ + if (getnameinfo((x), (x)->sa_len, (y), sizeof(y), (z), sizeof(z), \ + NIFLAGS) != 0) { \ + if (y) \ + strncpy((y), "(invalid)", sizeof(y)); \ + if (z) \ + strncpy((z), "(invalid)", sizeof(z)); \ + } \ +} while (0); + +#include +#ifndef LIST_FOREACH +#define LIST_FOREACH(elm, head, field) \ + for (elm = LIST_FIRST(head); elm; elm = LIST_NEXT(elm, field)) +#endif + +#include "gcmalloc.h" + +#endif /*!defined(_VAR_H_)*/ diff --git a/racoon.tproj/vendorid.c b/racoon.tproj/vendorid.c new file mode 100644 index 0000000..088226b --- /dev/null +++ b/racoon.tproj/vendorid.c @@ -0,0 +1,139 @@ +/* $KAME: vendorid.c,v 1.7 2000/12/15 13:43:57 sakane 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. 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. + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "localconf.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "vendorid.h" +#include "crypto_openssl.h" + +const char *vendorid_strings[] = VENDORID_STRINGS; + +/* + * set hashed vendor id. + * hash function is always MD5. + */ +vchar_t * +set_vendorid(int vendorid) +{ + vchar_t vid, *vidhash; + + if (vendorid == VENDORID_UNKNOWN) { + /* + * The default unknown ID gets translated to + * KAME/racoon. + */ + vendorid = VENDORID_KAME; + } + + if (vendorid < 0 || vendorid >= NUMVENDORIDS) { + plog(LLV_ERROR, LOCATION, NULL, + "invalid vendor ID index: %d\n", vendorid); + return (NULL); + } + + /* XXX Cast away const. */ + vid.v = (char *) vendorid_strings[vendorid]; + vid.l = strlen(vendorid_strings[vendorid]); + + vidhash = eay_md5_one(&vid); + if (vidhash == NULL) + plog(LLV_ERROR, LOCATION, NULL, + "unable to hash vendor ID string\n"); + + return vidhash; +} + +/* + * Check the vendor ID payload -- return the vendor ID index + * if we find a recognized one, or UNKNOWN if we don't. + */ +int +check_vendorid(gen) + struct isakmp_gen *gen; /* points to Vendor ID payload */ +{ + vchar_t vid, *vidhash; + int i, vidlen; + + if (gen == NULL) + return (VENDORID_UNKNOWN); + + vidlen = ntohs(gen->len) - sizeof(*gen); + + for (i = 0; i < NUMVENDORIDS; i++) { + /* XXX Cast away const. */ + vid.v = (char *) vendorid_strings[i]; + vid.l = strlen(vendorid_strings[i]); + + vidhash = eay_md5_one(&vid); + if (vidhash == NULL) { + plog(LLV_ERROR, LOCATION, NULL, + "unable to hash vendor ID string\n"); + return (VENDORID_UNKNOWN); + } + + /* + * XXX THIS IS NOT QUITE RIGHT! + * + * But we need to be able to recognize + * Windows 2000's ID, which is the MD5 + * has of a known string + 4 bytes of + * what appears to be version info. + */ + if (vidhash->l <= vidlen && + memcmp(vidhash->v, gen + 1, vidhash->l) == 0) { + plog(LLV_INFO, LOCATION, NULL, + "received Vendor ID: %s\n", + vendorid_strings[i]); + vfree(vidhash); + return (i); + } + vfree(vidhash); + } + + plog(LLV_DEBUG, LOCATION, NULL, "received unknown Vendor ID\n"); + return (VENDORID_UNKNOWN); +} diff --git a/racoon.tproj/vendorid.h b/racoon.tproj/vendorid.h new file mode 100644 index 0000000..84ed725 --- /dev/null +++ b/racoon.tproj/vendorid.h @@ -0,0 +1,62 @@ +/* $KAME: vendorid.h,v 1.5 2000/10/04 17:41:04 itojun 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. 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. + */ + +/* The unknown vendor ID. */ +#define VENDORID_UNKNOWN -1 + +/* Our default vendor ID. */ +#define VENDORID_KAME 0 + +/* + * Refer to draft-ietf-ipsec-isakmp-gss-auth-06.txt. + */ +#define VENDORID_GSSAPI_LONG 1 +#define VENDORID_GSSAPI 2 +#define VENDORID_MS_NT5 3 +#define VENDOR_SUPPORTS_GSSAPI(x) \ + ((x) == VENDORID_GSSAPI_LONG || \ + (x) == VENDORID_GSSAPI || \ + (x) == VENDORID_MS_NT5) + +#define NUMVENDORIDS 4 + +#define VENDORID_STRINGS \ +{ \ + "KAME/racoon", \ + "A GSS-API Authentication Method for IKE", \ + "GSSAPI", \ + "MS NT5 ISAKMPOAKLEY", \ +} + +extern const char *vendorid_strings[]; + +vchar_t *set_vendorid __P((int)); +int check_vendorid __P((struct isakmp_gen *)); diff --git a/racoon.tproj/vmbuf.c b/racoon.tproj/vmbuf.c new file mode 100644 index 0000000..cdb4110 --- /dev/null +++ b/racoon.tproj/vmbuf.c @@ -0,0 +1,115 @@ +/* $KAME: vmbuf.c,v 1.10 2001/04/03 15:51:57 thorpej 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. 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. + */ + +#define NONEED_DRM +#include +#include + +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "debug.h" +#include "gcmalloc.h" + +vchar_t * +vmalloc(size) + size_t size; +{ + vchar_t *var; + + if ((var = (vchar_t *)racoon_malloc(sizeof(*var))) == NULL) + return NULL; + + var->l = size; + var->v = (caddr_t)racoon_calloc(1, size); + if (var->v == NULL) { + (void)racoon_free(var); + return NULL; + } + + return var; +} + +vchar_t * +vrealloc(ptr, size) + vchar_t *ptr; + size_t size; +{ + caddr_t v; + + if (ptr != NULL) { + if ((v = (caddr_t)racoon_realloc(ptr->v, size)) == NULL) { + (void)vfree(ptr); + return NULL; + } + memset(v + ptr->l, 0, size - ptr->l); + ptr->v = v; + ptr->l = size; + } else { + if ((ptr = vmalloc(size)) == NULL) + return NULL; + } + + return ptr; +} + +void +vfree(var) + vchar_t *var; +{ + if (var == NULL) + return; + + if (var->v) + (void)racoon_free(var->v); + + (void)racoon_free(var); + + return; +} + +vchar_t * +vdup(src) + vchar_t *src; +{ + vchar_t *new; + + if ((new = vmalloc(src->l)) == NULL) + return NULL; + + memcpy(new->v, src->v, src->l); + + return new; +} diff --git a/racoon.tproj/vmbuf.h b/racoon.tproj/vmbuf.h new file mode 100644 index 0000000..0a2a1b9 --- /dev/null +++ b/racoon.tproj/vmbuf.h @@ -0,0 +1,63 @@ +/* $KAME: vmbuf.h,v 1.7 2000/10/04 17:41:05 itojun 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. 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. + */ + +/* + * bp v + * v v + * ........................ + * <--------------> l + * <----------------------> bl + */ +typedef struct _vchar_t_ { +#if notyet + u_int32_t t; /* type of the value */ + vchar_t *n; /* next vchar_t buffer */ + size_t bl; /* length of the buffer */ + caddr_t bp; /* pointer to the buffer */ +#endif + size_t l; /* length of the value */ + caddr_t v; /* place holder to the pointer to the value */ +} vchar_t; + +#define VPTRINIT(p) \ +do { \ + if (p) { \ + vfree(p); \ + (p) = NULL; \ + } \ +} while(0); + +#define vfree vmbuf_free + +extern vchar_t *vmalloc __P((size_t)); +extern vchar_t *vrealloc __P((vchar_t *, size_t)); +extern void vfree __P((vchar_t *)); +extern vchar_t *vdup __P((vchar_t *)); diff --git a/uucpd.tproj/Makefile b/racoonctl.tproj/Makefile similarity index 71% rename from uucpd.tproj/Makefile rename to racoonctl.tproj/Makefile index 4c25374..603d7f1 100644 --- a/uucpd.tproj/Makefile +++ b/racoonctl.tproj/Makefile @@ -1,5 +1,5 @@ # -# Generated by the NeXT Project Builder. +# Generated by the Apple Project Builder. # # NOTE: Do NOT change this file -- Project Builder maintains it. # @@ -7,14 +7,15 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = uucpd +NAME = racoonctl PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -HFILES = pathnames.h +HFILES = misc.h str2val.h vmbuf.h -CFILES = uucpd.c +CFILES = key_debug.c kmpstat.c misc.c pfkey.c pfkey_dump.c str2val.c\ + vmbuf.c OTHERSRCS = Makefile.preamble Makefile Makefile.postamble @@ -22,10 +23,10 @@ OTHERSRCS = Makefile.preamble Makefile Makefile.postamble MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC MAKEFILE = tool.make -NEXTSTEP_INSTALLDIR = /usr/libexec -WINDOWS_INSTALLDIR = /usr/libexec -PDO_UNIX_INSTALLDIR = /usr/libexec -LIBS = +NEXTSTEP_INSTALLDIR = /usr/sbin +WINDOWS_INSTALLDIR = /Library/Executables +PDO_UNIX_INSTALLDIR = /bin +LIBS = -lipsec DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) @@ -37,7 +38,7 @@ WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc NEXTSTEP_JAVA_COMPILER = /usr/bin/javac WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe -PDO_UNIX_JAVA_COMPILER = $(NEXTDEV_BIN)/javac +PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac include $(MAKEFILEDIR)/platform.make diff --git a/racoonctl.tproj/Makefile.postamble b/racoonctl.tproj/Makefile.postamble new file mode 100644 index 0000000..411cde6 --- /dev/null +++ b/racoonctl.tproj/Makefile.postamble @@ -0,0 +1,100 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGES: langages in which the project is written (default "English") +# English_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# diff --git a/racoonctl.tproj/Makefile.preamble b/racoonctl.tproj/Makefile.preamble new file mode 100644 index 0000000..68b3736 --- /dev/null +++ b/racoonctl.tproj/Makefile.preamble @@ -0,0 +1,146 @@ +############################################################################### +# Makefile.preamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile for configuring the standard application makefiles +# associated with ProjectBuilder. It is included before the main makefile. +# In Makefile.preamble you set attributes for a project, so they are available +# to the project's makefiles. In contrast, you typically write additional rules or +# override built-in behavior in the Makefile.postamble. +# +# Each directory in a project tree (main project plus subprojects) should +# have its own Makefile.preamble and Makefile.postamble. +############################################################################### +# +# Before the main makefile is included for this project, you may set: +# +# MAKEFILEDIR: Directory in which to find $(MAKEFILE) +# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make) + +# Compiler/linker flags added to the defaults: The OTHER_* variables will be +# inherited by all nested sub-projects, but the LOCAL_ versions of the same +# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's +# Build Attributes inspector if at all possible. To override the default flags +# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The +# variables below are *inputs* to the build process and distinct from the override +# settings done (less often) in the Makefile.postamble. +# +# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler +# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m, +# .cc, .cxx, .C, and .M files. There is no need to respecify the +# flags in OTHER_MFLAGS, etc. +# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files +# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files +# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files +# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when +# precompiling header files +# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool +# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap +# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen +# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc +# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex +OTHER_CFLAGS=-DHAVE_FUNCTION_MACRO=1 -DENABLE_IPV6=1 -DADVAPI=1 -DHAVE_GETADDRINFO=1 \ +-DHAVE_GETNAMEINFO=1 -DHAVE_LIBSSL=1 -DHAVE_LIBCRYPTO=1 -DHAVE_LIBL=1 -DHAVE_LIBY=1 \ +-DSTDC_HEADERS=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_UNISTD_H=1 \ +-DHAVE_STDARG_H=1 -DHAVE_VARARGS_H=1 -DHAVE_OPENSSL_RSA_H=1 -DHAVE_OPENSSL_PEM_H=1 \ +-DHAVE_OPENSSL_EVP_H=1 -DHAVE_OPENSSL_X509_H=1 -DHAVE_SIGNING_C=1 -DHAVE_OPENSSL_OPENSSLV_H=1 \ +-DTIME_WITH_SYS_TIME=1 -DRETSIGTYPE=void -DHAVE_VPRINTF=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_SELECT=1 \ +-DHAVE_SOCKET=1 -DHAVE_STRERROR=1 -DHAVE_STRTOL=1 -DHAVE_STRTOUL=1 -DHAVE_STRDUP=1 \ +-DHAVE_GETIFADDRS=1 -DINET6 -DHAVE_PFKEYV2 -O -DYIPS_DEBUG -DIPSEC -Dss_family=__ss_family \ +-Dss_len=__ss_len -DSYSCONFDIR=\"/etc\" -DYY_NO_UNPUT -I../racoon.tproj -I../ipsec + +# These variables provide hooks enabling you to add behavior at almost every +# stage of the make: +# +# BEFORE_PREBUILD: targets to build before installing headers for a subproject +# AFTER_PREBUILD: targets to build after installing headers for a subproject +# BEFORE_BUILD_RECURSION: targets to make before building subprojects +# BEFORE_BUILD: targets to make before a build, but after subprojects +# AFTER_BUILD: targets to make after a build +# +# BEFORE_INSTALL: targets to build before installing the product +# AFTER_INSTALL: targets to build after installing the product +# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject +# AFTER_POSTINSTALL: targts to build after postinstalling every subproject +# +# BEFORE_INSTALLHDRS: targets to build before installing headers for a +# subproject +# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject +# BEFORE_INSTALLSRC: targets to build before installing source for a subproject +# AFTER_INSTALLSRC: targets to build after installing source for a subproject +# +# BEFORE_DEPEND: targets to build before building dependencies for a +# subproject +# AFTER_DEPEND: targets to build after building dependencies for a +# subproject +# +# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is +# updated every time the project is built. If NO, the dependency +# file is only built when the depend target is invoked. + +# Framework-related variables: +# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the framework's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables + +# Library-related variables: +# PUBLIC_HEADER_DIR: Determines where public exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. For library projects you should +# set this to something like /Developer/Headers/$(NAME). Do not set +# this variable for framework projects unless you do not want the +# header files included in the framework. +# PRIVATE_HEADER_DIR: Determines where private exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. +# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines +# whether the libraries produced are statically linked when they +# are used or if they are dynamically loadable. This defaults to +# DYNAMIC. +# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the library's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables +# +# INSTALL_AS_USER: owner of the intalled products (default root) +# INSTALL_AS_GROUP: group of the installed products (default wheel) +# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX) +# +# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be +# passed on the command line to recursive invocations of make. Note that +# the values in OTHER_*FLAGS are inherited by subprojects automatically -- +# you do not have to (and shouldn't) add OTHER_*FLAGS to +# OTHER_RECURSIVE_VARIABLES. + +# Additional headers to export beyond those in the PB.project: +# OTHER_PUBLIC_HEADERS +# OTHER_PROJECT_HEADERS +# OTHER_PRIVATE_HEADERS + +# Additional files for the project's product: <> +# OTHER_RESOURCES: (non-localized) resources for this project +# OTHER_OFILES: relocatables to be linked into this project +# OTHER_LIBS: more libraries to link against +# OTHER_PRODUCT_DEPENDS: other dependencies of this project +# OTHER_SOURCEFILES: other source files maintained by .pre/postamble +# OTHER_GARBAGE: additional files to be removed by `make clean' + +# Set this to YES if you don't want a final libtool call for a library/framework. +# BUILD_OFILES_LIST_ONLY + +# To include a version string, project source must exist in a directory named +# $(NAME).%d[.%d][.%d] and the following line must be uncommented. +# OTHER_GENERATED_OFILES = $(VERS_OFILE) + +# This definition will suppress stripping of debug symbols when an executable +# is installed. By default it is YES. +# STRIP_ON_INSTALL = NO + +# Uncomment to suppress generation of a KeyValueCoding index when installing +# frameworks (This index is used by WOB and IB to determine keys available +# for an object). Set to YES by default. +# PREINDEX_FRAMEWORK = NO + +# Change this definition to install projects somewhere other than the +# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems +# and "" on other systems. +DSTROOT = $(HOME) diff --git a/racoonctl.tproj/PB.project b/racoonctl.tproj/PB.project new file mode 100644 index 0000000..8651f3e --- /dev/null +++ b/racoonctl.tproj/PB.project @@ -0,0 +1,35 @@ +{ + "DYNAMIC_CODE_GEN" = YES; + FILESTABLE = { + FRAMEWORKS = (); + "H_FILES" = ("misc.h", "str2val.h", "vmbuf.h"); + "OTHER_LIBS" = (ipsec); + "OTHER_LINKED" = ( + "key_debug.c", + "kmpstat.c", + "misc.c", + "pfkey.c", + "pfkey_dump.c", + "str2val.c", + "vmbuf.c" + ); + "OTHER_SOURCES" = ("Makefile.preamble", Makefile, "Makefile.postamble"); + }; + LANGUAGE = English; + MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; + "NEXTSTEP_BUILDTOOL" = "/bin/gnumake"; + "NEXTSTEP_INSTALLDIR" = "/bin"; + "NEXTSTEP_JAVA_COMPILER" = "/usr/bin/javac"; + "NEXTSTEP_OBJCPLUS_COMPILER" = "/usr/bin/cc"; + "PDO_UNIX_BUILDTOOL" = "$NEXT_ROOT/Developer/bin/make"; + "PDO_UNIX_INSTALLDIR" = "/bin"; + "PDO_UNIX_JAVA_COMPILER" = "$(JDKBINDIR)/javac"; + "PDO_UNIX_OBJCPLUS_COMPILER" = "$(NEXTDEV_BIN)/gcc"; + PROJECTNAME = racoonctl; + PROJECTTYPE = Tool; + PROJECTVERSION = "2.8"; + "WINDOWS_BUILDTOOL" = "$NEXT_ROOT/Developer/Executables/make"; + "WINDOWS_INSTALLDIR" = "/Library/Executables"; + "WINDOWS_JAVA_COMPILER" = "$(JDKBINDIR)/javac.exe"; + "WINDOWS_OBJCPLUS_COMPILER" = "$(DEVDIR)/gcc"; +} diff --git a/racoonctl.tproj/key_debug.c b/racoonctl.tproj/key_debug.c new file mode 100644 index 0000000..7ace6be --- /dev/null +++ b/racoonctl.tproj/key_debug.c @@ -0,0 +1,751 @@ +/* $FreeBSD: src/sys/netkey/key_debug.c,v 1.10.2.2 2001/07/03 11:01:59 ume Exp $ */ +/* $KAME: key_debug.c,v 1.25 2000/07/24 13:23:12 itojun 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. 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. + */ + +#ifdef _KERNEL +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" +#endif + +#include +#include +#ifdef _KERNEL +#include +#include +#include +#endif +#include + +#include + +#include +#include + +#include +#include + +#ifndef _KERNEL +#include +#include +#include +#endif /* !_KERNEL */ + +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) + +static void kdebug_sadb_prop __P((struct sadb_ext *)); +static void kdebug_sadb_identity __P((struct sadb_ext *)); +static void kdebug_sadb_supported __P((struct sadb_ext *)); +static void kdebug_sadb_lifetime __P((struct sadb_ext *)); +static void kdebug_sadb_sa __P((struct sadb_ext *)); +static void kdebug_sadb_address __P((struct sadb_ext *)); +static void kdebug_sadb_key __P((struct sadb_ext *)); +static void kdebug_sadb_x_sa2 __P((struct sadb_ext *)); + +#ifdef _KERNEL +static void kdebug_secreplay __P((struct secreplay *)); +#endif + +#ifndef _KERNEL +#define panic(param) { printf(param); exit(-1); } +#endif + +/* NOTE: host byte order */ + +/* %%%: about struct sadb_msg */ +void +kdebug_sadb(base) + struct sadb_msg *base; +{ + struct sadb_ext *ext; + int tlen, extlen; + + /* sanity check */ + if (base == NULL) + panic("kdebug_sadb: NULL pointer was passed.\n"); + + printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", + base->sadb_msg_version, base->sadb_msg_type, + base->sadb_msg_errno, base->sadb_msg_satype); + printf(" len=%u reserved=%u seq=%u pid=%u\n", + base->sadb_msg_len, base->sadb_msg_reserved, + base->sadb_msg_seq, base->sadb_msg_pid); + + tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); + + while (tlen > 0) { + printf("sadb_ext{ len=%u type=%u }\n", + ext->sadb_ext_len, ext->sadb_ext_type); + + if (ext->sadb_ext_len == 0) { + printf("kdebug_sadb: invalid ext_len=0 was passed.\n"); + return; + } + if (ext->sadb_ext_len > tlen) { + printf("kdebug_sadb: ext_len exceeds end of buffer.\n"); + return; + } + + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + kdebug_sadb_sa(ext); + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + kdebug_sadb_lifetime(ext); + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + kdebug_sadb_address(ext); + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + kdebug_sadb_key(ext); + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + kdebug_sadb_identity(ext); + break; + case SADB_EXT_SENSITIVITY: + break; + case SADB_EXT_PROPOSAL: + kdebug_sadb_prop(ext); + break; + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + kdebug_sadb_supported(ext); + break; + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_KMPRIVATE: + break; + case SADB_X_EXT_POLICY: + kdebug_sadb_x_policy(ext); + break; + case SADB_X_EXT_SA2: + kdebug_sadb_x_sa2(ext); + break; + default: + printf("kdebug_sadb: invalid ext_type %u was passed.\n", + ext->sadb_ext_type); + return; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (struct sadb_ext *)((caddr_t)ext + extlen); + } + + return; +} + +static void +kdebug_sadb_prop(ext) + struct sadb_ext *ext; +{ + struct sadb_prop *prop = (struct sadb_prop *)ext; + struct sadb_comb *comb; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_prop: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop)) + / sizeof(*comb); + comb = (struct sadb_comb *)(prop + 1); + printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay); + + while (len--) { + printf("sadb_comb{ auth=%u encrypt=%u " + "flags=0x%04x reserved=0x%08x\n", + comb->sadb_comb_auth, comb->sadb_comb_encrypt, + comb->sadb_comb_flags, comb->sadb_comb_reserved); + + printf(" auth_minbits=%u auth_maxbits=%u " + "encrypt_minbits=%u encrypt_maxbits=%u\n", + comb->sadb_comb_auth_minbits, + comb->sadb_comb_auth_maxbits, + comb->sadb_comb_encrypt_minbits, + comb->sadb_comb_encrypt_maxbits); + + printf(" soft_alloc=%u hard_alloc=%u " + "soft_bytes=%lu hard_bytes=%lu\n", + comb->sadb_comb_soft_allocations, + comb->sadb_comb_hard_allocations, + (unsigned long)comb->sadb_comb_soft_bytes, + (unsigned long)comb->sadb_comb_hard_bytes); + + printf(" soft_alloc=%lu hard_alloc=%lu " + "soft_bytes=%lu hard_bytes=%lu }\n", + (unsigned long)comb->sadb_comb_soft_addtime, + (unsigned long)comb->sadb_comb_hard_addtime, + (unsigned long)comb->sadb_comb_soft_usetime, + (unsigned long)comb->sadb_comb_hard_usetime); + comb++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_identity(ext) + struct sadb_ext *ext; +{ + struct sadb_ident *id = (struct sadb_ident *)ext; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_identity: NULL pointer was passed.\n"); + + len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); + printf("sadb_ident_%s{", + id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); + switch (id->sadb_ident_type) { + default: + printf(" type=%d id=%lu", + id->sadb_ident_type, (u_long)id->sadb_ident_id); + if (len) { +#ifdef _KERNEL + ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ +#else + char *p, *ep; + printf("\n str=\""); + p = (char *)(id + 1); + ep = p + len; + for (/*nothing*/; *p && p < ep; p++) { + if (isprint(*p)) + printf("%c", *p & 0xff); + else + printf("\\%03o", *p & 0xff); + } +#endif + printf("\""); + } + break; + } + + printf(" }\n"); + + return; +} + +static void +kdebug_sadb_supported(ext) + struct sadb_ext *ext; +{ + struct sadb_supported *sup = (struct sadb_supported *)ext; + struct sadb_alg *alg; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_supported: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup)) + / sizeof(*alg); + alg = (struct sadb_alg *)(sup + 1); + printf("sadb_sup{\n"); + while (len--) { + printf(" { id=%d ivlen=%d min=%d max=%d }\n", + alg->sadb_alg_id, alg->sadb_alg_ivlen, + alg->sadb_alg_minbits, alg->sadb_alg_maxbits); + alg++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_lifetime(ext) + struct sadb_ext *ext; +{ + struct sadb_lifetime *lft = (struct sadb_lifetime *)ext; + + /* sanity check */ + if (ext == NULL) + printf("kdebug_sadb_lifetime: NULL pointer was passed.\n"); + + printf("sadb_lifetime{ alloc=%u, bytes=%u\n", + lft->sadb_lifetime_allocations, + (u_int32_t)lft->sadb_lifetime_bytes); + printf(" addtime=%u, usetime=%u }\n", + (u_int32_t)lft->sadb_lifetime_addtime, + (u_int32_t)lft->sadb_lifetime_usetime); + + return; +} + +static void +kdebug_sadb_sa(ext) + struct sadb_ext *ext; +{ + struct sadb_sa *sa = (struct sadb_sa *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_sa: NULL pointer was passed.\n"); + + printf("sadb_sa{ spi=%u replay=%u state=%u\n", + (u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, + sa->sadb_sa_state); + printf(" auth=%u encrypt=%u flags=0x%08x }\n", + sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags); + + return; +} + +static void +kdebug_sadb_address(ext) + struct sadb_ext *ext; +{ + struct sadb_address *addr = (struct sadb_address *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_address: NULL pointer was passed.\n"); + + printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n", + addr->sadb_address_proto, addr->sadb_address_prefixlen, + ((u_char *)&addr->sadb_address_reserved)[0], + ((u_char *)&addr->sadb_address_reserved)[1]); + + kdebug_sockaddr((struct sockaddr *)((caddr_t)ext + sizeof(*addr))); + + return; +} + +static void +kdebug_sadb_key(ext) + struct sadb_ext *ext; +{ + struct sadb_key *key = (struct sadb_key *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_key: NULL pointer was passed.\n"); + + printf("sadb_key{ bits=%u reserved=%u\n", + key->sadb_key_bits, key->sadb_key_reserved); + printf(" key="); + + /* sanity check 2 */ + if ((key->sadb_key_bits >> 3) > + (PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) { + printf("kdebug_sadb_key: key length mismatch, bit:%d len:%ld.\n", + key->sadb_key_bits >> 3, + (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key)); + } + + ipsec_hexdump((caddr_t)key + sizeof(struct sadb_key), + key->sadb_key_bits >> 3); + printf(" }\n"); + return; +} + +static void +kdebug_sadb_x_sa2(ext) + struct sadb_ext *ext; +{ + struct sadb_x_sa2 *sa2 = (struct sadb_x_sa2 *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_sa2: NULL pointer was passed.\n"); + + printf("sadb_x_sa2{ mode=%u reqid=%u\n", + sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid); + printf(" reserved1=%u reserved2=%u reserved3=%u }\n", + sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved1, + sa2->sadb_x_sa2_reserved1); + + return; +} + +void +kdebug_sadb_x_policy(ext) + struct sadb_ext *ext; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext; + struct sockaddr *addr; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); + + printf("sadb_x_policy{ type=%u dir=%u id=%x }\n", + xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, + xpl->sadb_x_policy_id); + + if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + int tlen; + struct sadb_x_ipsecrequest *xisr; + + tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + while (tlen > 0) { + printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n", + xisr->sadb_x_ipsecrequest_len, + xisr->sadb_x_ipsecrequest_proto, + xisr->sadb_x_ipsecrequest_mode, + xisr->sadb_x_ipsecrequest_level, + xisr->sadb_x_ipsecrequest_reqid); + + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + addr = (struct sockaddr *)(xisr + 1); + kdebug_sockaddr(addr); + addr = (struct sockaddr *)((caddr_t)addr + + addr->sa_len); + kdebug_sockaddr(addr); + } + + printf(" }\n"); + + /* prevent infinite loop */ + if (xisr->sadb_x_ipsecrequest_len <= 0) { + printf("kdebug_sadb_x_policy: wrong policy struct.\n"); + return; + } + /* prevent overflow */ + if (xisr->sadb_x_ipsecrequest_len > tlen) { + printf("invalid ipsec policy length\n"); + return; + } + + tlen -= xisr->sadb_x_ipsecrequest_len; + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + + if (tlen != 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + } + + return; +} + +#ifdef _KERNEL +/* %%%: about SPD and SAD */ +void +kdebug_secpolicy(sp) + struct secpolicy *sp; +{ + /* sanity check */ + if (sp == NULL) + panic("kdebug_secpolicy: NULL pointer was passed.\n"); + + printf("secpolicy{ refcnt=%u state=%u policy=%u\n", + sp->refcnt, sp->state, sp->policy); + + kdebug_secpolicyindex(&sp->spidx); + + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + printf(" type=discard }\n"); + break; + case IPSEC_POLICY_NONE: + printf(" type=none }\n"); + break; + case IPSEC_POLICY_IPSEC: + { + struct ipsecrequest *isr; + for (isr = sp->req; isr != NULL; isr = isr->next) { + + printf(" level=%u\n", isr->level); + kdebug_secasindex(&isr->saidx); + + if (isr->sav != NULL) + kdebug_secasv(isr->sav); + } + printf(" }\n"); + } + break; + case IPSEC_POLICY_BYPASS: + printf(" type=bypass }\n"); + break; + case IPSEC_POLICY_ENTRUST: + printf(" type=entrust }\n"); + break; + default: + printf("kdebug_secpolicy: Invalid policy found. %d\n", + sp->policy); + break; + } + + return; +} + +void +kdebug_secpolicyindex(spidx) + struct secpolicyindex *spidx; +{ + /* sanity check */ + if (spidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n", + spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto); + + ipsec_hexdump((caddr_t)&spidx->src, + ((struct sockaddr *)&spidx->src)->sa_len); + printf("\n"); + ipsec_hexdump((caddr_t)&spidx->dst, + ((struct sockaddr *)&spidx->dst)->sa_len); + printf("}\n"); + + return; +} + +void +kdebug_secasindex(saidx) + struct secasindex *saidx; +{ + /* sanity check */ + if (saidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secasindex{ mode=%u proto=%u\n", + saidx->mode, saidx->proto); + + ipsec_hexdump((caddr_t)&saidx->src, + ((struct sockaddr *)&saidx->src)->sa_len); + printf("\n"); + ipsec_hexdump((caddr_t)&saidx->dst, + ((struct sockaddr *)&saidx->dst)->sa_len); + printf("\n"); + + return; +} + +void +kdebug_secasv(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("kdebug_secasv: NULL pointer was passed.\n"); + + printf("secas{"); + kdebug_secasindex(&sav->sah->saidx); + + printf(" refcnt=%u state=%u auth=%u enc=%u\n", + sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc); + printf(" spi=%u flags=%u\n", + (u_int32_t)ntohl(sav->spi), sav->flags); + + if (sav->key_auth != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_auth); + if (sav->key_enc != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_enc); + if (sav->iv != NULL) { + printf(" iv="); + ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); + printf("\n"); + } + + if (sav->replay != NULL) + kdebug_secreplay(sav->replay); + if (sav->lft_c != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c); + if (sav->lft_h != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h); + if (sav->lft_s != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s); + +#if notyet + /* XXX: misc[123] ? */ +#endif + + return; +} + +static void +kdebug_secreplay(rpl) + struct secreplay *rpl; +{ + int len, l; + + /* sanity check */ + if (rpl == NULL) + panic("kdebug_secreplay: NULL pointer was passed.\n"); + + printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u", + rpl->count, rpl->wsize, rpl->seq, rpl->lastseq); + + if (rpl->bitmap == NULL) { + printf(" }\n"); + return; + } + + printf("\n bitmap { "); + + for (len = 0; len < rpl->wsize; len++) { + for (l = 7; l >= 0; l--) + printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0); + } + printf(" }\n"); + + return; +} + +void +kdebug_mbufhdr(m) + struct mbuf *m; +{ + /* sanity check */ + if (m == NULL) + return; + + printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " + "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", + m, m->m_next, m->m_nextpkt, m->m_data, + m->m_len, m->m_type, m->m_flags); + + if (m->m_flags & M_PKTHDR) { + printf(" m_pkthdr{ len:%d rcvif:%p }\n", + m->m_pkthdr.len, m->m_pkthdr.rcvif); + } + + if (m->m_flags & M_EXT) { + printf(" m_ext{ ext_buf:%p ext_free:%p " + "ext_size:%u ext_ref:%p }\n", + m->m_ext.ext_buf, m->m_ext.ext_free, + m->m_ext.ext_size, m->m_ext.ext_ref); + } + + return; +} + +void +kdebug_mbuf(m0) + struct mbuf *m0; +{ + struct mbuf *m = m0; + int i, j; + + for (j = 0; m; m = m->m_next) { + kdebug_mbufhdr(m); + printf(" m_data:\n"); + for (i = 0; i < m->m_len; i++) { + if (i && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", mtod(m, u_char *)[i]); + j++; + } + printf("\n"); + } + + return; +} +#endif /* _KERNEL */ + +void +kdebug_sockaddr(addr) + struct sockaddr *addr; +{ + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + /* sanity check */ + if (addr == NULL) + panic("kdebug_sockaddr: NULL pointer was passed.\n"); + + /* NOTE: We deal with port number as host byte order. */ + printf("sockaddr{ len=%u family=%u", addr->sa_len, addr->sa_family); + + switch (addr->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *)addr; + printf(" port=%u\n", ntohs(sin->sin_port)); + ipsec_hexdump((caddr_t)&sin->sin_addr, sizeof(sin->sin_addr)); + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + printf(" port=%u\n", ntohs(sin6->sin6_port)); + printf(" flowinfo=0x%08x, scope_id=0x%08x\n", + sin6->sin6_flowinfo, sin6->sin6_scope_id); + ipsec_hexdump((caddr_t)&sin6->sin6_addr, + sizeof(sin6->sin6_addr)); + break; +#endif + } + + printf(" }\n"); + + return; +} + +void +ipsec_bindump(buf, len) + caddr_t buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) + printf("%c", (unsigned char)buf[i]); + + return; +} + + +void +ipsec_hexdump(buf, len) + caddr_t buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", (unsigned char)buf[i]); + } +#if 0 + if (i % 32 != 0) printf("\n"); +#endif + + return; +} + +#endif /* !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) */ diff --git a/racoonctl.tproj/kmpstat.c b/racoonctl.tproj/kmpstat.c new file mode 100644 index 0000000..883f6fe --- /dev/null +++ b/racoonctl.tproj/kmpstat.c @@ -0,0 +1,1101 @@ +/* $KAME: kmpstat.c,v 1.28 2001/06/01 10:14:49 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "libpfkey.h" + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "plog.h" +#include "debug.h" + +#include "schedule.h" +#include "isakmp_var.h" +#include "isakmp.h" +#include "oakley.h" +#include "handler.h" +#include "pfkey.h" +#include "admin.h" +#include "admin_var.h" + +static void usage __P((void)); +static void com_init __P((void)); +static int com_send __P((vchar_t *)); +static vchar_t *com_recv __P((void)); + +static vchar_t *get_combuf __P((int, char **)); +static vchar_t *f_reload __P((int, char **)); +static vchar_t *f_getsched __P((int, char **)); +static vchar_t *f_getsa __P((int, char **)); +static vchar_t *f_flushsa __P((int, char **)); +static vchar_t *f_deletesa __P((int, char **)); +static vchar_t *f_exchangesa __P((int, char **)); + +struct cmd_tag { + vchar_t *(*func) __P((int, char **)); + int cmd; + char *str; +} cmdtab[] = { + { f_reload, ADMIN_RELOAD_CONF, "reload-config" }, + { f_reload, ADMIN_RELOAD_CONF, "rc" }, + { f_getsched, ADMIN_SHOW_SCHED, "show-schedule" }, + { f_getsched, ADMIN_SHOW_SCHED, "sc" }, + { f_getsa, ADMIN_SHOW_SA, "show-sa" }, + { f_getsa, ADMIN_SHOW_SA, "ss" }, + { f_flushsa, ADMIN_FLUSH_SA, "flush-sa" }, + { f_flushsa, ADMIN_FLUSH_SA, "fs" }, + { f_deletesa, ADMIN_DELETE_SA, "delete-sa" }, + { f_deletesa, ADMIN_DELETE_SA, "ds" }, + { f_exchangesa, ADMIN_ESTABLISH_SA, "establish-sa" }, + { f_exchangesa, ADMIN_ESTABLISH_SA, "es" }, + { NULL, 0, NULL }, +}; + +static int get_proto __P((char *)); +static vchar_t *get_index __P((int, char **)); +static int get_family __P((char *)); +static vchar_t *get_comindexes __P((int, int, char **)); +static int get_comindex __P((char *, char **, char **, char **)); +static struct sockaddr *get_sockaddr __P((int, char *, char *)); +static int get_ulproto __P((char *)); + +struct proto_tag { + int proto; + char *str; +} prototab[] = { + { ADMIN_PROTO_ISAKMP, "isakmp" }, + { ADMIN_PROTO_IPSEC, "ipsec" }, + { ADMIN_PROTO_AH, "ah" }, + { ADMIN_PROTO_ESP, "esp" }, + { ADMIN_PROTO_INTERNAL, "internal" }, + { 0, NULL }, +}; + +struct ulproto_tag { + int ul_proto; + char *str; +} ulprototab[] = { + { 0, "any" }, + { IPPROTO_ICMP, "icmp" }, + { IPPROTO_TCP, "tcp" }, + { IPPROTO_UDP, "udp" }, + { 0, NULL }, +}; + +int so; + +static char _addr1_[NI_MAXHOST], _addr2_[NI_MAXHOST]; + +char *pname; +int long_format = 0; +u_int32_t loglevel = 4; + +void dump_isakmp_sa __P((char *, int)); +void dump_internal __P((char *, int)); +char *pindex_isakmp __P((isakmp_index *)); +void print_schedule __P((caddr_t, int)); +char * fixed_addr __P((char *, char *, int)); + +static void +usage() +{ + printf( +"Usage:\n" +" %s reload-config\n" +" %s [-l [-l]] show-sa [protocol]\n" +" %s flush-sa [protocol]\n" +" %s delete-sa \n" +" %s establish-sa \n" +"\n" +" : \"isakmp\", \"esp\" or \"ah\".\n" +" In the case of \"show-sa\" or \"flush-sa\", you can use \"ipsec\".\n" +"\n" +" : \"isakmp\" \n" +" : {\"esp\",\"ah\"} \n" +" \n" +" : \"inet\" or \"inet6\"\n" +" : \"icmp\", \"tcp\", \"udp\" or \"any\"\n", + pname, pname, pname, pname, pname); +} + +int +main(ac, av) + int ac; + char **av; +{ + extern char *optarg; + extern int optind; + vchar_t *combuf; + int c; + + pname = *av; + + while ((c = getopt(ac, av, "ld")) != -1) { + switch(c) { + case 'l': + long_format++; + break; + + case 'd': + loglevel++; + break; + + default: + usage(); + exit(0); + } + } + + ac -= optind; + av += optind; + + combuf = get_combuf(ac, av); + if (!combuf) + err(1, "kmpstat"); + + if (loglevel) + hexdump(combuf, ((struct admin_com *)combuf)->ac_len); + + com_init(); + + if (com_send(combuf) < 0) + goto bad; + + vfree(combuf); + + combuf = com_recv(); + if (!combuf) + goto bad; + + exit(0); + + bad: + exit(1); +} + +static void +com_init() +{ + struct sockaddr_un name; + + memset(&name, 0, sizeof(name)); + name.sun_family = AF_UNIX; + snprintf(name.sun_path, sizeof(name.sun_path), + "%s", PORT_ADMIN); + + so = socket(AF_UNIX, SOCK_STREAM, 0); + if (so < 0) + err(1, "socket"); + + if (connect(so, (struct sockaddr *)&name, sizeof(name)) < 0) { + (void)close(so); + err(1, "connect"); + } +} + +static int +com_send(combuf) + vchar_t *combuf; +{ + int len; + + if ((len = send(so, combuf->v, combuf->l, 0)) < 0){ + perror("send"); + (void)close(so); + return -1; + } + + return len; +} + +static vchar_t * +com_recv() +{ + vchar_t *combuf = NULL; + struct admin_com h, *com; + caddr_t buf; + int len; + + /* receive by PEEK */ + len = recv(so, &h, sizeof(h), MSG_PEEK); + if (len == -1) + goto bad; + + /* sanity check */ + if (len < sizeof(h)) + return NULL; + if (len == 0) + goto bad; + + /* error ? */ + if (h.ac_errno) { + errno = h.ac_errno; + goto bad; + } + + /* allocate buffer */ + combuf = vmalloc(h.ac_len); + if (combuf == NULL) + goto bad; + + /* read real message */ + { + int l = 0; + caddr_t p = combuf->v; + while (l < combuf->l) { + if ((len = recv(so, p, h.ac_len, 0)) < 0) { + perror("recv"); + goto bad; + } + l += len; + p += len; + } + } + + com = (struct admin_com *)combuf->v; + len = com->ac_len - sizeof(*com); + buf = combuf->v + sizeof(*com); + + switch (com->ac_cmd) { + case ADMIN_SHOW_SCHED: + print_schedule(buf, len); + break; + + case ADMIN_SHOW_SA: + { + switch (com->ac_proto) { + case ADMIN_PROTO_ISAKMP: + dump_isakmp_sa(buf, len); + break; + case ADMIN_PROTO_IPSEC: + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + { + struct sadb_msg *msg = (struct sadb_msg *)buf; + + switch (msg->sadb_msg_errno) { + case ENOENT: + switch (msg->sadb_msg_type) { + case SADB_DELETE: + case SADB_GET: + printf("No entry.\n"); + break; + case SADB_DUMP: + printf("No SAD entries.\n"); + break; + } + break; + case 0: + while (1) { + pfkey_sadump(msg); + if (msg->sadb_msg_seq == 0) + break; + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + } + break; + default: + printf("%s.\n", strerror(msg->sadb_msg_errno)); + } + } + break; + case ADMIN_PROTO_INTERNAL: + dump_internal(buf, len); + break; + default: + printf("Invalid proto [%d]\n", com->ac_proto); + } + + } + break; + +/* default:*/ + /* IGNORE */ + } + + (void)close(so); + return combuf; + + bad: + (void)close(so); + return NULL; +} + +/* %%% */ +/* + * return command buffer. + */ +static vchar_t * +get_combuf(ac, av) + int ac; + char **av; +{ + struct cmd_tag *cp; + + if (ac == 0) { + usage(); + exit(0); + } + + /* checking the string of command. */ + for (cp = &cmdtab[0]; cp->str; cp++) { + if (strcmp(*av, cp->str) == 0) { + break; + } + } + if (!cp->str) { + printf("Invalid command [%s]\n", *av); + errno = EINVAL; + return NULL; + } + + ac--; + av++; + return (cp->func)(ac, av); +} + +static vchar_t * +f_reload(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_RELOAD_CONF; + head->ac_errno = 0; + head->ac_proto = 0; + + return buf; +} + +static vchar_t * +f_getsched(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_SHOW_SCHED; + head->ac_errno = 0; + head->ac_proto = 0; + + return buf; +} + +static vchar_t * +f_getsa(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac != 1) + errx(1, "insufficient arguments"); + proto = get_proto(*av); + if (proto == -1) + errx(1, "unknown protocol %s", *av); + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_SHOW_SA; + head->ac_errno = 0; + head->ac_proto = proto; + + return buf; +} + +static vchar_t * +f_flushsa(ac, av) + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac != 1) + errx(1, "insufficient arguments"); + proto = get_proto(*av); + if (proto == -1) + errx(1, "unknown protocol %s", *av); + + buf = vmalloc(sizeof(*head)); + if (buf == NULL) + errx(1, "not enough core"); + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l; + head->ac_cmd = ADMIN_FLUSH_SA; + head->ac_errno = 0; + head->ac_proto = proto; + + return buf; +} + +static vchar_t * +f_deletesa(ac, av) + int ac; + char **av; +{ + vchar_t *buf, *index; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac < 1) + errx(1, "insufficient arguments"); + proto = get_proto(*av); + if (proto == -1) + errx(1, "unknown protocol %s", *av); + + /* get index(es) */ + av++; + ac--; + switch (proto) { + case ADMIN_PROTO_ISAKMP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + default: + errno = EPROTONOSUPPORT; + return NULL; + } + + buf = vmalloc(sizeof(*head) + index->l); + if (buf == NULL) + return NULL; + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l + index->l; + head->ac_cmd = ADMIN_DELETE_SA; + head->ac_errno = 0; + head->ac_proto = proto; + + return buf; +} + +static vchar_t * +f_exchangesa(ac, av) + int ac; + char **av; +{ + vchar_t *buf, *index; + struct admin_com *head; + int proto; + + /* need protocol */ + if (ac < 1) + errx(1, "insufficient arguments"); + if ((proto = get_proto(*av)) == -1) + errx(1, "unknown protocol %s", *av); + + /* get index(es) */ + av++; + ac--; + switch (proto) { + case ADMIN_PROTO_ISAKMP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + case ADMIN_PROTO_AH: + case ADMIN_PROTO_ESP: + index = get_index(ac, av); + if (index == NULL) + return NULL; + break; + default: + errno = EPROTONOSUPPORT; + return NULL; + } + + buf = vmalloc(sizeof(*head) + index->l); + if (buf == NULL) + return NULL; + + head = (struct admin_com *)buf->v; + head->ac_len = buf->l + index->l; + head->ac_cmd = ADMIN_DELETE_SA; + head->ac_errno = 0; + head->ac_proto = proto; + + return buf; +} + +static int +get_proto(str) + char *str; +{ + struct proto_tag *cp; + + if (str == NULL) { + errno = EINVAL; + return -1; + } + + /* checking the string of command. */ + for (cp = &prototab[0]; cp->str; cp++) { + if (strcmp(str, cp->str) == 0) + return cp->proto; + } + + errno = EINVAL; + return -1; +} + +static vchar_t * +get_index(ac, av) + int ac; + char **av; +{ + int family; + + if (ac != 3) { + errno = EINVAL; + return NULL; + } + + /* checking the string of family */ + family = get_family(*av); + if (family == -1) + return NULL; + av++; + + return get_comindexes(family, ac, av); +} + +static int +get_family(str) + char *str; +{ + if (strcmp("inet", str) == 0) + return AF_INET; +#ifdef INET6 + else if (strcmp("inet6", str) == 0) + return AF_INET6; +#endif + errno = EAFNOSUPPORT; + return -1; +} + +static vchar_t * +get_comindexes(family, ac, av) + int family; + int ac; + char **av; +{ + vchar_t *buf; + struct admin_com_indexes *ci; + char *p_name = NULL, *p_port = NULL; + char *p_prefs = NULL, *p_prefd = NULL; + struct sockaddr *src = NULL, *dst = NULL; + int ulproto; + + if (ac != 2) { + errno = EINVAL; + return NULL; + } + + if (get_comindex(*av, &p_name, &p_port, &p_prefs) == -1) + goto bad; + src = get_sockaddr(family, p_name, p_port); + if (p_name) { + racoon_free(p_name); + p_name = NULL; + } + if (p_port) { + racoon_free(p_port); + p_port = NULL; + } + if (src == NULL) + goto bad; + av++; + if (get_comindex(*av, &p_name, &p_port, &p_prefd) == -1) + goto bad; + dst = get_sockaddr(family, p_name, p_port); + if (dst == NULL) + goto bad; + + buf = vmalloc(sizeof(*ci)); + if (buf == NULL) + goto bad; + + av++; + ulproto = get_ulproto(*av); + if (ulproto == -1) + goto bad; + + ci = (struct admin_com_indexes *)buf; + ci->prefs = (u_int8_t)atoi(p_prefs); /* XXX should be handled error. */ + ci->prefd = (u_int8_t)atoi(p_prefd); /* XXX should be handled error. */ + ci->ul_proto = ulproto; + memcpy(&ci->src, src, src->sa_len); + memcpy(&ci->dst, dst, dst->sa_len); + + if (p_name) + + return buf; + + bad: + if (p_name) + racoon_free(p_name); + if (p_port) + racoon_free(p_port); + if (p_prefs); + racoon_free(p_prefs); + if (p_prefd); + racoon_free(p_prefd); + return NULL; +} + +static int +get_comindex(str, name, port, pref) + char *str, **name, **port, **pref; +{ + char *p; + + *name = *port = *pref = NULL; + + *name = strdup(str); + p = strpbrk(*name, "/["); + if (p != NULL) { + if (*(p + 1) == '\0') + goto bad; + if (*p == '/') { + *p = '\0'; + *pref = strdup(p + 1); + p = strchr(*pref, '['); + if (p != NULL) { + if (*(p + 1) == '\0') + goto bad; + *p = '\0'; + *port = strdup(p + 1); + p = strchr(*pref, ']'); + if (p == NULL) + goto bad; + *p = '\0'; + } + } else if (*p == '[') { + *p = '\0'; + *port = strdup(p + 1); + p = strchr(*pref, ']'); + if (p == NULL) + goto bad; + *p = '\0'; + } else { + /* XXX */ + } + } + + return 0; + + bad: + if (*name) + racoon_free(*name); + if (*port) + racoon_free(*port); + if (*pref) + racoon_free(*pref); + *name = *port = *pref = NULL; + return -1; +} + +static struct sockaddr * +get_sockaddr(family, name, port) + int family; + char *name, *port; +{ + struct addrinfo hint, *ai; + int error; + + memset(&hint, 0, sizeof(hint)); + hint.ai_family = PF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(name, port, &hint, &ai); + if (error != 0) { + printf("%s: %s/%s\n", gai_strerror(error), name, port); + return NULL; + } + + return ai->ai_addr; +} + +static int +get_ulproto(str) + char *str; +{ + struct ulproto_tag *cp; + + /* checking the string of upper layer protocol. */ + for (cp = &ulprototab[0]; cp->str; cp++) { + if (strcmp(str, cp->str) == 0) + return cp->ul_proto; + } + + errno = EINVAL; + return -1; +} + +/* %%% */ +void +dump_isakmp_sa(buf, len) + char *buf; + int len; +{ + struct ph1dump *pd; + struct tm *tm; + char tbuf[56]; + caddr_t p = NULL; + +/* isakmp status header */ +/* short header; + 1234567890123456789012 0000000000000000:0000000000000000 000000000000 +*/ +char *header1 = +"Destination Cookies Created"; + +/* semi long header; + 1234567890123456789012 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000 +*/ +char *header2 = +"Destination Cookies ST S V E Created Phase2"; + +/* long header; + 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000000000000000:0000000000000000 00 X 00 X 0000-00-00 00:00:00 000000 +*/ +char *header3 = +"Source Destination Cookies ST S V E Created Phase2"; + +/* phase status header */ +/* short format; + side stats source address destination address + xxx xxxxx 1234567890123456789012 1234567890123456789012 +*/ + + static char *estr[] = { "", "B", "M", "U", "A", "I", }; + + switch (long_format) { + case 0: + printf("%s\n", header1); + break; + case 1: + printf("%s\n", header2); + break; + case 2: + default: + printf("%s\n", header3); + break; + } + + if (len % sizeof(*pd)) + printf("invalid length %d\n", len); + len /= sizeof(*pd); + + pd = (struct ph1dump *)buf; + + while (len-- > 0) { + /* source address */ + if (long_format >= 2) { + GETNAMEINFO((struct sockaddr *)&pd->local, _addr1_, _addr2_); + switch (long_format) { + case 0: + break; + case 1: + p = fixed_addr(_addr1_, _addr2_, 22); + break; + case 2: + default: + p = fixed_addr(_addr1_, _addr2_, 45); + break; + } + printf("%s ", p); + } + + /* destination address */ + GETNAMEINFO((struct sockaddr *)&pd->remote, _addr1_, _addr2_); + switch (long_format) { + case 0: + case 1: + p = fixed_addr(_addr1_, _addr2_, 22); + break; + case 2: + default: + p = fixed_addr(_addr1_, _addr2_, 45); + break; + } + printf("%s ", p); + + printf("%s ", pindex_isakmp(&pd->index)); + + /* statuc, side and version */ + if (long_format >= 1) { + printf("%2d %c %2x ", + pd->status, + pd->side == INITIATOR ? 'I' : 'R', + pd->version); + if (ARRAYLEN(estr) > pd->etype) + printf("%s ", estr[pd->etype]); + } + + /* created date */ + if (pd->created) { + tm = localtime(&pd->created); + strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm); + } else + snprintf(tbuf, sizeof(tbuf), " "); + printf("%s ", tbuf); + + /* counter of phase 2 */ + if (long_format >= 1) + printf("%6d ", pd->ph2cnt); + + printf("\n"); + + pd++; + } + + return; +} + +/* %%% */ +void +dump_internal(buf, tlen) + char *buf; + int tlen; +{ + struct ph2handle *iph2; + struct sockaddr *addr; + +/* +short header; + source address destination address + 1234567890123456789012 1234567890123456789012 +*/ +char *short_h1 = +"Source Destination "; + +/* +long header; + source address destination address + 123456789012345678901234567890123456789012345 123456789012345678901234567890123456789012345 + 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 0000:0000:0000:0000:0000:0000:0000:0000.00000 +*/ +char *long_h1 = +"Source Destination "; + + printf("%s\n", long_format ? long_h1 : short_h1); + + while (tlen > 0) { + iph2 = (struct ph2handle *)buf; + addr = (struct sockaddr *)(++iph2); + + GETNAMEINFO(addr, _addr1_, _addr2_); + printf("%s ", long_format ? + fixed_addr(_addr1_, _addr2_, 45) + : fixed_addr(_addr1_, _addr2_, 22)); + addr++; + tlen -= addr->sa_len; + + GETNAMEINFO(addr, _addr1_, _addr2_); + printf("%s ", long_format ? + fixed_addr(_addr1_, _addr2_, 45) + : fixed_addr(_addr1_, _addr2_, 22)); + addr++; + tlen -= addr->sa_len; + + printf("\n"); + } + + return; +} + +/* %%% */ +char * +pindex_isakmp(index) + isakmp_index *index; +{ + static char buf[64]; + u_char *p; + int i, j; + + memset(buf, 0, sizeof(buf)); + + /* copy index */ + p = (u_char *)index; + for (j = 0, i = 0; i < sizeof(isakmp_index); i++) { + snprintf((char *)&buf[j], sizeof(buf) - j, "%02x", p[i]); + j += 2; + switch (i) { + case 7: +#if 0 + case 15: +#endif + buf[j++] = ':'; + } + } + + return buf; +} + +/* print schedule */ +char *str_sched_stat[] = { +"off", +"on", +"dead", +}; + +char *str_sched_id[] = { +"PH1resend", +"PH1lifetime", +"PH2resend", +"PSTacquire", +"PSTlifetime", +}; + +void +print_schedule(buf, len) + caddr_t buf; + int len; +{ + struct scheddump *sc = (struct scheddump *)buf; + struct tm *tm; + char tbuf[56]; + + if (len % sizeof(*sc)) + printf("invalid length %d\n", len); + len /= sizeof(*sc); + + /* 00000000 00000000 00000000 xxx........*/ + printf("index tick xtime created\n"); + + while (len-- > 0) { + tm = localtime(&sc->created); + strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %T", tm); + + printf("%-8ld %-8ld %-8ld %s\n", + sc->id, + (long)sc->tick, + (long)sc->xtime, + tbuf); + sc++; + } + + return; +} + +char * +fixed_addr(addr, port, len) + char *addr, *port; + int len; +{ + static char _addr_buf_[BUFSIZ]; + char *p; + int plen, i; + + /* initialize */ + memset(_addr_buf_, ' ', sizeof(_addr_buf_)); + + plen = strlen(port); + if (len < plen + 1) + return NULL; + + p = _addr_buf_; + for (i = 0; i < len - plen - 1 && addr[i] != '\0'; /*noting*/) + *p++ = addr[i++]; + *p++ = '.'; + + for (i = 0; i < plen && port[i] != '\0'; /*noting*/) + *p++ = port[i++]; + + _addr_buf_[len] = '\0'; + + return _addr_buf_; +} diff --git a/racoonctl.tproj/misc.c b/racoonctl.tproj/misc.c new file mode 100644 index 0000000..8906017 --- /dev/null +++ b/racoonctl.tproj/misc.c @@ -0,0 +1,167 @@ +/* $KAME: misc.c,v 1.22 2001/07/14 05:48:33 sakane 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. 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "debug.h" + +#if 0 +static int bindump __P((void *, size_t)); + +static int +bindump(buf0, len) + void *buf0; + size_t len; +{ + unsigned char *buf = (unsigned char *)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if ((buf[i] & 0x80) || !isprint(buf[i])) + printf("\\x%x", buf[i]); + else + printf("%c", buf[i]); + } + printf("\n"); + + return 0; +} +#endif + +int +hexdump(buf0, len) + void *buf0; + size_t len; +{ + caddr_t buf = (caddr_t)buf0; + size_t i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", (unsigned char)buf[i]); + } + printf("\n"); + + return 0; +} + +char * +bit2str(n, bl) + int n, bl; +{ +#define MAXBITLEN 128 + static char b[MAXBITLEN + 1]; + int i; + + if (bl > MAXBITLEN) + return "Failed to convert."; /* NG */ + memset(b, '0', bl); + b[bl] = '\0'; + + for (i = 0; i < bl; i++) { + if (n & (1 << i)) + b[bl - 1 - i] = '1'; + } + + return b; +} + +const char * +debug_location(file, line, func) + const char *file; + int line; + const char *func; +{ + static char buf[1024]; + const char *p; + + /* truncate pathname */ + p = strrchr(file, '/'); + if (p) + p++; + else + p = file; + + if (func) + snprintf(buf, sizeof(buf), "%s:%d:%s()", p, line, func); + else + snprintf(buf, sizeof(buf), "%s:%d", p, line); + + return buf; +} + +/* + * get file size. + * -1: error occured. + */ +int +getfsize(path) + char *path; +{ + struct stat st; + + if (stat(path, &st) != 0) + return -1; + else + return st.st_size; +} + +/* + * calculate the difference between two times. + * t1: start + * t2: end + */ +double +timedelta(t1, t2) + struct timeval *t1, *t2; +{ + if (t2->tv_usec >= t1->tv_usec) + return t2->tv_sec - t1->tv_sec + + (double)(t2->tv_usec - t1->tv_usec) / 1000000; + + return t2->tv_sec - t1->tv_sec - 1 + + (double)(1000000 + t2->tv_usec - t1->tv_usec) / 1000000; +} diff --git a/racoonctl.tproj/misc.h b/racoonctl.tproj/misc.h new file mode 100644 index 0000000..c5f2846 --- /dev/null +++ b/racoonctl.tproj/misc.h @@ -0,0 +1,46 @@ +/* $KAME: misc.h,v 1.11 2001/07/14 05:48:33 sakane 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. 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. + */ + +#define BIT2STR(b) bit2str(b, sizeof(b)<<3) + +#ifdef HAVE_FUNCTION_MACRO +#define LOCATION debug_location(__FILE__, __LINE__, __FUNCTION__) +#else +#define LOCATION debug_location(__FILE__, __LINE__, NULL) +#endif + +extern int hexdump __P((void *, size_t)); +extern char *bit2str __P((int, int)); +extern void *get_newbuf __P((void *, size_t)); +extern const char *debug_location __P((const char *, int, const char *)); +extern int getfsize __P((char *)); +struct timeval; +extern double timedelta __P((struct timeval *, struct timeval *)); diff --git a/racoonctl.tproj/pfkey.c b/racoonctl.tproj/pfkey.c new file mode 100644 index 0000000..813b304 --- /dev/null +++ b/racoonctl.tproj/pfkey.c @@ -0,0 +1,2108 @@ +/* $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +#define CALLOC(size, cast) (cast)calloc(1, (size)) + +static int findsupportedmap __P((int)); +static int setsupportedmap __P((struct sadb_supported *)); +static struct sadb_alg *findsupportedalg __P((u_int, u_int)); +static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, + u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static int pfkey_send_x2 __P((int, u_int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +static int pfkey_send_x3 __P((int, u_int, u_int)); +static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + char *, int, u_int32_t)); +static int pfkey_send_x5 __P((int, u_int, u_int32_t)); + +static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int, + u_int, u_int32_t, pid_t)); +static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, + u_int, u_int, u_int32_t)); +static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int, + struct sockaddr *, u_int, u_int)); +static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int)); +static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t)); + +/* + * make and search supported algorithm structure. + */ +static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, }; + +static int supported_map[] = { + SADB_SATYPE_AH, + SADB_SATYPE_ESP, + SADB_X_SATYPE_IPCOMP, +}; + +static int +findsupportedmap(satype) + int satype; +{ + int i; + + for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++) + if (supported_map[i] == satype) + return i; + return -1; +} + +static struct sadb_alg * +findsupportedalg(satype, alg_id) + u_int satype, alg_id; +{ + int algno; + int tlen; + caddr_t p; + + /* validity check */ + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + if (ipsec_supported[algno] == NULL) { + __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; + return NULL; + } + + tlen = ipsec_supported[algno]->sadb_supported_len + - sizeof(struct sadb_supported); + p = (caddr_t)(ipsec_supported[algno] + 1); + while (tlen > 0) { + if (tlen < sizeof(struct sadb_alg)) { + /* invalid format */ + break; + } + if (((struct sadb_alg *)p)->sadb_alg_id == alg_id) + return (struct sadb_alg *)p; + + tlen -= sizeof(struct sadb_alg); + p += sizeof(struct sadb_alg); + } + + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return NULL; +} + +static int +setsupportedmap(sup) + struct sadb_supported *sup; +{ + struct sadb_supported **ipsup; + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + if (*ipsup) + free(*ipsup); + + *ipsup = malloc(sup->sadb_supported_len); + if (!*ipsup) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + memcpy(*ipsup, sup, sup->sadb_supported_len); + + return 0; +} + +/* + * check key length against algorithm specified. + * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the + * augument, and only calls to ipsec_check_keylen2(); + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen(supported, alg_id, keylen) + u_int supported; + u_int alg_id; + u_int keylen; +{ + int satype; + + /* validity check */ + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + return ipsec_check_keylen2(satype, alg_id, keylen); +} + +/* + * check key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen2(satype, alg_id, keylen) + u_int satype; + u_int alg_id; + u_int keylen; +{ + struct sadb_alg *alg; + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { + __ipsec_errcode = EIPSEC_INVAL_KEYLEN; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * get max/min key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_get_keylen(supported, alg_id, alg0) + u_int supported, alg_id; + struct sadb_alg *alg0; +{ + struct sadb_alg *alg; + u_int satype; + + /* validity check */ + if (!alg0) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + memcpy(alg0, alg, sizeof(*alg0)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set the rate for SOFT lifetime against HARD one. + * If rate is more than 100 or equal to zero, then set to 100. + */ +static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; + +u_int +pfkey_set_softrate(type, rate) + u_int type, rate; +{ + __ipsec_errcode = EIPSEC_NO_ERROR; + + if (rate > 100 || rate == 0) + rate = 100; + + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + soft_lifetime_allocations_rate = rate; + return 0; + case SADB_X_LIFETIME_BYTES: + soft_lifetime_bytes_rate = rate; + return 0; + case SADB_X_LIFETIME_ADDTIME: + soft_lifetime_addtime_rate = rate; + return 0; + case SADB_X_LIFETIME_USETIME: + soft_lifetime_usetime_rate = rate; + return 0; + } + + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return 1; +} + +/* + * get current rate for SOFT lifetime against HARD one. + * ATTENTION: ~0 is returned if invalid type was passed. + */ +u_int +pfkey_get_softrate(type) + u_int type; +{ + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + return soft_lifetime_allocations_rate; + case SADB_X_LIFETIME_BYTES: + return soft_lifetime_bytes_rate; + case SADB_X_LIFETIME_ADDTIME: + return soft_lifetime_addtime_rate; + case SADB_X_LIFETIME_USETIME: + return soft_lifetime_usetime_rate; + } + + return ~0; +} + +/* + * sending SADB_GETSPI message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t min, max, reqid, seq; +{ + struct sadb_msg *newmsg; + caddr_t ep; + int len; + int need_spirange = 0; + caddr_t p; + int plen; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (min > max || (min > 0 && min <= 255)) { + __ipsec_errcode = EIPSEC_INVAL_SPI; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if (min > 255 && max < ~0) { + need_spirange++; + len += sizeof(struct sadb_spirange); + } + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI, + len, satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for source */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for destination */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* proccessing spi range */ + if (need_spirange) { + struct sadb_spirange spirange; + + if (p + sizeof(spirange) > ep) { + free(newmsg); + return -1; + } + + memset(&spirange, 0, sizeof(spirange)); + spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); + spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + spirange.sadb_spirange_min = min; + spirange.sadb_spirange_max = max; + + memcpy(p, &spirange, sizeof(spirange)); + + p += sizeof(spirange); + } + if (p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_UPDATE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_ADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_delete(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE without spi to the kernel. This is + * the "delete all" request (an extension also present in + * Solaris). + * + * OUT: + * positive: success and return length sent + * -1 : error occured, and set errno + */ +int +pfkey_send_delete_all(so, satype, mode, src, dst) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_GET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_get(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_REGISTER message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_register(so, satype) + int so; + u_int satype; +{ + int len, algno; + + if (satype == PF_UNSPEC) { + for (algno = 0; + algno < sizeof(supported_map)/sizeof(supported_map[0]); + algno++) { + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + } else { + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + + if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) + return -1; + + return len; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_recv_register(so) + int so; +{ + pid_t pid = getpid(); + struct sadb_msg *newmsg; + int error = -1; + + /* receive message */ + do { + if ((newmsg = pfkey_recv(so)) == NULL) + return -1; + } while (newmsg->sadb_msg_type != SADB_REGISTER + || newmsg->sadb_msg_pid != pid); + + /* check and fix */ + newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); + + error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); + free(newmsg); + + if (error == 0) + __ipsec_errcode = EIPSEC_NO_ERROR; + + return error; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * NOTE: sadb_msg_len must be host order. + * IN: + * tlen: msg length, it's to makeing sure. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_set_supported(msg, tlen) + struct sadb_msg *msg; + int tlen; +{ + struct sadb_supported *sup; + caddr_t p; + caddr_t ep; + + /* validity */ + if (msg->sadb_msg_len != tlen) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + p = (caddr_t)msg; + ep = p + tlen; + + p += sizeof(struct sadb_msg); + + while (p < ep) { + sup = (struct sadb_supported *)p; + if (ep < p + sizeof(*sup) || + PFKEY_EXTLEN(sup) < sizeof(*sup) || + ep < p + sup->sadb_supported_len) { + /* invalid format */ + break; + } + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* fixed length */ + sup->sadb_supported_len = PFKEY_EXTLEN(sup); + + /* set supported map */ + if (setsupportedmap(sup) != 0) + return -1; + + p += sup->sadb_supported_len; + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + + return 0; +} + +/* + * sending SADB_FLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_flush(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_dump(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_PROMISC message to the kernel. + * NOTE that this function handles promisc mode toggle only. + * IN: + * flag: set promisc off if zero, set promisc on if non-zero. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + * 0 : error occured, and set errno. + * others: a pointer to new allocated buffer in which supported + * algorithms is. + */ +int +pfkey_send_promisc_toggle(so, flag) + int so; + int flag; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete2(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDGET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdget(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDSETIDX message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDFLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdflush(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDDUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddump(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* sending SADB_ADD or SADB_UPDATE message to the kernel */ +static int +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + u_int wsize; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + switch (satype) { + case SADB_SATYPE_ESP: + if (e_type == SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_SATYPE_AH: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type == SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_X_SATYPE_IPCOMP: + if (e_type == SADB_X_CALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime); + + if (e_type != SADB_EALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); + if (a_type != SADB_AALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + if (e_type != SADB_EALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, + keymat, e_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + if (a_type != SADB_AALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, + keymat + e_keylen, a_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + + /* set sadb_lifetime for destination */ + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_DELETE or SADB_GET message to the kernel */ +static int +pfkey_send_x2(so, type, satype, mode, src, dst, spi) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message + * to the kernel + */ +static int +pfkey_send_x3(so, type, satype) + int so; + u_int type, satype; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + caddr_t ep; + + /* validity check */ + switch (type) { + case SADB_X_PROMISC: + if (satype != 0 && satype != 1) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + default: + switch (satype) { + case SADB_SATYPE_UNSPEC: + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDADD message to the kernel */ +static int +pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int type, prefs, prefd, proto; + u_int64_t ltime, vtime; + char *policy; + int policylen; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + if (prefs > plen || prefd > plen) { + __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_lifetime) + + policylen; + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + 0, 0, ltime, vtime); + if (!p || p + policylen != ep) { + free(newmsg); + return -1; + } + memcpy(p, policy, policylen); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ +static int +pfkey_send_x5(so, type, spid) + int so; + u_int type; + u_int32_t spid; +{ + struct sadb_msg *newmsg; + struct sadb_x_policy xpl; + int len; + caddr_t p; + caddr_t ep; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(xpl); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, 0, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + if (p + sizeof(xpl) != ep) { + free(newmsg); + return -1; + } + memset(&xpl, 0, sizeof(xpl)); + xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl)); + xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl.sadb_x_policy_id = spid; + memcpy(p, &xpl, sizeof(xpl)); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * open a socket. + * OUT: + * -1: fail. + * others : success and return value of socket. + */ +int +pfkey_open() +{ + int so; + const int bufsiz = 128 * 1024; /*is 128K enough?*/ + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + /* + * This is a temporary workaround for KAME PR 154. + * Don't really care even if it fails. + */ + (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); + (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return so; +} + +/* + * close a socket. + * OUT: + * 0: success. + * -1: fail. + */ +void +pfkey_close(so) + int so; +{ + (void)close(so); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return; +} + +/* + * receive sadb_msg data, and return pointer to new buffer allocated. + * Must free this buffer later. + * OUT: + * NULL : error occured. + * others : a pointer to sadb_msg structure. + * + * XXX should be rewritten to pass length explicitly + */ +struct sadb_msg * +pfkey_recv(so) + int so; +{ + struct sadb_msg buf, *newmsg; + int len, reallen; + + while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + if (len < sizeof(buf)) { + recv(so, (caddr_t)&buf, sizeof(buf), 0); + __ipsec_errcode = EIPSEC_MAX; + return NULL; + } + + /* read real message */ + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + free(newmsg); + return NULL; + } + + if (len != reallen) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + /* don't trust what the kernel says, validate! */ + if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return newmsg; +} + +/* + * send message to a socket. + * OUT: + * others: success and return length sent. + * -1 : fail. + */ +int +pfkey_send(so, msg, len) + int so; + struct sadb_msg *msg; + int len; +{ + if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * %%% Utilities + * NOTE: These functions are derived from netkey/key.c in KAME. + */ +/* + * set the pointer to each header in this message buffer. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * caddr_t mhp[SADB_EXT_MAX + 1]; + * OUT: -1: invalid. + * 0: valid. + * + * XXX should be rewritten to obtain length explicitly + */ +int +pfkey_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; +{ + struct sadb_ext *ext; + int i; + caddr_t p; + caddr_t ep; /* XXX should be passed from upper layer */ + + /* validity check */ + if (msg == NULL || mhp == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (caddr_t)msg; + + /* initialize */ + p = (caddr_t) msg; + ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); + + /* skip base header */ + p += sizeof(struct sadb_msg); + + while (p < ep) { + ext = (struct sadb_ext *)p; + if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) || + ep < p + PFKEY_EXTLEN(ext)) { + /* invalid format */ + break; + } + + /* duplicate check */ + /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ + if (mhp[ext->sadb_ext_type] != NULL) { + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* XXX should to be check weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* XXX should to be check weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: + mhp[ext->sadb_ext_type] = (caddr_t)ext; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + p += PFKEY_EXTLEN(ext); + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * check basic usage for sadb_msg, + * NOTE: This routine is derived from netkey/key.c in KAME. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * + * caddr_t mhp[SADB_EXT_MAX + 1]; + * + * OUT: -1: invalid. + * 0: valid. + */ +int +pfkey_check(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + + /* validity check */ + if (mhp == NULL || mhp[0] == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + msg = (struct sadb_msg *)mhp[0]; + + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + __ipsec_errcode = EIPSEC_INVAL_VERSION; + return -1; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; + return -1; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_ESP: + case SADB_SATYPE_AH: + case SADB_X_SATYPE_IPCOMP: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return -1; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + if (src0->sadb_address_proto != dst0->sadb_address_proto) { + __ipsec_errcode = EIPSEC_PROTO_MISMATCH; + return -1; + } + + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* + * prefixlen == 0 is valid because there must be the case + * all addresses are matched. + */ + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) + caddr_t buf; + caddr_t lim; + u_int type, satype; + u_int tlen; + u_int32_t seq; + pid_t pid; +{ + struct sadb_msg *p; + u_int len; + + p = (struct sadb_msg *)buf; + len = sizeof(struct sadb_msg); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_reserved = 0; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + + return(buf + len); +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) + caddr_t buf; + caddr_t lim; + u_int32_t spi, flags; + u_int wsize, auth, enc; +{ + struct sadb_sa *p; + u_int len; + + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = spi; + p->sadb_sa_replay = wsize; + p->sadb_sa_state = SADB_SASTATE_LARVAL; + p->sadb_sa_auth = auth; + p->sadb_sa_encrypt = enc; + p->sadb_sa_flags = flags; + + return(buf + len); +} + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + * prefixlen is in bits. + */ +static caddr_t +pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + caddr_t lim; + u_int exttype; + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + struct sadb_address *p; + u_int len; + + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype & 0xffff; + p->sadb_address_proto = ul_proto & 0xff; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + memcpy(p + 1, saddr, saddr->sa_len); + + return(buf + len); +} + +/* + * set sadb_key structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadbkey(buf, lim, type, key, keylen) + caddr_t buf; + caddr_t lim; + caddr_t key; + u_int type, keylen; +{ + struct sadb_key *p; + u_int len; + + p = (struct sadb_key *)buf; + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_key_len = PFKEY_UNIT64(len); + p->sadb_key_exttype = type; + p->sadb_key_bits = keylen << 3; + p->sadb_key_reserved = 0; + + memcpy(p + 1, key, keylen); + + return buf + len; +} + +/* + * set sadb_lifetime structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) + caddr_t buf; + caddr_t lim; + u_int type; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; +{ + struct sadb_lifetime *p; + u_int len; + + p = (struct sadb_lifetime *)buf; + len = sizeof(struct sadb_lifetime); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_lifetime_len = PFKEY_UNIT64(len); + p->sadb_lifetime_exttype = type; + + switch (type) { + case SADB_EXT_LIFETIME_SOFT: + p->sadb_lifetime_allocations + = (l_alloc * soft_lifetime_allocations_rate) /100; + p->sadb_lifetime_bytes + = (l_bytes * soft_lifetime_bytes_rate) /100; + p->sadb_lifetime_addtime + = (l_addtime * soft_lifetime_addtime_rate) /100; + p->sadb_lifetime_usetime + = (l_usetime * soft_lifetime_usetime_rate) /100; + break; + case SADB_EXT_LIFETIME_HARD: + p->sadb_lifetime_allocations = l_alloc; + p->sadb_lifetime_bytes = l_bytes; + p->sadb_lifetime_addtime = l_addtime; + p->sadb_lifetime_usetime = l_usetime; + break; + } + + return buf + len; +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbxsa2(buf, lim, mode0, reqid) + caddr_t buf; + caddr_t lim; + u_int32_t mode0; + u_int32_t reqid; +{ + struct sadb_x_sa2 *p; + u_int8_t mode = mode0 & 0xff; + u_int len; + + p = (struct sadb_x_sa2 *)buf; + len = sizeof(struct sadb_x_sa2); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_sa2_len = PFKEY_UNIT64(len); + p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + p->sadb_x_sa2_mode = mode; + p->sadb_x_sa2_reqid = reqid; + + return(buf + len); +} diff --git a/racoonctl.tproj/pfkey_dump.c b/racoonctl.tproj/pfkey_dump.c new file mode 100644 index 0000000..485ed46 --- /dev/null +++ b/racoonctl.tproj/pfkey_dump.c @@ -0,0 +1,596 @@ +/* $FreeBSD: src/lib/libipsec/pfkey_dump.c,v 1.1.2.2 2001/07/03 11:01:15 ume Exp $ */ +/* $KAME: pfkey_dump.c,v 1.27 2001/03/12 09:03:38 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +/* cope with old kame headers - ugly */ +#ifndef SADB_X_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#endif +#ifndef SADB_X_AALG_SHA +#define SADB_X_AALG_SHA SADB_AALG_SHA +#endif +#ifndef SADB_X_AALG_NULL +#define SADB_X_AALG_NULL SADB_AALG_NULL +#endif + +#ifndef SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC +#endif +#ifndef SADB_X_EALG_CAST128CBC +#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC +#endif +#ifndef SADB_X_EALG_RC5CBC +#ifdef SADB_EALG_RC5CBC +#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC +#endif +#endif + +#define GETMSGSTR(str, num) \ +do { \ + if (sizeof((str)[0]) == 0 \ + || num >= sizeof(str)/sizeof((str)[0])) \ + printf("%d ", (num)); \ + else if (strlen((str)[(num)]) == 0) \ + printf("%d ", (num)); \ + else \ + printf("%s ", (str)[(num)]); \ +} while (0) + +#define GETMSGV2S(v2s, num) \ +do { \ + struct val2str *p; \ + for (p = (v2s); p && p->str; p++) { \ + if (p->val == (num)) \ + break; \ + } \ + if (p && p->str) \ + printf("%s ", p->str); \ + else \ + printf("%d ", (num)); \ +} while (0) + +static char *str_ipaddr __P((struct sockaddr *)); +static char *str_prefport __P((u_int, u_int, u_int)); +static char *str_time __P((time_t)); +static void str_lifetime_byte __P((struct sadb_lifetime *, char *)); + +struct val2str { + int val; + const char *str; +}; + +/* + * Must to be re-written about following strings. + */ +static char *str_satype[] = { + "unspec", + "unknown", + "ah", + "esp", + "unknown", + "rsvp", + "ospfv2", + "ripv2", + "mip", + "ipcomp", +}; + +static char *str_mode[] = { + "any", + "transport", + "tunnel", +}; + +static char *str_upper[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + "", "tcp", "", "egp", "", +/*10*/ "", "", "", "", "", + "", "", "udp", "", "", +/*20*/ "", "", "idp", "", "", + "", "", "", "", "tp", +/*30*/ "", "", "", "", "", + "", "", "", "", "", +/*40*/ "", "ip6", "", "rt6", "frag6", + "", "rsvp", "gre", "", "", +/*50*/ "esp", "ah", "", "", "", + "", "", "", "icmp6", "none", +/*60*/ "dst6", +}; + +static char *str_state[] = { + "larval", + "mature", + "dying", + "dead", +}; + +static struct val2str str_alg_auth[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_enc[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, +#ifdef SADB_X_EALG_RC5CBC + { SADB_X_EALG_RC5CBC, "rc5-cbc", }, +#endif + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_RIJNDAELCBC + { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, +#endif +#ifdef SADB_X_EALG_TWOFISHCBC + { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_comp[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL, }, +}; + +/* + * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). + */ +void +pfkey_sadump(m) + struct sadb_msg *m; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_sa *m_sa; + struct sadb_x_sa2 *m_sa2; + struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; + struct sadb_address *m_saddr, *m_daddr, *m_paddr; + struct sadb_key *m_auth, *m_enc; + struct sadb_ident *m_sid, *m_did; + struct sadb_sens *m_sens; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2]; + m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; + m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + m_paddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_PROXY]; + m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; + m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; + m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; + m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; + m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY]; + + /* source address */ + if (m_saddr == NULL) { + printf("no ADDRESS_SRC extension.\n"); + return; + } + printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1))); + + /* destination address */ + if (m_daddr == NULL) { + printf("no ADDRESS_DST extension.\n"); + return; + } + printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1))); + + /* SA type */ + if (m_sa == NULL) { + printf("no SA extension.\n"); + return; + } + if (m_sa2 == NULL) { + printf("no SA2 extension.\n"); + return; + } + printf("\n\t"); + + GETMSGSTR(str_satype, m->sadb_msg_satype); + + printf("mode="); + GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); + + printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)m_sa2->sadb_x_sa2_reqid, + (u_int32_t)m_sa2->sadb_x_sa2_reqid); + + /* encryption key */ + if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { + printf("\tC: "); + GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt); + } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) { + if (m_enc != NULL) { + printf("\tE: "); + GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt); + ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc), + m_enc->sadb_key_bits / 8); + printf("\n"); + } + } + + /* authentication key */ + if (m_auth != NULL) { + printf("\tA: "); + GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth); + ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth), + m_auth->sadb_key_bits / 8); + printf("\n"); + } + + /* replay windoe size & flags */ + printf("\treplay=%u flags=0x%08x ", + m_sa->sadb_sa_replay, + m_sa->sadb_sa_flags); + + /* state */ + printf("state="); + GETMSGSTR(str_state, m_sa->sadb_sa_state); + + printf("seq=%lu pid=%lu\n", + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* lifetime */ + if (m_lftc != NULL) { + time_t tmp_time = time(0); + + printf("\tcreated: %s", + str_time(m_lftc->sadb_lifetime_addtime)); + printf("\tcurrent: %s\n", str_time(tmp_time)); + printf("\tdiff: %lu(s)", + (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? + 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); + + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_addtime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_addtime)); + + printf("\tlast: %s", + str_time(m_lftc->sadb_lifetime_usetime)); + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_usetime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_usetime)); + + str_lifetime_byte(m_lftc, "current"); + str_lifetime_byte(m_lfth, "hard"); + str_lifetime_byte(m_lfts, "soft"); + printf("\n"); + + printf("\tallocated: %lu", + (unsigned long)m_lftc->sadb_lifetime_allocations); + printf("\thard: %lu", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_allocations)); + printf("\tsoft: %lu\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_allocations)); + } + + /* XXX DEBUG */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +void +pfkey_spdump(m) + struct sadb_msg *m; +{ + char pbuf[NI_MAXSERV]; + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_address *m_saddr, *m_daddr; + struct sadb_x_policy *m_xpl; + struct sadb_lifetime *m_lft = NULL; + struct sockaddr *sa; + u_int16_t port; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + m_lft = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + + /* source address */ + if (m_saddr == NULL) { + printf("no ADDRESS_SRC extension.\n"); + return; + } + sa = (struct sockaddr *)(m_saddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_saddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } + + /* destination address */ + if (m_daddr == NULL) { + printf("no ADDRESS_DST extension.\n"); + return; + } + sa = (struct sockaddr *)(m_daddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_daddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } + + /* upper layer protocol */ + if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { + printf("upper layer protocol mismatched.\n"); + return; + } + if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY) + printf("any"); + else + GETMSGSTR(str_upper, m_saddr->sadb_address_proto); + + /* policy */ + { + char *d_xpl; + + if (m_xpl == NULL) { + printf("no X_POLICY extension.\n"); + return; + } + d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t"); + + /* dump SPD */ + printf("\n\t%s\n", d_xpl); + free(d_xpl); + } + + /* lifetime */ + if (m_lft) { + printf("\tlifetime:%lu validtime:%lu\n", + (u_long)m_lft->sadb_lifetime_addtime, + (u_long)m_lft->sadb_lifetime_usetime); + } + + printf("\tspid=%ld seq=%ld pid=%ld\n", + (u_long)m_xpl->sadb_x_policy_id, + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* XXX TEST */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +/* + * set "ipaddress" to buffer. + */ +static char * +str_ipaddr(sa) + struct sockaddr *sa; +{ + static char buf[NI_MAXHOST]; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif + + if (sa == NULL) + return ""; + + if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, niflag) == 0) + return buf; + return NULL; +} + +/* + * set "/prefix[port number]" to buffer. + */ +static char * +str_prefport(family, pref, port) + u_int family, pref, port; +{ + static char buf[128]; + char prefbuf[10]; + char portbuf[10]; + int plen; + + switch (family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + return "?"; + } + + if (pref == plen) + prefbuf[0] = '\0'; + else + snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); + + if (port == IPSEC_PORT_ANY) + snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); + else + snprintf(portbuf, sizeof(portbuf), "[%u]", port); + + snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); + + return buf; +} + +/* + * set "Mon Day Time Year" to buffer + */ +static char * +str_time(t) + time_t t; +{ + static char buf[128]; + + if (t == 0) { + int i = 0; + for (;i < 20;) buf[i++] = ' '; + } else { + char *t0; + t0 = ctime(&t); + memcpy(buf, t0 + 4, 20); + } + + buf[20] = '\0'; + + return(buf); +} + +static void +str_lifetime_byte(x, str) + struct sadb_lifetime *x; + char *str; +{ + double y; + char *unit; + int w; + + if (x == NULL) { + printf("\t%s: 0(bytes)", str); + return; + } + +#if 0 + if ((x->sadb_lifetime_bytes) / 1024 / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024; + unit = "M"; + w = 1; + } else if ((x->sadb_lifetime_bytes) / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024; + unit = "K"; + w = 1; + } else { + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; + } +#else + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; +#endif + printf("\t%s: %.*f(%sbytes)", str, w, y, unit); +} diff --git a/racoonctl.tproj/str2val.c b/racoonctl.tproj/str2val.c new file mode 100644 index 0000000..72aee51 --- /dev/null +++ b/racoonctl.tproj/str2val.c @@ -0,0 +1,122 @@ +/* $KAME: str2val.c,v 1.10 2001/04/03 15:51:57 thorpej 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. 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. + */ + +#include +#include +#include + +#include +#include + +#include "str2val.h" +#include "gcmalloc.h" + +/* + * exchange a value to a hex string. + * must free buffer allocated later. + */ +caddr_t +val2str(buf, mlen) + const char *buf; + size_t mlen; +{ + caddr_t new; + size_t len = (mlen * 2) + mlen / 8 + 10; + size_t i, j; + + if ((new = racoon_malloc(len)) == 0) return(0); + + for (i = 0, j = 0; i < mlen; i++) { + snprintf(&new[j], len - j, "%02x", (u_char)buf[i]); + j += 2; + if (i % 8 == 7) { + new[j++] = ' '; + new[j] = '\0'; + } + } + new[j] = '\0'; + + return(new); +} + +/* + * exchange a string based "base" to a value. + */ +char * +str2val(str, base, len) + const char *str; + int base; + size_t *len; +{ + int f; + size_t i; + char *dst; + char *rp; + const char *p; + char b[3]; + + i = 0; + for (p = str; *p != '\0'; p++) { + if (isxdigit(*p)) + i++; + else if (isspace(*p)) + ; + else + return NULL; + } + if (i == 0 || (i % 2) != 0) + return NULL; + i /= 2; + + if ((dst = racoon_malloc(i)) == NULL) + return NULL; + + i = 0; + f = 0; + for (rp = dst, p = str; *p != '\0'; p++) { + if (isxdigit(*p)) { + if (!f) { + b[0] = *p; + f = 1; + } else { + b[1] = *p; + b[2] = '\0'; + *rp++ = (char)strtol(b, NULL, base); + i++; + f = 0; + } + } + } + + *len = i; + + return(dst); +} diff --git a/racoonctl.tproj/str2val.h b/racoonctl.tproj/str2val.h new file mode 100644 index 0000000..15f5245 --- /dev/null +++ b/racoonctl.tproj/str2val.h @@ -0,0 +1,33 @@ +/* $KAME: str2val.h,v 1.5 2000/10/04 17:41:04 itojun 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. 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. + */ + +extern caddr_t val2str __P((const char *, size_t)); +extern char *str2val __P((const char *, int, size_t *)); diff --git a/racoonctl.tproj/vmbuf.c b/racoonctl.tproj/vmbuf.c new file mode 100644 index 0000000..cdb4110 --- /dev/null +++ b/racoonctl.tproj/vmbuf.c @@ -0,0 +1,115 @@ +/* $KAME: vmbuf.c,v 1.10 2001/04/03 15:51:57 thorpej 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. 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. + */ + +#define NONEED_DRM +#include +#include + +#include +#include +#include + +#include "var.h" +#include "misc.h" +#include "vmbuf.h" +#include "debug.h" +#include "gcmalloc.h" + +vchar_t * +vmalloc(size) + size_t size; +{ + vchar_t *var; + + if ((var = (vchar_t *)racoon_malloc(sizeof(*var))) == NULL) + return NULL; + + var->l = size; + var->v = (caddr_t)racoon_calloc(1, size); + if (var->v == NULL) { + (void)racoon_free(var); + return NULL; + } + + return var; +} + +vchar_t * +vrealloc(ptr, size) + vchar_t *ptr; + size_t size; +{ + caddr_t v; + + if (ptr != NULL) { + if ((v = (caddr_t)racoon_realloc(ptr->v, size)) == NULL) { + (void)vfree(ptr); + return NULL; + } + memset(v + ptr->l, 0, size - ptr->l); + ptr->v = v; + ptr->l = size; + } else { + if ((ptr = vmalloc(size)) == NULL) + return NULL; + } + + return ptr; +} + +void +vfree(var) + vchar_t *var; +{ + if (var == NULL) + return; + + if (var->v) + (void)racoon_free(var->v); + + (void)racoon_free(var); + + return; +} + +vchar_t * +vdup(src) + vchar_t *src; +{ + vchar_t *new; + + if ((new = vmalloc(src->l)) == NULL) + return NULL; + + memcpy(new->v, src->v, src->l); + + return new; +} diff --git a/racoonctl.tproj/vmbuf.h b/racoonctl.tproj/vmbuf.h new file mode 100644 index 0000000..bec394b --- /dev/null +++ b/racoonctl.tproj/vmbuf.h @@ -0,0 +1,63 @@ +/* $KAME: vmbuf.h,v 1.7 2000/10/04 17:41:05 itojun 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. 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. + */ + +/* + * bp v + * v v + * ........................ + * <--------------> l + * <----------------------> bl + */ +typedef struct _vchar_t_ { +#if notyet + u_int32_t t; /* type of the value */ + vchar_t *n; /* next vchar_t buffer */ + size_t bl; /* length of the buffer */ + caddr_t bp; /* pointer to the buffer */ +#endif + size_t l; /* length of the value */ + caddr_t v; /* place holder to the pointer to the value */ +} vchar_t; + +#define VPTRINIT(p) \ +do { \ + if (p) { \ + vfree(p); \ + (p) = NULL; \ + } \ +} while(0); + +#define vfree vmbuf_free + +extern vchar_t *vmalloc __P((size_t)); +extern vchar_t *vrealloc __P((vchar_t *, size_t)); +extern void vfree __P((vchar_t *)); +extern vchar_t *vdup __P((vchar_t *)); diff --git a/rbootd.tproj/Makefile.postamble b/rbootd.tproj/Makefile.postamble deleted file mode 100644 index 7ede358..0000000 --- a/rbootd.tproj/Makefile.postamble +++ /dev/null @@ -1,111 +0,0 @@ -############################################################################### -# NeXT Makefile.postamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. Additional -# rules (e.g., after_install) that are defined by the developer should be -# defined in this file. -# -############################################################################### -# -# Here are the variables exported by the common "app" makefiles that can be -# used in any customizations you make to the template below: -# -# PRODUCT_ROOT - Name of the directory to which resources are copied. -# OFILE_DIR - Directory into which .o object files are generated. -# (Note that this name is calculated based on the target -# architectures specified in Project Builder). -# DERIVED_SRC_DIR - Directory used for all other derived files -# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations -# -# NAME - name of application, bundle, subproject, palette, etc. -# LANGUAGE - langage in which the project is written (default "English") -# ENGLISH - boolean flag set iff $(LANGUAGE) = "English" -# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese" -# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project -# GLOBAL_RESOURCES - non-localized resources of project -# PROJECTVERSION - version of ProjectBuilder that output Makefile -# APPICON - application icon file -# DOCICONS - dock icon files -# ICONSECTIONS - Specifies icon sections when linking executable -# -# CLASSES - Class implementation files in project. -# HFILES - Header files in project. -# MFILES - Other Objective-C source files in project. -# CFILES - Other C source files in project. -# PSWFILES - .psw files in the project -# PSWMFILES - .pswm files in the project -# SUBPROJECTS - Subprojects of this project -# BUNDLES - Bundle subprojects of this project -# OTHERSRCS - Other miscellaneous sources of this project -# OTHERLINKED - Source files not matching a standard source extention -# -# LIBS - Libraries to link with when making app target -# DEBUG_LIBS - Libraries to link with when making debug target -# PROF_LIBS - Libraries to link with when making profile target -# OTHERLINKEDOFILES - Other relocatable files to (always) link in. -# -# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles -# MAKEFILEDIR - Directory in which to find $(MAKEFILE) -# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make) -# INSTALLDIR - Directory app will be installed into by 'install' target -# -############################################################################### - - -# Change defaults assumed by the standard makefiles here. Edit the -# following default values as appropriate. (Note that if no Makefile.postamble -# exists, these values will have defaults set in common.make). - -# Versioning of frameworks, libraries, bundles, and palettes: -#CURRENTLY_ACTIVE_VERSION = YES # Set to "NO" to produce a compatibility binary -#DEPLOY_WITH_VERSION_NAME = A -#COMPATIBILITY_PROJECT_VERSION = 1 - -# Some compiler flags can be easily overridden here, but onlytake effect at -# the top-level: -#OPTIMIZATION_CFLAG = -O -#DEBUG_SYMBOLS_CFLAG = -g -#WARNING_CFLAGS = -Wall -#DEBUG_BUILD_CFLAGS = -DDEBUG -#PROFILE_BUILD_CFLAGS = -pg -DPROFILE - -# Flags passed to yacc -#YFLAGS = -d - -# Library and Framework projects only: -# 1. If you want something other than the default .dylib name, override it here -#DYLIB_INSTALL_NAME = lib$(NAME).dylib - -# 2. If you want to change the -install_name flag from the absolute path to the development area, change it here. One good choice is the installation directory. Another one might be none at all. -#DYLIB_INSTALL_DIR = $(INSTALLDIR) - -# Ownership and permissions of files installed by 'install' target -#INSTALL_AS_USER = root # User/group ownership -#INSTALL_AS_GROUP = wheel # (probably want to set both of these) -#INSTALL_PERMISSIONS = # If set, 'install' chmod's executable to this - -# Options to strip for various project types. Note: -S strips debugging symbols -# (executables can be stripped down further with -x or, if they load no bundles, with no -# options at all). -#APP_STRIP_OPTS = -S -#TOOL_STRIP_OPTS = -S -#LIBRARY_STRIP_OPTS = -S # for .a archives -#DYNAMIC_STRIP_OPTS = -S # for bundles and shared libraries -STRIPFLAGS = - -######################################################################### -# Put rules to extend the behavior of the standard Makefiles here. "Official" -# user-defined rules are: -# * before_install -# * after_install -# * after_installhdrs -# You should avoid redefining things like "install" or "app", as they are -# owned by the top-level Makefile API and no context has been set up for where -# derived files should go. - diff --git a/rbootd.tproj/Makefile.preamble b/rbootd.tproj/Makefile.preamble deleted file mode 100644 index dcbd1c8..0000000 --- a/rbootd.tproj/Makefile.preamble +++ /dev/null @@ -1,119 +0,0 @@ -############################################################################### -# NeXT Makefile.preamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project. Each node in a project -# tree of sub-projects, tools, etc. should have its own Makefile.preamble and -# Makefile.postamble. -# -############################################################################### -## Configure the flags passed to $(CC) here. These flags will also be -## inherited by all nested sub-projects and bundles. Put your -I, -D, -U, and -## -L flags in ProjectBuilder's Build Options inspector if at all possible. -## To change the default flags that get passed to ${CC} -## (e.g. change -O to -O2), see Makefile.postamble. - -# Flags passed to compiler (in addition to -g, -O, etc) -OTHER_CFLAGS = -# Flags passed to ld (in addition to -ObjC, etc.) -OTHER_LDFLAGS = -# Flags passed to libtool when building libraries -OTHER_LIBTOOL_FLAGS = -# For ordering named sections on NEXTSTEP (see ld(1)) -SECTORDER_FLAGS = - -# Stuff related to exporting headers from this project that isn't already -# handled by PB. -OTHER_PUBLIC_HEADERS = -OTHER_PROJECT_HEADERS = -OTHER_PRIVATE_HEADERS = - -# Set all three of these if you want a precomp to be built as part of -# installation. The cc -precomp will be run in the specified dir on the -# specified public header files with the specified additional flags. Don't put -# $(DSTROOT) in PUBLIC_HEADER_DIR; this is done for you. -PUBLIC_HEADER_DIR = -PUBLIC_PRECOMPILED_HEADERS = -PUBLIC_PRECOMPILED_HEADERS_CFLAGS = - -PRIVATE_HEADER_DIR = - -# If, in a subproject, you want to append to the parent's PUBLIC_HEADER_DIR# -# (say, to add a subdirectory like "/sys"), you can use: -PUBLIC_HEADER_DIR_SUFFIX = -PRIVATE_HEADER_DIR_SUFFIX = - -# Additional (non-localized) resources for this project, which can be generated -OTHER_RESOURCES = - -# Set this to YES if you don't want a final libtool call for a library/framework. -BUILD_OFILES_LIST_ONLY = - -# Additional relocatables to be linked into this project -OTHER_OFILES = -# Additional libraries to link against -OTHER_LIBS = -# To include a version string, project source must exist in a directory named -# $(NAME).%d[.%d][.%d] and the following line must be uncommented. -OTHER_GENERATED_OFILES = $(VERS_OFILE) - -## Configure how things get built here. Additional dependencies, source files, -## derived files, and build order should be specified here. - -# Other dependencies of this project -OTHER_PRODUCT_DEPENDS = -# Built *before* building subprojects/bundles -OTHER_INITIAL_TARGETS = -# Other source files maintained by .pre/postamble -OTHER_SOURCEFILES = -# Additional files to be removed by `make clean' -OTHER_GARBAGE = - -# Targets to build before installation -OTHER_INSTALL_DEPENDS = - -# A virtual root directory (other than /) to be prepended to the $(INSTALLDIR) -# passed from ProjectBuilder. -DSTROOT = - -# More obscure flags you might want to set for pswrap, yacc, lex, etc. -PSWFLAGS = -YFLAGS = -LFLAGS = - -## Delete this line if you want fast and loose cleans that will not remove -## things like precomps and user-defined OTHER_GARBAGE in subprojects. -CLEAN_ALL_SUBPROJECTS = YES - -## Add more obscure source files here to cause them to be automatically -## processed by the appropriate tool. Note that these files should also be -## added to "Supporting Files" in ProjectBuilder. The desired .o files that -## result from these files should also be added to OTHER_OFILES above so they -## will be linked in. - -# .msg files that should have msgwrap run on them -MSGFILES = -# .defs files that should have mig run on them -DEFSFILES = -# .mig files (no .defs files) that should have mig run on them -MIGFILES = - -## Add additional Help directories here (add them to the project as "Other -## Resources" in Project Builder) so that they will be compressed into .store -## files and copied into the app wrapper. If the help directories themselves -## need to also be in the app wrapper, then a cp command will need to be added -## in an after_install target. -OTHER_HELP_DIRS = - -# After you have saved your project using the 4.0 PB, you will automatically -# start using the makefiles in $(SYSTEM_DEVELOPER_DIR)/Makefiles/project. If you should -# need to revert back to the old 3.3 Makefile behavior, override MAKEFILEDIR to -# be $(SYSTEM_DEVELOPER_DIR)/Makefiles/app. - -# Don't add more rules here unless you want the first one to be the default -# target for make! Put all your targets in Makefile.postamble. - --include ../Makefile.include diff --git a/rbootd.tproj/PB.project b/rbootd.tproj/PB.project deleted file mode 100644 index 4423a10..0000000 --- a/rbootd.tproj/PB.project +++ /dev/null @@ -1,39 +0,0 @@ -{ - FILESTABLE = { - C_FILES = (); - H_FILES = (defs.h, pathnames.h, rmp.h, rmp_var.h); - M_FILES = (); - OTHER_LIBS = (); - OTHER_LINKED = (bpf.c, conf.c, parseconf.c, rbootd.c, rmpproto.c, utils.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, rbootd.8); - SUBPROJECTS = (); - }; - GENERATEMAIN = YES; - LANGUAGE = English; - LOCALIZABLE_FILES = {}; - NEXTSTEP_BUILDDIR = ""; - NEXTSTEP_BUILDTOOL = /bin/make; - NEXTSTEP_COMPILEROPTIONS = ""; - NEXTSTEP_DOCUMENTEXTENSIONS = (); - NEXTSTEP_INSTALLDIR = /usr/libexec; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_LINKEROPTIONS = ""; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; - PDO_UNIX_INSTALLDIR = /usr/libexec; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; - PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = rbootd; - PROJECTTYPE = Tool; - PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; - WINDOWS_INSTALLDIR = /usr/libexec; - WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; - WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; -} diff --git a/rbootd.tproj/bpf.c b/rbootd.tproj/bpf.c deleted file mode 100644 index ed21480..0000000 --- a/rbootd.tproj/bpf.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)bpf.c 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: bpf.c 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#ifndef lint -static char sccsid[] = "@(#)bpf.c 8.1 (Berkeley) 6/4/93"; -#endif /* not lint */ - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "defs.h" -#include "pathnames.h" - -static int BpfFd = -1; -static unsigned BpfLen = 0; -static u_char *BpfPkt = NULL; - -/* -** BpfOpen -- Open and initialize a BPF device. -** -** Parameters: -** None. -** -** Returns: -** File descriptor of opened BPF device (for select() etc). -** -** Side Effects: -** If an error is encountered, the program terminates here. -*/ -int -BpfOpen() -{ - struct ifreq ifr; - char bpfdev[32]; - int n = 0; - - /* - * Open the first available BPF device. - */ - do { - (void) sprintf(bpfdev, _PATH_BPF, n++); - BpfFd = open(bpfdev, O_RDWR); - } while (BpfFd < 0 && (errno == EBUSY || errno == EPERM)); - - if (BpfFd < 0) { - syslog(LOG_ERR, "bpf: no available devices: %m"); - Exit(0); - } - - /* - * Set interface name for bpf device, get data link layer - * type and make sure it's type Ethernet. - */ - (void) strncpy(ifr.ifr_name, IntfName, sizeof(ifr.ifr_name)); - if (ioctl(BpfFd, BIOCSETIF, (caddr_t)&ifr) < 0) { - syslog(LOG_ERR, "bpf: ioctl(BIOCSETIF,%s): %m", IntfName); - Exit(0); - } - - /* - * Make sure we are dealing with an Ethernet device. - */ - if (ioctl(BpfFd, BIOCGDLT, (caddr_t)&n) < 0) { - syslog(LOG_ERR, "bpf: ioctl(BIOCGDLT): %m"); - Exit(0); - } - if (n != DLT_EN10MB) { - syslog(LOG_ERR,"bpf: %s: data-link type %d unsupported", - IntfName, n); - Exit(0); - } - - /* - * On read(), return packets immediately (do not buffer them). - */ - n = 1; - if (ioctl(BpfFd, BIOCIMMEDIATE, (caddr_t)&n) < 0) { - syslog(LOG_ERR, "bpf: ioctl(BIOCIMMEDIATE): %m"); - Exit(0); - } - - /* - * Try to enable the chip/driver's multicast address filter to - * grab our RMP address. If this fails, try promiscuous mode. - * If this fails, there's no way we are going to get any RMP - * packets so just exit here. - */ -#ifdef MSG_EOR - ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; -#endif - ifr.ifr_addr.sa_family = AF_UNSPEC; - bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); - if (ioctl(BpfFd, SIOCADDMULTI, (caddr_t)&ifr) < 0) { - syslog(LOG_WARNING, - "bpf: can't add mcast addr (%m), setting promiscuous mode"); - - if (ioctl(BpfFd, BIOCPROMISC, (caddr_t)0) < 0) { - syslog(LOG_ERR, "bpf: can't set promiscuous mode: %m"); - Exit(0); - } - } - - /* - * Ask BPF how much buffer space it requires and allocate one. - */ - if (ioctl(BpfFd, BIOCGBLEN, (caddr_t)&BpfLen) < 0) { - syslog(LOG_ERR, "bpf: ioctl(BIOCGBLEN): %m"); - Exit(0); - } - if (BpfPkt == NULL) - BpfPkt = (u_char *)malloc(BpfLen); - - if (BpfPkt == NULL) { - syslog(LOG_ERR, "bpf: out of memory (%u bytes for bpfpkt)", - BpfLen); - Exit(0); - } - - /* - * Write a little program to snarf RMP Boot packets and stuff - * it down BPF's throat (i.e. set up the packet filter). - */ - { -#define RMP ((struct rmp_packet *)0) - static struct bpf_insn bpf_insn[] = { - { BPF_LD|BPF_B|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dsap }, - { BPF_JMP|BPF_JEQ|BPF_K, 0, 5, IEEE_DSAP_HP }, - { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.cntrl }, - { BPF_JMP|BPF_JEQ|BPF_K, 0, 3, IEEE_CNTL_HP }, - { BPF_LD|BPF_H|BPF_ABS, 0, 0, (long)&RMP->hp_llc.dxsap }, - { BPF_JMP|BPF_JEQ|BPF_K, 0, 1, HPEXT_DXSAP }, - { BPF_RET|BPF_K, 0, 0, RMP_MAX_PACKET }, - { BPF_RET|BPF_K, 0, 0, 0x0 } - }; -#undef RMP - static struct bpf_program bpf_pgm = { - sizeof(bpf_insn)/sizeof(bpf_insn[0]), bpf_insn - }; - - if (ioctl(BpfFd, BIOCSETF, (caddr_t)&bpf_pgm) < 0) { - syslog(LOG_ERR, "bpf: ioctl(BIOCSETF): %m"); - Exit(0); - } - } - - return(BpfFd); -} - -/* -** BPF GetIntfName -- Return the name of a network interface attached to -** the system, or 0 if none can be found. The interface -** must be configured up; the lowest unit number is -** preferred; loopback is ignored. -** -** Parameters: -** errmsg - if no network interface found, *errmsg explains why. -** -** Returns: -** A (static) pointer to interface name, or NULL on error. -** -** Side Effects: -** None. -*/ -char * -BpfGetIntfName(errmsg) - char **errmsg; -{ - struct ifreq ibuf[8], *ifrp, *ifend, *mp; - struct ifconf ifc; - int fd; - int minunit, n; - char *cp; - static char device[sizeof(ifrp->ifr_name)]; - static char errbuf[128] = "No Error!"; - - if (errmsg != NULL) - *errmsg = errbuf; - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - (void) strcpy(errbuf, "bpf: socket: %m"); - return(NULL); - } - ifc.ifc_len = sizeof ibuf; - ifc.ifc_buf = (caddr_t)ibuf; - -#ifdef OSIOCGIFCONF - if (ioctl(fd, OSIOCGIFCONF, (char *)&ifc) < 0 || - ifc.ifc_len < sizeof(struct ifreq)) { - (void) strcpy(errbuf, "bpf: ioctl(OSIOCGIFCONF): %m"); - return(NULL); - } -#else - if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 || - ifc.ifc_len < sizeof(struct ifreq)) { - (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFCONF): %m"); - return(NULL); - } -#endif - ifrp = ibuf; - ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); - - mp = 0; - minunit = 666; - for (; ifrp < ifend; ++ifrp) { - if (ioctl(fd, SIOCGIFFLAGS, (char *)ifrp) < 0) { - (void) strcpy(errbuf, "bpf: ioctl(SIOCGIFFLAGS): %m"); - return(NULL); - } - - /* - * If interface is down or this is the loopback interface, - * ignore it. - */ - if ((ifrp->ifr_flags & IFF_UP) == 0 || -#ifdef IFF_LOOPBACK - (ifrp->ifr_flags & IFF_LOOPBACK)) -#else - (strcmp(ifrp->ifr_name, "lo0") == 0)) -#endif - continue; - - for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp) - ; - n = atoi(cp); - if (n < minunit) { - minunit = n; - mp = ifrp; - } - } - - (void) close(fd); - if (mp == 0) { - (void) strcpy(errbuf, "bpf: no interfaces found"); - return(NULL); - } - - (void) strcpy(device, mp->ifr_name); - return(device); -} - -/* -** BpfRead -- Read packets from a BPF device and fill in `rconn'. -** -** Parameters: -** rconn - filled in with next packet. -** doread - is True if we can issue a read() syscall. -** -** Returns: -** True if `rconn' contains a new packet, False otherwise. -** -** Side Effects: -** None. -*/ -int -BpfRead(rconn, doread) - RMPCONN *rconn; - int doread; -{ - register int datlen, caplen, hdrlen; - static u_char *bp = NULL, *ep = NULL; - int cc; - - /* - * The read() may block, or it may return one or more packets. - * We let the caller decide whether or not we can issue a read(). - */ - if (doread) { - if ((cc = read(BpfFd, (char *)BpfPkt, (int)BpfLen)) < 0) { - syslog(LOG_ERR, "bpf: read: %m"); - return(0); - } else { - bp = BpfPkt; - ep = BpfPkt + cc; - } - } - -#define bhp ((struct bpf_hdr *)bp) - /* - * If there is a new packet in the buffer, stuff it into `rconn' - * and return a success indication. - */ - if (bp < ep) { - datlen = bhp->bh_datalen; - caplen = bhp->bh_caplen; - hdrlen = bhp->bh_hdrlen; - - if (caplen != datlen) - syslog(LOG_ERR, - "bpf: short packet dropped (%d of %d bytes)", - caplen, datlen); - else if (caplen > sizeof(struct rmp_packet)) - syslog(LOG_ERR, "bpf: large packet dropped (%d bytes)", - caplen); - else { - rconn->rmplen = caplen; - bcopy((char *)&bhp->bh_tstamp, (char *)&rconn->tstamp, - sizeof(struct timeval)); - bcopy((char *)bp + hdrlen, (char *)&rconn->rmp, caplen); - } - bp += BPF_WORDALIGN(caplen + hdrlen); - return(1); - } -#undef bhp - - return(0); -} - -/* -** BpfWrite -- Write packet to BPF device. -** -** Parameters: -** rconn - packet to send. -** -** Returns: -** True if write succeeded, False otherwise. -** -** Side Effects: -** None. -*/ -int -BpfWrite(rconn) - RMPCONN *rconn; -{ - if (write(BpfFd, (char *)&rconn->rmp, rconn->rmplen) < 0) { - syslog(LOG_ERR, "write: %s: %m", EnetStr(rconn)); - return(0); - } - - return(1); -} - -/* -** BpfClose -- Close a BPF device. -** -** Parameters: -** None. -** -** Returns: -** Nothing. -** -** Side Effects: -** None. -*/ -void -BpfClose() -{ - struct ifreq ifr; - - if (BpfPkt != NULL) { - free((char *)BpfPkt); - BpfPkt = NULL; - } - - if (BpfFd == -1) - return; - -#ifdef MSG_EOR - ifr.ifr_addr.sa_len = RMP_ADDRLEN + 2; -#endif - ifr.ifr_addr.sa_family = AF_UNSPEC; - bcopy(&RmpMcastAddr[0], (char *)&ifr.ifr_addr.sa_data[0], RMP_ADDRLEN); - if (ioctl(BpfFd, SIOCDELMULTI, (caddr_t)&ifr) < 0) - (void) ioctl(BpfFd, BIOCPROMISC, (caddr_t)0); - - (void) close(BpfFd); - BpfFd = -1; -} diff --git a/rbootd.tproj/conf.c b/rbootd.tproj/conf.c deleted file mode 100644 index e61a0f3..0000000 --- a/rbootd.tproj/conf.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)conf.c 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: conf.c 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#ifndef lint -static char sccsid[] = "@(#)conf.c 8.1 (Berkeley) 6/4/93"; -#endif /* not lint */ - -#include -#include - -#include -#include "defs.h" -#include "pathnames.h" - -/* -** Define (and possibly initialize) global variables here. -** -** Caveat: -** The maximum number of bootable files (`char *BootFiles[]') is -** limited to C_MAXFILE (i.e. the maximum number of files that -** can be spec'd in the configuration file). This was done to -** simplify the boot file search code. -*/ - -char *ProgName; /* path-stripped argv[0] */ -char MyHost[MAXHOSTNAMELEN+1]; /* host name */ -int MyPid; /* process id */ -int DebugFlg = 0; /* set true if debugging */ -int BootAny = 0; /* set true if we boot anyone */ - -char *ConfigFile = NULL; /* configuration file */ -char *DfltConfig = _PATH_RBOOTDCONF; /* default configuration file */ -char *PidFile = _PATH_RBOOTDPID; /* file w/pid of server */ -char *BootDir = _PATH_RBOOTDLIB; /* directory w/boot files */ -char *DbgFile = _PATH_RBOOTDDBG; /* debug output file */ - -FILE *DbgFp = NULL; /* debug file pointer */ -char *IntfName = NULL; /* intf we are attached to */ - -u_short SessionID = 0; /* generated session ID */ - -char *BootFiles[C_MAXFILE]; /* list of boot files */ - -CLIENT *Clients = NULL; /* list of addrs we'll accept */ -RMPCONN *RmpConns = NULL; /* list of active connections */ - -char RmpMcastAddr[RMP_ADDRLEN] = RMP_ADDR; /* RMP multicast address */ diff --git a/rbootd.tproj/defs.h b/rbootd.tproj/defs.h deleted file mode 100644 index 976ffc1..0000000 --- a/rbootd.tproj/defs.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)defs.h 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: defs.h 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#include "rmp.h" -#include "rmp_var.h" - -/* -** Common #define's and external variables. All other files should -** include this. -*/ - -/* - * This may be defined in , if not, it's defined here. - */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -/* - * SIGUSR1 and SIGUSR2 are defined in for 4.3BSD systems. - */ -#ifndef SIGUSR1 -#define SIGUSR1 SIGEMT -#endif -#ifndef SIGUSR2 -#define SIGUSR2 SIGFPE -#endif - -/* - * These can be faster & more efficient than strcmp()/strncmp()... - */ -#define STREQN(s1,s2) ((*s1 == *s2) && (strcmp(s1,s2) == 0)) -#define STRNEQN(s1,s2,n) ((*s1 == *s2) && (strncmp(s1,s2,n) == 0)) - -/* - * Configuration file limitations. - */ -#define C_MAXFILE 10 /* max number of boot-able files */ -#define C_LINELEN 1024 /* max length of line */ - -/* - * Direction of packet (used as argument to DispPkt). - */ -#define DIR_RCVD 0 -#define DIR_SENT 1 -#define DIR_NONE 2 - -/* - * These need not be functions, so... - */ -#define FreeStr(str) free(str) -#define FreeClient(cli) free(cli) -#define GenSessID() (++SessionID ? SessionID: ++SessionID) - -/* - * Converting an Ethernet address to a string is done in many routines. - * Using `rmp.hp_hdr.saddr' works because this field is *never* changed; - * it will *always* contain the source address of the packet. - */ -#define EnetStr(rptr) GetEtherAddr(&(rptr)->rmp.hp_hdr.saddr[0]) - -/* - * Every machine we can boot will have one of these allocated for it - * (unless there are no restrictions on who we can boot). - */ -typedef struct client_s { - u_char addr[RMP_ADDRLEN]; /* addr of machine */ - char *files[C_MAXFILE]; /* boot-able files */ - struct client_s *next; /* ptr to next */ -} CLIENT; - -/* - * Every active connection has one of these allocated for it. - */ -typedef struct rmpconn_s { - struct rmp_packet rmp; /* RMP packet */ - int rmplen; /* length of packet */ - struct timeval tstamp; /* last time active */ - int bootfd; /* open boot file */ - struct rmpconn_s *next; /* ptr to next */ -} RMPCONN; - -/* - * All these variables are defined in "conf.c". - */ -extern char *ProgName; /* path-stripped argv[0] */ -extern char MyHost[]; /* this hosts' name */ -extern int MyPid; /* this processes' ID */ -extern int DebugFlg; /* set true if debugging */ -extern int BootAny; /* set true if we can boot anyone */ - -extern char *ConfigFile; /* configuration file */ -extern char *DfltConfig; /* default configuration file */ -extern char *DbgFile; /* debug output file */ -extern char *PidFile; /* file containing pid of server */ -extern char *BootDir; /* directory w/boot files */ - -extern FILE *DbgFp; /* debug file pointer */ -extern char *IntfName; /* interface we are attached to */ - -extern u_short SessionID; /* generated session ID */ - -extern char *BootFiles[]; /* list of boot files */ - -extern CLIENT *Clients; /* list of addrs we'll accept */ -extern RMPCONN *RmpConns; /* list of active connections */ - -extern char RmpMcastAddr[]; /* RMP multicast address */ - -void AddConn __P((RMPCONN *)); -int BootDone __P((RMPCONN *)); -void BpfClose __P((void)); -char *BpfGetIntfName __P((char **)); -int BpfOpen __P((void)); -int BpfRead __P((RMPCONN *, int)); -int BpfWrite __P((RMPCONN *)); -void DebugOff __P((int)); -void DebugOn __P((int)); -void DispPkt __P((RMPCONN *, int)); -void DoTimeout __P((void)); -void DspFlnm __P((u_int, char *)); -void Exit __P((int)); -CLIENT *FindClient __P((RMPCONN *)); -RMPCONN *FindConn __P((RMPCONN *)); -void FreeClients __P((void)); -void FreeConn __P((RMPCONN *)); -void FreeConns __P((void)); -int GetBootFiles __P((void)); -char *GetEtherAddr __P((u_char *)); -CLIENT *NewClient __P((u_char *)); -RMPCONN *NewConn __P((RMPCONN *)); -char *NewStr __P((char *)); -u_char *ParseAddr __P((char *)); -int ParseConfig __P((void)); -void ProcessPacket __P((RMPCONN *, CLIENT *)); -void ReConfig __P((int)); -void RemoveConn __P((RMPCONN *)); -int SendBootRepl __P((struct rmp_packet *, RMPCONN *, char *[])); -int SendFileNo __P((struct rmp_packet *, RMPCONN *, char *[])); -int SendPacket __P((RMPCONN *)); -int SendReadRepl __P((RMPCONN *)); -int SendServerID __P((RMPCONN *)); diff --git a/rbootd.tproj/parseconf.c b/rbootd.tproj/parseconf.c deleted file mode 100644 index ddf2f19..0000000 --- a/rbootd.tproj/parseconf.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)parseconf.c 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: parseconf.c 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#ifndef lint -static char sccsid[] = "@(#)parseconf.c 8.1 (Berkeley) 6/4/93"; -#endif /* not lint */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "defs.h" - -/* -** ParseConfig -- parse the config file into linked list of clients. -** -** Parameters: -** None. -** -** Returns: -** 1 on success, 0 otherwise. -** -** Side Effects: -** - Linked list of clients will be (re)allocated. -** -** Warnings: -** - GetBootFiles() must be called before this routine -** to create a linked list of default boot files. -*/ -int -ParseConfig() -{ - FILE *fp; - CLIENT *client; - u_char *addr; - char line[C_LINELEN]; - register char *cp, *bcp; - register int i, j; - int omask, linecnt = 0; - - if (BootAny) /* ignore config file */ - return(1); - - FreeClients(); /* delete old list of clients */ - - if ((fp = fopen(ConfigFile, "r")) == NULL) { - syslog(LOG_ERR, "ParseConfig: can't open config file (%s)", - ConfigFile); - return(0); - } - - /* - * We've got to block SIGHUP to prevent reconfiguration while - * dealing with the linked list of Clients. This can be done - * when actually linking the new client into the list, but - * this could have unexpected results if the server was HUP'd - * whilst reconfiguring. Hence, it is done here. - */ - omask = sigblock(sigmask(SIGHUP)); - - /* - * GETSTR positions `bcp' at the start of the current token, - * and null terminates it. `cp' is positioned at the start - * of the next token. spaces & commas are separators. - */ -#define GETSTR while (isspace(*cp) || *cp == ',') cp++; \ - bcp = cp; \ - while (*cp && *cp!=',' && !isspace(*cp)) cp++; \ - if (*cp) *cp++ = '\0' - - /* - * For each line, parse it into a new CLIENT struct. - */ - while (fgets(line, C_LINELEN, fp) != NULL) { - linecnt++; /* line counter */ - - if (*line == '\0' || *line == '#') /* ignore comment */ - continue; - - if ((cp = index(line,'#')) != NULL) /* trash comments */ - *cp = '\0'; - - cp = line; /* init `cp' */ - GETSTR; /* get RMP addr */ - if (bcp == cp) /* all delimiters */ - continue; - - /* - * Get an RMP address from a string. Abort on failure. - */ - if ((addr = ParseAddr(bcp)) == NULL) { - syslog(LOG_ERR, - "ParseConfig: line %d: cant parse <%s>", - linecnt, bcp); - continue; - } - - if ((client = NewClient(addr)) == NULL) /* alloc new client */ - continue; - - GETSTR; /* get first file */ - - /* - * If no boot files are spec'd, use the default list. - * Otherwise, validate each file (`bcp') against the - * list of boot-able files. - */ - i = 0; - if (bcp == cp) /* no files spec'd */ - for (; i < C_MAXFILE && BootFiles[i] != NULL; i++) - client->files[i] = BootFiles[i]; - else { - do { - /* - * For each boot file spec'd, make sure it's - * in our list. If so, include a pointer to - * it in the CLIENT's list of boot files. - */ - for (j = 0; ; j++) { - if (j==C_MAXFILE||BootFiles[j]==NULL) { - syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)", - linecnt, bcp); - break; - } - if (STREQN(BootFiles[j], bcp)) { - if (i < C_MAXFILE) - client->files[i++] = - BootFiles[j]; - else - syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)", - linecnt, bcp); - break; - } - } - GETSTR; /* get next file */ - } while (bcp != cp); - - /* - * Restricted list of boot files were spec'd, - * however, none of them were found. Since we - * apparently cant let them boot "just anything", - * the entire record is invalidated. - */ - if (i == 0) { - FreeClient(client); - continue; - } - } - - /* - * Link this client into the linked list of clients. - * SIGHUP has already been blocked. - */ - if (Clients) - client->next = Clients; - Clients = client; - } - - (void) fclose(fp); /* close config file */ - - (void) sigsetmask(omask); /* reset signal mask */ - - return(1); /* return success */ -} - -/* -** ParseAddr -- Parse a string containing an RMP address. -** -** This routine is fairly liberal at parsing an RMP address. The -** address must contain 6 octets consisting of between 0 and 2 hex -** chars (upper/lower case) separated by colons. If two colons are -** together (e.g. "::", the octet between them is recorded as being -** zero. Hence, the following addrs are all valid and parse to the -** same thing: -** -** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD -** -** For clarity, an RMP address is really an Ethernet address, but -** since the HP boot code uses IEEE 802.3, it's really an IEEE -** 802.3 address. Of course, all of these are identical. -** -** Parameters: -** str - string representation of an RMP address. -** -** Returns: -** pointer to a static array of RMP_ADDRLEN bytes. -** -** Side Effects: -** None. -** -** Warnings: -** - The return value points to a static buffer; it must -** be copied if it's to be saved. -** - For speed, we assume a u_char consists of 8 bits. -*/ -u_char * -ParseAddr(str) - char *str; -{ - static u_char addr[RMP_ADDRLEN]; - register char *cp; - register unsigned i; - register int part, subpart; - - bzero((char *)&addr[0], RMP_ADDRLEN); /* zero static buffer */ - - part = subpart = 0; - for (cp = str; *cp; cp++) { - /* - * A colon (`:') must be used to delimit each octet. - */ - if (*cp == ':') { - if (++part == RMP_ADDRLEN) /* too many parts */ - return(NULL); - subpart = 0; - continue; - } - - /* - * Convert hex character to an integer. - */ - if (isdigit(*cp)) - i = *cp - '0'; - else { - i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10; - if (i < 10 || i > 15) /* not a hex char */ - return(NULL); - } - - if (subpart++) { - if (subpart > 2) /* too many hex chars */ - return(NULL); - addr[part] <<= 4; - } - addr[part] |= i; - } - - if (part != (RMP_ADDRLEN-1)) /* too few parts */ - return(NULL); - - return(&addr[0]); -} - -/* -** GetBootFiles -- record list of files in current (boot) directory. -** -** Parameters: -** None. -** -** Returns: -** Number of boot files on success, 0 on failure. -** -** Side Effects: -** Strings in `BootFiles' are freed/allocated. -** -** Warnings: -** - After this routine is called, ParseConfig() must be -** called to re-order it's list of boot file pointers. -*/ -int -GetBootFiles() -{ - DIR *dfd; - struct stat statb; - register struct dirent *dp; - register int i; - - /* - * Free the current list of boot files. - */ - for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) { - FreeStr(BootFiles[i]); - BootFiles[i] = NULL; - } - - /* - * Open current directory to read boot file names. - */ - if ((dfd = opendir(".")) == NULL) { /* open BootDir */ - syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n", - BootDir); - return(0); - } - - /* - * Read each boot file name and allocate space for it in the - * list of boot files (BootFiles). All boot files read after - * C_MAXFILE will be ignored. - */ - i = 0; - for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) { - if (stat(dp->d_name, &statb) < 0 || - (statb.st_mode & S_IFMT) != S_IFREG) - continue; - if (i == C_MAXFILE) - syslog(LOG_ERR, - "GetBootFiles: too many boot files (%s ignored)", - dp->d_name); - else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL) - i++; - } - - (void) closedir(dfd); /* close BootDir */ - - if (i == 0) /* cant find any boot files */ - syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir); - - return(i); -} diff --git a/rbootd.tproj/pathnames.h b/rbootd.tproj/pathnames.h deleted file mode 100644 index 15765da..0000000 --- a/rbootd.tproj/pathnames.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)pathnames.h 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: pathnames.h 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#define _PATH_BPF "/dev/bpf%d" -#define _PATH_RBOOTDCONF "/etc/rbootd.conf" -#define _PATH_RBOOTDDBG "/tmp/rbootd.dbg" -#define _PATH_RBOOTDLIB "/usr/mdec/rbootd" -#define _PATH_RBOOTDPID "/var/run/rbootd.pid" diff --git a/rbootd.tproj/rbootd.8 b/rbootd.tproj/rbootd.8 deleted file mode 100644 index f4eb364..0000000 --- a/rbootd.tproj/rbootd.8 +++ /dev/null @@ -1,156 +0,0 @@ -.\" Copyright (c) 1988, 1992 The University of Utah and the Center -.\" for Software Science (CSS). -.\" Copyright (c) 1992, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" This code is derived from software contributed to Berkeley by -.\" the Center for Software Science of the University of Utah Computer -.\" Science Department. CSS requests users of this software to return -.\" to css-dist@cs.utah.edu any improvements that they make and grant -.\" CSS redistribution rights. -.\" -.\" 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. -.\" -.\" @(#)rbootd.8 8.2 (Berkeley) 12/11/93 -.\" -.\" Utah $Hdr: rbootd.man 3.1 92/07/06$ -.\" Author: Jeff Forys, University of Utah CSS -.\" -.Dd "December 11, 1993" -.Dt RBOOTD 8 -.Os -.Sh NAME -.Nm rbootd -.Nd HP remote boot server -.Sh SYNOPSIS -.Nm rbootd -.Op Fl ad -.Op Fl i Ar interface -.Op config_file -.Sh DESCRIPTION -The -.Nm rbootd -utility services boot requests from Hewlett-Packard workstations over a -local area network. -All boot files must reside in the boot file directory; further, if a -client supplies path information in its boot request, it will be silently -stripped away before processing. -By default, -.Nm rbootd -only responds to requests from machines listed in its configuration file. -.Pp -The options are as follows: -.Bl -tag -width Fl -.It Fl a -Respond to boot requests from any machine. -The configuration file is ignored if this option is specified. -.It Fl d -Run -.Nm rbootd -in debug mode. -Packets sent and received are displayed to the terminal. -.It Fl i Ar interface -Service boot requests on specified interface. -If unspecified, -.Nm rbootd -searches the system interface list for the lowest numbered, configured -``up'' interface (excluding loopback). -Ties are broken by choosing the earliest match. -.El -.Pp -Specifying -.Ar config_file -on the command line causes -.Nm rbootd -to use a different configuration file from the default. -.Pp -The configuration file is a text file where each line describes a particular -machine. -A line must start with a machine's Ethernet address followed by an optional -list of boot file names. -An Ethernet address is specified in hexadecimal with each of its six octets -separated by a colon. -The boot file names come from the boot file directory. -The ethernet address and boot file(s) must be separated by white-space -and/or comma characters. -A pound sign causes the remainder of a line to be ignored. -.Pp -Here is a sample configuration file: -.Bl -column 08:00:09:0:66:ad SYSHPBSD,SYSHPUX "# vandy (anything)" -.It # -.It # ethernet addr boot file(s) comments -.It # -.It 08:00:09:0:66:ad SYSHPBSD # snake (4.3BSD) -.It 08:00:09:0:59:5b # vandy (anything) -.It 8::9:1:C6:75 SYSHPBSD,SYSHPUX # jaguar (either) -.El -.Pp -.Nm Rbootd -logs status and error messages via -.Xr syslog 3 . -A startup message is always logged, and in the case of fatal errors (or -deadly signals) a message is logged announcing the server's termination. -In general, a non-fatal error is handled by ignoring the event that caused -it (e.g. an invalid Ethernet address in the config file causes that line -to be invalidated). -.Pp -The following signals have the specified effect when sent to the server -process using the -.Xr kill 1 -command: -.Bl -tag -width SIGUSR1 -offset -compact -.It SIGHUP -Drop all active connections and reconfigure. -.It SIGUSR1 -Turn on debugging, do nothing if already on. -.It SIGUSR2 -Turn off debugging, do nothing if already off. -.El -.Sh "FILES" -.Bl -tag -width /usr/libexec/rbootd -compact -.It /dev/bpf# -packet-filter device -.It /etc/rbootd.conf -configuration file -.It /tmp/rbootd.dbg -debug output -.It /usr/mdec/rbootd -directory containing boot files -.It /var/run/rbootd.pid -process id -.El -.Sh SEE ALSO -.Xr kill 1 , -.Xr socket 2 , -.Xr signal 3 , -.Xr syslog 3 , -.Xr rmp 4 -.Sh BUGS -If multiple servers are started on the same interface, each will receive -and respond to the same boot packets. diff --git a/rbootd.tproj/rbootd.c b/rbootd.tproj/rbootd.c deleted file mode 100644 index cf661b2..0000000 --- a/rbootd.tproj/rbootd.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)rbootd.c 8.2 (Berkeley) 2/22/94 - * - * Utah $Hdr: rbootd.c 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1992, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)rbootd.c 8.2 (Berkeley) 2/22/94"; -#endif /* not lint */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "defs.h" - - -/* fd mask macros (backward compatibility with 4.2BSD) */ -#ifndef FD_SET -#ifdef notdef -typedef struct fd_set { /* this should already be in 4.2 */ - int fds_bits[1]; -} fd_set; -#endif -#define FD_ZERO(p) ((p)->fds_bits[0] = 0) -#define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n))) -#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << (n))) -#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n))) -#endif - -int -main(argc, argv) - int argc; - char *argv[]; -{ - int c, fd, omask, maxfds; - fd_set rset; - - /* - * Find what name we are running under. - */ - ProgName = (ProgName = rindex(argv[0],'/')) ? ++ProgName : *argv; - - /* - * Close any open file descriptors. - * Temporarily leave stdin & stdout open for `-d', - * and stderr open for any pre-syslog error messages. - */ - { - int i, nfds = getdtablesize(); - - for (i = 0; i < nfds; i++) - if (i != fileno(stdin) && i != fileno(stdout) && - i != fileno(stderr)) - (void) close(i); - } - - /* - * Parse any arguments. - */ - while ((c = getopt(argc, argv, "adi:")) != EOF) - switch(c) { - case 'a': - BootAny++; - break; - case 'd': - DebugFlg++; - break; - case 'i': - IntfName = optarg; - break; - } - for (; optind < argc; optind++) { - if (ConfigFile == NULL) - ConfigFile = argv[optind]; - else { - fprintf(stderr, - "%s: too many config files (`%s' ignored)\n", - ProgName, argv[optind]); - } - } - - if (ConfigFile == NULL) /* use default config file */ - ConfigFile = DfltConfig; - - if (DebugFlg) { - DbgFp = stdout; /* output to stdout */ - - (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */ - (void) signal(SIGUSR2, SIG_IGN); - } else { - (void) fclose(stdin); /* dont need these */ - (void) fclose(stdout); - - /* - * Fork off a child to do the work & exit. - */ - switch(fork()) { - case -1: /* fork failed */ - fprintf(stderr, "%s: ", ProgName); - perror("fork"); - Exit(0); - case 0: /* this is the CHILD */ - break; - default: /* this is the PARENT */ - _exit(0); - } - - /* - * Try to disassociate from the current tty. - */ - { - char *devtty = "/dev/tty"; - int i; - - if ((i = open(devtty, O_RDWR)) < 0) { - /* probably already disassociated */ - if (setpgrp(0, 0) < 0) { - fprintf(stderr, "%s: ", ProgName); - perror("setpgrp"); - } - } else { - if (ioctl(i, (u_long)TIOCNOTTY, (char *)0) < 0){ - fprintf(stderr, "%s: ", ProgName); - perror("ioctl"); - } - (void) close(i); - } - } - - (void) signal(SIGUSR1, DebugOn); - (void) signal(SIGUSR2, DebugOff); - } - - (void) fclose(stderr); /* finished with it */ - -#ifdef SYSLOG4_2 - openlog(ProgName, LOG_PID); -#else - openlog(ProgName, LOG_PID, LOG_DAEMON); -#endif - - /* - * If no interface was specified, get one now. - * - * This is convoluted because we want to get the default interface - * name for the syslog("restarted") message. If BpfGetIntfName() - * runs into an error, it will return a syslog-able error message - * (in `errmsg') which will be displayed here. - */ - if (IntfName == NULL) { - char *errmsg; - - if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { - syslog(LOG_NOTICE, "restarted (??)"); - syslog(LOG_ERR, errmsg); - Exit(0); - } - } - - syslog(LOG_NOTICE, "restarted (%s)", IntfName); - - (void) signal(SIGHUP, ReConfig); - (void) signal(SIGINT, Exit); - (void) signal(SIGTERM, Exit); - - /* - * Grab our host name and pid. - */ - if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) { - syslog(LOG_ERR, "gethostname: %m"); - Exit(0); - } - MyHost[MAXHOSTNAMELEN] = '\0'; - - MyPid = getpid(); - - /* - * Write proc's pid to a file. - */ - { - FILE *fp; - - if ((fp = fopen(PidFile, "w")) != NULL) { - (void) fprintf(fp, "%d\n", MyPid); - (void) fclose(fp); - } else { - syslog(LOG_WARNING, "fopen: failed (%s)", PidFile); - } - } - - /* - * All boot files are relative to the boot directory, we might - * as well chdir() there to make life easier. - */ - if (chdir(BootDir) < 0) { - syslog(LOG_ERR, "chdir: %m (%s)", BootDir); - Exit(0); - } - - /* - * Initial configuration. - */ - omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */ - if (GetBootFiles() == 0) /* get list of boot files */ - Exit(0); - if (ParseConfig() == 0) /* parse config file */ - Exit(0); - - /* - * Open and initialize a BPF device for the appropriate interface. - * If an error is encountered, a message is displayed and Exit() - * is called. - */ - fd = BpfOpen(); - - (void) sigsetmask(omask); /* allow reconfig's */ - - /* - * Main loop: receive a packet, determine where it came from, - * and if we service this host, call routine to handle request. - */ - maxfds = fd + 1; - FD_ZERO(&rset); - FD_SET(fd, &rset); - for (;;) { - struct timeval timeout; - fd_set r; - int nsel; - - r = rset; - - if (RmpConns == NULL) { /* timeout isnt necessary */ - nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0, - (struct timeval *)0); - } else { - timeout.tv_sec = RMP_TIMEOUT; - timeout.tv_usec = 0; - nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0, - &timeout); - } - - if (nsel < 0) { - if (errno == EINTR) - continue; - syslog(LOG_ERR, "select: %m"); - Exit(0); - } else if (nsel == 0) { /* timeout */ - DoTimeout(); /* clear stale conns */ - continue; - } - - if (FD_ISSET(fd, &r)) { - RMPCONN rconn; - CLIENT *client, *FindClient(); - int doread = 1; - - while (BpfRead(&rconn, doread)) { - doread = 0; - - if (DbgFp != NULL) /* display packet */ - DispPkt(&rconn,DIR_RCVD); - - omask = sigblock(sigmask(SIGHUP)); - - /* - * If we do not restrict service, set the - * client to NULL (ProcessPacket() handles - * this). Otherwise, check that we can - * service this host; if not, log a message - * and ignore the packet. - */ - if (BootAny) { - client = NULL; - } else if ((client=FindClient(&rconn))==NULL) { - syslog(LOG_INFO, - "%s: boot packet ignored", - EnetStr(&rconn)); - (void) sigsetmask(omask); - continue; - } - - ProcessPacket(&rconn,client); - - (void) sigsetmask(omask); - } - } - } -} - -/* -** DoTimeout -- Free any connections that have timed out. -** -** Parameters: -** None. -** -** Returns: -** Nothing. -** -** Side Effects: -** - Timed out connections in `RmpConns' will be freed. -*/ -void -DoTimeout() -{ - register RMPCONN *rtmp; - struct timeval now; - - (void) gettimeofday(&now, (struct timezone *)0); - - /* - * For each active connection, if RMP_TIMEOUT seconds have passed - * since the last packet was sent, delete the connection. - */ - for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) - if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) { - syslog(LOG_WARNING, "%s: connection timed out (%u)", - EnetStr(rtmp), rtmp->rmp.r_type); - RemoveConn(rtmp); - } -} - -/* -** FindClient -- Find client associated with a packet. -** -** Parameters: -** rconn - the new packet. -** -** Returns: -** Pointer to client info if found, NULL otherwise. -** -** Side Effects: -** None. -** -** Warnings: -** - This routine must be called with SIGHUP blocked since -** a reconfigure can invalidate the information returned. -*/ - -CLIENT * -FindClient(rconn) - register RMPCONN *rconn; -{ - register CLIENT *ctmp; - - for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next) - if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], - (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0) - break; - - return(ctmp); -} - -/* -** Exit -- Log an error message and exit. -** -** Parameters: -** sig - caught signal (or zero if not dying on a signal). -** -** Returns: -** Does not return. -** -** Side Effects: -** - This process ceases to exist. -*/ -void -Exit(sig) - int sig; -{ - if (sig > 0) - syslog(LOG_ERR, "going down on signal %d", sig); - else - syslog(LOG_ERR, "going down with fatal error"); - BpfClose(); - exit(1); -} - -/* -** ReConfig -- Get new list of boot files and reread config files. -** -** Parameters: -** None. -** -** Returns: -** Nothing. -** -** Side Effects: -** - All active connections are dropped. -** - List of boot-able files is changed. -** - List of clients is changed. -** -** Warnings: -** - This routine must be called with SIGHUP blocked. -*/ -void -ReConfig(signo) - int signo; -{ - syslog(LOG_NOTICE, "reconfiguring boot server"); - - FreeConns(); - - if (GetBootFiles() == 0) - Exit(0); - - if (ParseConfig() == 0) - Exit(0); -} - -/* -** DebugOff -- Turn off debugging. -** -** Parameters: -** None. -** -** Returns: -** Nothing. -** -** Side Effects: -** - Debug file is closed. -*/ -void -DebugOff(signo) - int signo; -{ - if (DbgFp != NULL) - (void) fclose(DbgFp); - - DbgFp = NULL; -} - -/* -** DebugOn -- Turn on debugging. -** -** Parameters: -** None. -** -** Returns: -** Nothing. -** -** Side Effects: -** - Debug file is opened/truncated if not already opened, -** otherwise do nothing. -*/ -void -DebugOn(signo) - int signo; -{ - if (DbgFp == NULL) { - if ((DbgFp = fopen(DbgFile, "w")) == NULL) - syslog(LOG_ERR, "can't open debug file (%s)", DbgFile); - } -} diff --git a/rbootd.tproj/rmp.h b/rbootd.tproj/rmp.h deleted file mode 100644 index 31b9440..0000000 --- a/rbootd.tproj/rmp.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)rmp.h 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: rmp.h 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -/* - * Define MIN/MAX sizes of RMP (ethernet) packet. - * For ease of computation, the 4 octet CRC field is not included. - * - * MCLBYTES is for bpfwrite(); it is adamant about using a cluster. - */ - -#define RMP_MAX_PACKET MIN(1514,MCLBYTES) -#define RMP_MIN_PACKET 60 - -/* - * Define RMP/Ethernet Multicast address (9:0:9:0:0:4) and its length. - */ -#define RMP_ADDR { 0x9, 0x0, 0x9, 0x0, 0x0, 0x4 } -#define RMP_ADDRLEN 6 - -/* - * Define IEEE802.2 (Logical Link Control) information. - */ -#define IEEE_DSAP_HP 0xF8 /* Destination Service Access Point */ -#define IEEE_SSAP_HP 0xF8 /* Source Service Access Point */ -#define IEEE_CNTL_HP 0x0300 /* Type 1 / I format control information */ - -#define HPEXT_DXSAP 0x608 /* HP Destination Service Access Point */ -#define HPEXT_SXSAP 0x609 /* HP Source Service Access Point */ - -/* - * 802.3-style "Ethernet" header. - */ - -struct hp_hdr { - u_char daddr[RMP_ADDRLEN]; - u_char saddr[RMP_ADDRLEN]; - u_short len; -}; - -/* - * HP uses 802.2 LLC with their own local extensions. This struct makes - * sence out of this data (encapsulated in the above 802.3 packet). - */ - -struct hp_llc { - u_char dsap; /* 802.2 DSAP */ - u_char ssap; /* 802.2 SSAP */ - u_short cntrl; /* 802.2 control field */ - u_short filler; /* HP filler (must be zero) */ - u_short dxsap; /* HP extended DSAP */ - u_short sxsap; /* HP extended SSAP */ -}; diff --git a/rbootd.tproj/rmp_var.h b/rbootd.tproj/rmp_var.h deleted file mode 100644 index adecc85..0000000 --- a/rbootd.tproj/rmp_var.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)rmp_var.h 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: rmp_var.h 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -/* - * Possible values for "rmp_type" fields. - */ - -#define RMP_BOOT_REQ 1 /* boot request packet */ -#define RMP_BOOT_REPL 129 /* boot reply packet */ -#define RMP_READ_REQ 2 /* read request packet */ -#define RMP_READ_REPL 130 /* read reply packet */ -#define RMP_BOOT_DONE 3 /* boot complete packet */ - -/* - * Useful constants. - */ - -#define RMP_VERSION 2 /* protocol version */ -#define RMP_TIMEOUT 600 /* timeout connection after ten minutes */ -#define RMP_PROBESID 0xffff /* session ID for probes */ -#define RMP_HOSTLEN 13 /* max length of server's name */ -#define RMP_MACHLEN 20 /* length of machine type field */ - -/* - * RMP error codes - */ - -#define RMP_E_OKAY 0 -#define RMP_E_EOF 2 /* read reply: returned end of file */ -#define RMP_E_ABORT 3 /* abort operation */ -#define RMP_E_BUSY 4 /* boot reply: server busy */ -#define RMP_E_TIMEOUT 5 /* lengthen time out (not implemented) */ -#define RMP_E_NOFILE 16 /* boot reply: file does not exist */ -#define RMP_E_OPENFILE 17 /* boot reply: file open failed */ -#define RMP_E_NODFLT 18 /* boot reply: default file does not exist */ -#define RMP_E_OPENDFLT 19 /* boot reply: default file open failed */ -#define RMP_E_BADSID 25 /* read reply: bad session ID */ -#define RMP_E_BADPACKET 27 /* Bad packet detected */ - -/* - * RMPDATALEN is the maximum number of data octets that can be stuffed - * into an RMP packet. This excludes the 802.2 LLC w/HP extensions. - */ -#define RMPDATALEN (RMP_MAX_PACKET - (sizeof(struct hp_hdr) + \ - sizeof(struct hp_llc))) - -/* - * Define sizes of packets we send. Boot and Read replies are variable - * in length depending on the length of `s'. - * - * Also, define how much space `restofpkt' can take up for outgoing - * Boot and Read replies. Boot Request packets are effectively - * limited to 255 bytes due to the preceding 1-byte length field. - */ - -#define RMPBOOTSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \ - sizeof(struct rmp_boot_repl) + s - sizeof(restofpkt)) -#define RMPREADSIZE(s) (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \ - sizeof(struct rmp_read_repl) + s - sizeof(restofpkt) \ - - sizeof(u_char)) -#define RMPDONESIZE (sizeof(struct hp_hdr) + sizeof(struct hp_llc) + \ - sizeof(struct rmp_boot_done)) -#define RMPBOOTDATA 255 -#define RMPREADDATA (RMPDATALEN - \ - (2*sizeof(u_char)+sizeof(u_short)+sizeof(u_word))) - -/* - * This protocol defines some field sizes as "rest of ethernet packet". - * There is no easy way to specify this in C, so we use a one character - * field to denote it, and index past it to the end of the packet. - */ - -typedef char restofpkt; - -/* - * Due to the RMP packet layout, we'll run into alignment problems - * on machines that cant access words on half-word boundaries. If - * you know that your machine does not suffer from this problem, - * add it to the hp300 #define below. - * - * The following macros are used to deal with this problem: - * WORDZE(w) Return True if u_word `w' is zero, False otherwise. - * ZEROWORD(w) Set u_word `w' to zero. - * COPYWORD(w1,w2) Copy u_word `w1' to `w2'. - * GETWORD(w,i) Copy u_word `w' into int `i'. - * PUTWORD(i,w) Copy int `i' into u_word `w'. - * - * N.B. We do not support little endian alignment-challenged machines. - */ -#if defined(vax) || defined(tahoe) || defined(hp300) - -typedef u_int u_word; - -#define WORDZE(w) ((w) == 0) -#define ZEROWORD(w) (w) = 0 -#define COPYWORD(w1,w2) (w2) = (w1) -#define GETWORD(w, i) (i) = (w) -#define PUTWORD(i, w) (w) = (i) - -#else - -#define _WORD_HIGHPART 0 /* XXX: assume Big Endian for now */ -#define _WORD_LOWPART 1 - -typedef struct _uword { u_short val[2]; } u_word; - -#define WORDZE(w) \ - ((w.val[_WORD_HIGHPART] == 0) && (w.val[_WORD_LOWPART] == 0)) -#define ZEROWORD(w) \ - (w).val[_WORD_HIGHPART] = (w).val[_WORD_LOWPART] = 0 -#define COPYWORD(w1, w2) \ - { (w2).val[_WORD_HIGHPART] = (w1).val[_WORD_HIGHPART]; \ - (w2).val[_WORD_LOWPART] = (w1).val[_WORD_LOWPART]; \ - } -#define GETWORD(w, i) \ - (i) = (((u_int)(w).val[_WORD_HIGHPART]) << 16) | (w).val[_WORD_LOWPART] -#define PUTWORD(i, w) \ - { (w).val[_WORD_HIGHPART] = (u_short) (((i) >> 16) & 0xffff); \ - (w).val[_WORD_LOWPART] = (u_short) (i & 0xffff); \ - } - -#endif - -/* - * Packet structures. - */ - -struct rmp_raw { /* generic RMP packet */ - u_char rmp_type; /* packet type */ - u_char rmp_rawdata[RMPDATALEN-1]; -}; - -struct rmp_boot_req { /* boot request */ - u_char rmp_type; /* packet type (RMP_BOOT_REQ) */ - u_char rmp_retcode; /* return code (0) */ - u_word rmp_seqno; /* sequence number (real time clock) */ - u_short rmp_session; /* session id (normally 0) */ - u_short rmp_version; /* protocol version (RMP_VERSION) */ - char rmp_machtype[RMP_MACHLEN]; /* machine type */ - u_char rmp_flnmsize; /* length of rmp_flnm */ - restofpkt rmp_flnm; /* name of file to be read */ -}; - -struct rmp_boot_repl { /* boot reply */ - u_char rmp_type; /* packet type (RMP_BOOT_REPL) */ - u_char rmp_retcode; /* return code (normally 0) */ - u_word rmp_seqno; /* sequence number (from boot req) */ - u_short rmp_session; /* session id (generated) */ - u_short rmp_version; /* protocol version (RMP_VERSION) */ - u_char rmp_flnmsize; /* length of rmp_flnm */ - restofpkt rmp_flnm; /* name of file (from boot req) */ -}; - -struct rmp_read_req { /* read request */ - u_char rmp_type; /* packet type (RMP_READ_REQ) */ - u_char rmp_retcode; /* return code (0) */ - u_word rmp_offset; /* file relative byte offset */ - u_short rmp_session; /* session id (from boot repl) */ - u_short rmp_size; /* max no of bytes to send */ -}; - -struct rmp_read_repl { /* read reply */ - u_char rmp_type; /* packet type (RMP_READ_REPL) */ - u_char rmp_retcode; /* return code (normally 0) */ - u_word rmp_offset; /* byte offset (from read req) */ - u_short rmp_session; /* session id (from read req) */ - restofpkt rmp_data; /* data (max size from read req) */ - u_char rmp_unused; /* padding to 16-bit boundary */ -}; - -struct rmp_boot_done { /* boot complete */ - u_char rmp_type; /* packet type (RMP_BOOT_DONE) */ - u_char rmp_retcode; /* return code (0) */ - u_word rmp_unused; /* not used (0) */ - u_short rmp_session; /* session id (from read repl) */ -}; - -struct rmp_packet { - struct hp_hdr hp_hdr; - struct hp_llc hp_llc; - union { - struct rmp_boot_req rmp_brq; /* boot request */ - struct rmp_boot_repl rmp_brpl; /* boot reply */ - struct rmp_read_req rmp_rrq; /* read request */ - struct rmp_read_repl rmp_rrpl; /* read reply */ - struct rmp_boot_done rmp_done; /* boot complete */ - struct rmp_raw rmp_raw; /* raw data */ - } rmp_proto; -}; - -/* - * Make life easier... - */ - -#define r_type rmp_proto.rmp_raw.rmp_type -#define r_data rmp_proto.rmp_raw.rmp_data -#define r_brq rmp_proto.rmp_brq -#define r_brpl rmp_proto.rmp_brpl -#define r_rrq rmp_proto.rmp_rrq -#define r_rrpl rmp_proto.rmp_rrpl -#define r_done rmp_proto.rmp_done diff --git a/rbootd.tproj/rmpproto.c b/rbootd.tproj/rmpproto.c deleted file mode 100644 index d8f676c..0000000 --- a/rbootd.tproj/rmpproto.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)rmpproto.c 8.1 (Berkeley) 6/4/93 - * - * Utah $Hdr: rmpproto.c 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#ifndef lint -static char sccsid[] = "@(#)rmpproto.c 8.1 (Berkeley) 6/4/93"; -#endif /* not lint */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include "defs.h" - -/* -** ProcessPacket -- determine packet type and do what's required. -** -** An RMP BOOT packet has been received. Look at the type field -** and process Boot Requests, Read Requests, and Boot Complete -** packets. Any other type will be dropped with a warning msg. -** -** Parameters: -** rconn - the new connection -** client - list of files available to this host -** -** Returns: -** Nothing. -** -** Side Effects: -** - If this is a valid boot request, it will be added to -** the linked list of outstanding requests (RmpConns). -** - If this is a valid boot complete, its associated -** entry in RmpConns will be deleted. -** - Also, unless we run out of memory, a reply will be -** sent to the host that sent the packet. -*/ -void -ProcessPacket(rconn, client) - RMPCONN *rconn; - CLIENT *client; -{ - struct rmp_packet *rmp; - RMPCONN *rconnout; - - rmp = &rconn->rmp; /* cache pointer to RMP packet */ - - switch(rmp->r_type) { /* do what we came here to do */ - case RMP_BOOT_REQ: /* boot request */ - if ((rconnout = NewConn(rconn)) == NULL) - return; - - /* - * If the Session ID is 0xffff, this is a "probe" - * packet and we do not want to add the connection - * to the linked list of active connections. There - * are two types of probe packets, if the Sequence - * Number is 0 they want to know our host name, o/w - * they want the name of the file associated with - * the number spec'd by the Sequence Number. - * - * If this is an actual boot request, open the file - * and send a reply. If SendBootRepl() does not - * return 0, add the connection to the linked list - * of active connections, otherwise delete it since - * an error was encountered. - */ - if (rmp->r_brq.rmp_session == RMP_PROBESID) { - if (WORDZE(rmp->r_brq.rmp_seqno)) - (void) SendServerID(rconnout); - else - (void) SendFileNo(rmp, rconnout, - client? client->files: - BootFiles); - FreeConn(rconnout); - } else { - if (SendBootRepl(rmp, rconnout, - client? client->files: BootFiles)) - AddConn(rconnout); - else - FreeConn(rconnout); - } - break; - - case RMP_BOOT_REPL: /* boot reply (not valid) */ - syslog(LOG_WARNING, "%s: sent a boot reply", - EnetStr(rconn)); - break; - - case RMP_READ_REQ: /* read request */ - /* - * Send a portion of the boot file. - */ - (void) SendReadRepl(rconn); - break; - - case RMP_READ_REPL: /* read reply (not valid) */ - syslog(LOG_WARNING, "%s: sent a read reply", - EnetStr(rconn)); - break; - - case RMP_BOOT_DONE: /* boot complete */ - /* - * Remove the entry from the linked list of active - * connections. - */ - (void) BootDone(rconn); - break; - - default: /* unknown RMP packet type */ - syslog(LOG_WARNING, "%s: unknown packet type (%u)", - EnetStr(rconn), rmp->r_type); - } -} - -/* -** SendServerID -- send our host name to who ever requested it. -** -** Parameters: -** rconn - the reply packet to be formatted. -** -** Returns: -** 1 on success, 0 on failure. -** -** Side Effects: -** none. -*/ -int -SendServerID(rconn) - RMPCONN *rconn; -{ - register struct rmp_packet *rpl; - register char *src, *dst; - register u_char *size; - - rpl = &rconn->rmp; /* cache ptr to RMP packet */ - - /* - * Set up assorted fields in reply packet. - */ - rpl->r_brpl.rmp_type = RMP_BOOT_REPL; - rpl->r_brpl.rmp_retcode = RMP_E_OKAY; - ZEROWORD(rpl->r_brpl.rmp_seqno); - rpl->r_brpl.rmp_session = 0; - rpl->r_brpl.rmp_version = RMP_VERSION; - - size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of host name */ - - /* - * Copy our host name into the reply packet incrementing the - * length as we go. Stop at RMP_HOSTLEN or the first dot. - */ - src = MyHost; - dst = (char *) &rpl->r_brpl.rmp_flnm; - for (*size = 0; *size < RMP_HOSTLEN; (*size)++) { - if (*src == '.' || *src == '\0') - break; - *dst++ = *src++; - } - - rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */ - - return(SendPacket(rconn)); /* send packet */ -} - -/* -** SendFileNo -- send the name of a bootable file to the requester. -** -** Parameters: -** req - RMP BOOT packet containing the request. -** rconn - the reply packet to be formatted. -** filelist - list of files available to the requester. -** -** Returns: -** 1 on success, 0 on failure. -** -** Side Effects: -** none. -*/ -int -SendFileNo(req, rconn, filelist) - struct rmp_packet *req; - RMPCONN *rconn; - char *filelist[]; -{ - register struct rmp_packet *rpl; - register char *src, *dst; - register u_char *size, i; - - GETWORD(req->r_brpl.rmp_seqno, i); /* SeqNo is really FileNo */ - rpl = &rconn->rmp; /* cache ptr to RMP packet */ - - /* - * Set up assorted fields in reply packet. - */ - rpl->r_brpl.rmp_type = RMP_BOOT_REPL; - PUTWORD(i, rpl->r_brpl.rmp_seqno); - i--; - rpl->r_brpl.rmp_session = 0; - rpl->r_brpl.rmp_version = RMP_VERSION; - - size = &rpl->r_brpl.rmp_flnmsize; /* ptr to length of filename */ - *size = 0; /* init length to zero */ - - /* - * Copy the file name into the reply packet incrementing the - * length as we go. Stop at end of string or when RMPBOOTDATA - * characters have been copied. Also, set return code to - * indicate success or "no more files". - */ - if (i < C_MAXFILE && filelist[i] != NULL) { - src = filelist[i]; - dst = (char *)&rpl->r_brpl.rmp_flnm; - for (; *src && *size < RMPBOOTDATA; (*size)++) { - if (*src == '\0') - break; - *dst++ = *src++; - } - rpl->r_brpl.rmp_retcode = RMP_E_OKAY; - } else - rpl->r_brpl.rmp_retcode = RMP_E_NODFLT; - - rconn->rmplen = RMPBOOTSIZE(*size); /* set packet length */ - - return(SendPacket(rconn)); /* send packet */ -} - -/* -** SendBootRepl -- open boot file and respond to boot request. -** -** Parameters: -** req - RMP BOOT packet containing the request. -** rconn - the reply packet to be formatted. -** filelist - list of files available to the requester. -** -** Returns: -** 1 on success, 0 on failure. -** -** Side Effects: -** none. -*/ -int -SendBootRepl(req, rconn, filelist) - struct rmp_packet *req; - RMPCONN *rconn; - char *filelist[]; -{ - int retval; - char *filename, filepath[RMPBOOTDATA+1]; - RMPCONN *oldconn; - register struct rmp_packet *rpl; - register char *src, *dst1, *dst2; - register u_char i; - - /* - * If another connection already exists, delete it since we - * are obviously starting again. - */ - if ((oldconn = FindConn(rconn)) != NULL) { - syslog(LOG_WARNING, "%s: dropping existing connection", - EnetStr(oldconn)); - RemoveConn(oldconn); - } - - rpl = &rconn->rmp; /* cache ptr to RMP packet */ - - /* - * Set up assorted fields in reply packet. - */ - rpl->r_brpl.rmp_type = RMP_BOOT_REPL; - COPYWORD(req->r_brq.rmp_seqno, rpl->r_brpl.rmp_seqno); - rpl->r_brpl.rmp_session = GenSessID(); - rpl->r_brpl.rmp_version = RMP_VERSION; - rpl->r_brpl.rmp_flnmsize = req->r_brq.rmp_flnmsize; - - /* - * Copy file name to `filepath' string, and into reply packet. - */ - src = &req->r_brq.rmp_flnm; - dst1 = filepath; - dst2 = &rpl->r_brpl.rmp_flnm; - for (i = 0; i < req->r_brq.rmp_flnmsize; i++) - *dst1++ = *dst2++ = *src++; - *dst1 = '\0'; - - /* - * If we are booting HP-UX machines, their secondary loader will - * ask for files like "/hp-ux". As a security measure, we do not - * allow boot files to lay outside the boot directory (unless they - * are purposely link'd out. So, make `filename' become the path- - * stripped file name and spoof the client into thinking that it - * really got what it wanted. - */ - filename = (filename = rindex(filepath,'/'))? ++filename: filepath; - - /* - * Check that this is a valid boot file name. - */ - for (i = 0; i < C_MAXFILE && filelist[i] != NULL; i++) - if (STREQN(filename, filelist[i])) - goto match; - - /* - * Invalid boot file name, set error and send reply packet. - */ - rpl->r_brpl.rmp_retcode = RMP_E_NOFILE; - retval = 0; - goto sendpkt; - -match: - /* - * This is a valid boot file. Open the file and save the file - * descriptor associated with this connection and set success - * indication. If the file couldnt be opened, set error: - * "no such file or dir" - RMP_E_NOFILE - * "file table overflow" - RMP_E_BUSY - * "too many open files" - RMP_E_BUSY - * anything else - RMP_E_OPENFILE - */ - if ((rconn->bootfd = open(filename, O_RDONLY, 0600)) < 0) { - rpl->r_brpl.rmp_retcode = (errno == ENOENT)? RMP_E_NOFILE: - (errno == EMFILE || errno == ENFILE)? RMP_E_BUSY: - RMP_E_OPENFILE; - retval = 0; - } else { - rpl->r_brpl.rmp_retcode = RMP_E_OKAY; - retval = 1; - } - -sendpkt: - syslog(LOG_INFO, "%s: request to boot %s (%s)", - EnetStr(rconn), filename, retval? "granted": "denied"); - - rconn->rmplen = RMPBOOTSIZE(rpl->r_brpl.rmp_flnmsize); - - return (retval & SendPacket(rconn)); -} - -/* -** SendReadRepl -- send a portion of the boot file to the requester. -** -** Parameters: -** rconn - the reply packet to be formatted. -** -** Returns: -** 1 on success, 0 on failure. -** -** Side Effects: -** none. -*/ -int -SendReadRepl(rconn) - RMPCONN *rconn; -{ - int retval; - RMPCONN *oldconn; - register struct rmp_packet *rpl, *req; - register int size = 0; - int madeconn = 0; - - /* - * Find the old connection. If one doesnt exist, create one only - * to return the error code. - */ - if ((oldconn = FindConn(rconn)) == NULL) { - if ((oldconn = NewConn(rconn)) == NULL) - return(0); - syslog(LOG_ERR, "SendReadRepl: no active connection (%s)", - EnetStr(rconn)); - madeconn++; - } - - req = &rconn->rmp; /* cache ptr to request packet */ - rpl = &oldconn->rmp; /* cache ptr to reply packet */ - - if (madeconn) { /* no active connection above; abort */ - rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; - retval = 1; - goto sendpkt; - } - - /* - * Make sure Session ID's match. - */ - if (req->r_rrq.rmp_session != - ((rpl->r_type == RMP_BOOT_REPL)? rpl->r_brpl.rmp_session: - rpl->r_rrpl.rmp_session)) { - syslog(LOG_ERR, "SendReadRepl: bad session id (%s)", - EnetStr(rconn)); - rpl->r_rrpl.rmp_retcode = RMP_E_BADSID; - retval = 1; - goto sendpkt; - } - - /* - * If the requester asks for more data than we can fit, - * silently clamp the request size down to RMPREADDATA. - * - * N.B. I do not know if this is "legal", however it seems - * to work. This is necessary for bpfwrite() on machines - * with MCLBYTES less than 1514. - */ - if (req->r_rrq.rmp_size > RMPREADDATA) - req->r_rrq.rmp_size = RMPREADDATA; - - /* - * Position read head on file according to info in request packet. - */ - GETWORD(req->r_rrq.rmp_offset, size); - if (lseek(oldconn->bootfd, (off_t)size, L_SET) < 0) { - syslog(LOG_ERR, "SendReadRepl: lseek: %m (%s)", - EnetStr(rconn)); - rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; - retval = 1; - goto sendpkt; - } - - /* - * Read data directly into reply packet. - */ - if ((size = read(oldconn->bootfd, &rpl->r_rrpl.rmp_data, - (int) req->r_rrq.rmp_size)) <= 0) { - if (size < 0) { - syslog(LOG_ERR, "SendReadRepl: read: %m (%s)", - EnetStr(rconn)); - rpl->r_rrpl.rmp_retcode = RMP_E_ABORT; - } else { - rpl->r_rrpl.rmp_retcode = RMP_E_EOF; - } - retval = 1; - goto sendpkt; - } - - /* - * Set success indication. - */ - rpl->r_rrpl.rmp_retcode = RMP_E_OKAY; - -sendpkt: - /* - * Set up assorted fields in reply packet. - */ - rpl->r_rrpl.rmp_type = RMP_READ_REPL; - COPYWORD(req->r_rrq.rmp_offset, rpl->r_rrpl.rmp_offset); - rpl->r_rrpl.rmp_session = req->r_rrq.rmp_session; - - oldconn->rmplen = RMPREADSIZE(size); /* set size of packet */ - - retval &= SendPacket(oldconn); /* send packet */ - - if (madeconn) /* clean up after ourself */ - FreeConn(oldconn); - - return (retval); -} - -/* -** BootDone -- free up memory allocated for a connection. -** -** Parameters: -** rconn - incoming boot complete packet. -** -** Returns: -** 1 on success, 0 on failure. -** -** Side Effects: -** none. -*/ -int -BootDone(rconn) - RMPCONN *rconn; -{ - RMPCONN *oldconn; - struct rmp_packet *rpl; - - /* - * If we cant find the connection, ignore the request. - */ - if ((oldconn = FindConn(rconn)) == NULL) { - syslog(LOG_ERR, "BootDone: no existing connection (%s)", - EnetStr(rconn)); - return(0); - } - - rpl = &oldconn->rmp; /* cache ptr to RMP packet */ - - /* - * Make sure Session ID's match. - */ - if (rconn->rmp.r_rrq.rmp_session != - ((rpl->r_type == RMP_BOOT_REPL)? rpl->r_brpl.rmp_session: - rpl->r_rrpl.rmp_session)) { - syslog(LOG_ERR, "BootDone: bad session id (%s)", - EnetStr(rconn)); - return(0); - } - - RemoveConn(oldconn); /* remove connection */ - - syslog(LOG_INFO, "%s: boot complete", EnetStr(rconn)); - - return(1); -} - -/* -** SendPacket -- send an RMP packet to a remote host. -** -** Parameters: -** rconn - packet to be sent. -** -** Returns: -** 1 on success, 0 on failure. -** -** Side Effects: -** none. -*/ -int -SendPacket(rconn) - register RMPCONN *rconn; -{ - /* - * Set Ethernet Destination address to Source (BPF and the enet - * driver will take care of getting our source address set). - */ - bcopy((char *)&rconn->rmp.hp_hdr.saddr[0], - (char *)&rconn->rmp.hp_hdr.daddr[0], RMP_ADDRLEN); - rconn->rmp.hp_hdr.len = rconn->rmplen - sizeof(struct hp_hdr); - - /* - * Reverse 802.2/HP Extended Source & Destination Access Pts. - */ - rconn->rmp.hp_llc.dxsap = HPEXT_SXSAP; - rconn->rmp.hp_llc.sxsap = HPEXT_DXSAP; - - /* - * Last time this connection was active. - */ - (void) gettimeofday(&rconn->tstamp, (struct timezone *)0); - - if (DbgFp != NULL) /* display packet */ - DispPkt(rconn,DIR_SENT); - - /* - * Send RMP packet to remote host. - */ - return(BpfWrite(rconn)); -} diff --git a/rbootd.tproj/utils.c b/rbootd.tproj/utils.c deleted file mode 100644 index 7837471..0000000 --- a/rbootd.tproj/utils.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1988, 1992 The University of Utah and the Center - * for Software Science (CSS). - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * the Center for Software Science of the University of Utah Computer - * Science Department. CSS requests users of this software to return - * to css-dist@cs.utah.edu any improvements that they make and grant - * CSS redistribution rights. - * - * 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. - * - * @(#)utils.c 8.2 (Berkeley) 2/22/94 - * - * Utah $Hdr: utils.c 3.1 92/07/06$ - * Author: Jeff Forys, University of Utah CSS - */ - -#ifndef lint -static char sccsid[] = "@(#)utils.c 8.2 (Berkeley) 2/22/94"; -#endif /* not lint */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "defs.h" - -/* -** DispPkt -- Display the contents of an RMPCONN packet. -** -** Parameters: -** rconn - packet to be displayed. -** direct - direction packet is going (DIR_*). -** -** Returns: -** Nothing. -** -** Side Effects: -** None. -*/ -void -DispPkt(rconn, direct) - RMPCONN *rconn; - int direct; -{ - static char BootFmt[] = "\t\tRetCode:%u SeqNo:%lx SessID:%x Vers:%u"; - static char ReadFmt[] = "\t\tRetCode:%u Offset:%lx SessID:%x\n"; - - struct tm *tmp; - register struct rmp_packet *rmp; - int i, omask; - u_int t; - - /* - * Since we will be working with RmpConns as well as DbgFp, we - * must block signals that can affect either. - */ - omask = sigblock(sigmask(SIGHUP)|sigmask(SIGUSR1)|sigmask(SIGUSR2)); - - if (DbgFp == NULL) { /* sanity */ - (void) sigsetmask(omask); - return; - } - - /* display direction packet is going using '>>>' or '<<<' */ - fputs((direct==DIR_RCVD)?"<<< ":(direct==DIR_SENT)?">>> ":"", DbgFp); - - /* display packet timestamp */ - tmp = localtime((time_t *)&rconn->tstamp.tv_sec); - fprintf(DbgFp, "%02d:%02d:%02d.%06ld ", tmp->tm_hour, tmp->tm_min, - tmp->tm_sec, rconn->tstamp.tv_usec); - - /* display src or dst addr and information about network interface */ - fprintf(DbgFp, "Addr: %s Intf: %s\n", EnetStr(rconn), IntfName); - - rmp = &rconn->rmp; - - /* display IEEE 802.2 Logical Link Control header */ - (void) fprintf(DbgFp, "\t802.2 LLC: DSAP:%x SSAP:%x CTRL:%x\n", - rmp->hp_llc.dsap, rmp->hp_llc.ssap, rmp->hp_llc.cntrl); - - /* display HP extensions to 802.2 Logical Link Control header */ - (void) fprintf(DbgFp, "\tHP Ext: DXSAP:%x SXSAP:%x\n", - rmp->hp_llc.dxsap, rmp->hp_llc.sxsap); - - /* - * Display information about RMP packet using type field to - * determine what kind of packet this is. - */ - switch(rmp->r_type) { - case RMP_BOOT_REQ: /* boot request */ - (void) fprintf(DbgFp, "\tBoot Request:"); - GETWORD(rmp->r_brq.rmp_seqno, t); - if (rmp->r_brq.rmp_session == RMP_PROBESID) { - if (WORDZE(rmp->r_brq.rmp_seqno)) - fputs(" (Send Server ID)", DbgFp); - else - fprintf(DbgFp," (Send Filename #%u)",t); - } - (void) fputc('\n', DbgFp); - (void) fprintf(DbgFp, BootFmt, rmp->r_brq.rmp_retcode, - t, rmp->r_brq.rmp_session, - rmp->r_brq.rmp_version); - (void) fprintf(DbgFp, "\n\t\tMachine Type: "); - for (i = 0; i < RMP_MACHLEN; i++) - (void) fputc(rmp->r_brq.rmp_machtype[i], DbgFp); - DspFlnm(rmp->r_brq.rmp_flnmsize, &rmp->r_brq.rmp_flnm); - break; - case RMP_BOOT_REPL: /* boot reply */ - fprintf(DbgFp, "\tBoot Reply:\n"); - GETWORD(rmp->r_brpl.rmp_seqno, t); - (void) fprintf(DbgFp, BootFmt, rmp->r_brpl.rmp_retcode, - t, rmp->r_brpl.rmp_session, - rmp->r_brpl.rmp_version); - DspFlnm(rmp->r_brpl.rmp_flnmsize,&rmp->r_brpl.rmp_flnm); - break; - case RMP_READ_REQ: /* read request */ - (void) fprintf(DbgFp, "\tRead Request:\n"); - GETWORD(rmp->r_rrq.rmp_offset, t); - (void) fprintf(DbgFp, ReadFmt, rmp->r_rrq.rmp_retcode, - t, rmp->r_rrq.rmp_session); - (void) fprintf(DbgFp, "\t\tNoOfBytes: %u\n", - rmp->r_rrq.rmp_size); - break; - case RMP_READ_REPL: /* read reply */ - (void) fprintf(DbgFp, "\tRead Reply:\n"); - GETWORD(rmp->r_rrpl.rmp_offset, t); - (void) fprintf(DbgFp, ReadFmt, rmp->r_rrpl.rmp_retcode, - t, rmp->r_rrpl.rmp_session); - (void) fprintf(DbgFp, "\t\tNoOfBytesSent: %d\n", - rconn->rmplen - RMPREADSIZE(0)); - break; - case RMP_BOOT_DONE: /* boot complete */ - (void) fprintf(DbgFp, "\tBoot Complete:\n"); - (void) fprintf(DbgFp, "\t\tRetCode:%u SessID:%x\n", - rmp->r_done.rmp_retcode, - rmp->r_done.rmp_session); - break; - default: /* ??? */ - (void) fprintf(DbgFp, "\tUnknown Type:(%d)\n", - rmp->r_type); - } - (void) fputc('\n', DbgFp); - (void) fflush(DbgFp); - - (void) sigsetmask(omask); /* reset old signal mask */ -} - - -/* -** GetEtherAddr -- convert an RMP (Ethernet) address into a string. -** -** An RMP BOOT packet has been received. Look at the type field -** and process Boot Requests, Read Requests, and Boot Complete -** packets. Any other type will be dropped with a warning msg. -** -** Parameters: -** addr - array of RMP_ADDRLEN bytes. -** -** Returns: -** Pointer to static string representation of `addr'. -** -** Side Effects: -** None. -** -** Warnings: -** - The return value points to a static buffer; it must -** be copied if it's to be saved. -** - For speed, we assume a u_char consists of 8 bits. -*/ -char * -GetEtherAddr(addr) - u_char *addr; -{ - static char Hex[] = "0123456789abcdef"; - static char etherstr[RMP_ADDRLEN*3]; - register int i; - register char *cp1, *cp2; - - /* - * For each byte in `addr', convert it to ":". - * The last byte does not get a trailing `:' appended. - */ - i = 0; - cp1 = (char *)addr; - cp2 = etherstr; - for(;;) { - *cp2++ = Hex[*cp1 >> 4 & 0xf]; - *cp2++ = Hex[*cp1++ & 0xf]; - if (++i == RMP_ADDRLEN) - break; - *cp2++ = ':'; - } - *cp2 = '\0'; - - return(etherstr); -} - - -/* -** DispFlnm -- Print a string of bytes to DbgFp (often, a file name). -** -** Parameters: -** size - number of bytes to print. -** flnm - address of first byte. -** -** Returns: -** Nothing. -** -** Side Effects: -** - Characters are sent to `DbgFp'. -*/ -void -DspFlnm(size, flnm) - register u_int size; - register char *flnm; -{ - register int i; - - (void) fprintf(DbgFp, "\n\t\tFile Name (%d): <", size); - for (i = 0; i < size; i++) - (void) fputc(*flnm++, DbgFp); - (void) fputs(">\n", DbgFp); -} - - -/* -** NewClient -- allocate memory for a new CLIENT. -** -** Parameters: -** addr - RMP (Ethernet) address of new client. -** -** Returns: -** Ptr to new CLIENT or NULL if we ran out of memory. -** -** Side Effects: -** - Memory will be malloc'd for the new CLIENT. -** - If malloc() fails, a log message will be generated. -*/ -CLIENT * -NewClient(addr) - u_char *addr; -{ - CLIENT *ctmp; - - if ((ctmp = (CLIENT *) malloc(sizeof(CLIENT))) == NULL) { - syslog(LOG_ERR, "NewClient: out of memory (%s)", - GetEtherAddr(addr)); - return(NULL); - } - - bzero(ctmp, sizeof(CLIENT)); - bcopy(addr, &ctmp->addr[0], RMP_ADDRLEN); - return(ctmp); -} - -/* -** FreeClient -- free linked list of Clients. -** -** Parameters: -** None. -** -** Returns: -** Nothing. -** -** Side Effects: -** - All malloc'd memory associated with the linked list of -** CLIENTS will be free'd; `Clients' will be set to NULL. -** -** Warnings: -** - This routine must be called with SIGHUP blocked. -*/ -void -FreeClients() -{ - register CLIENT *ctmp; - - while (Clients != NULL) { - ctmp = Clients; - Clients = Clients->next; - FreeClient(ctmp); - } -} - -/* -** NewStr -- allocate memory for a character array. -** -** Parameters: -** str - null terminated character array. -** -** Returns: -** Ptr to new character array or NULL if we ran out of memory. -** -** Side Effects: -** - Memory will be malloc'd for the new character array. -** - If malloc() fails, a log message will be generated. -*/ -char * -NewStr(str) - char *str; -{ - char *stmp; - - if ((stmp = (char *)malloc((unsigned) (strlen(str)+1))) == NULL) { - syslog(LOG_ERR, "NewStr: out of memory (%s)", str); - return(NULL); - } - - (void) strcpy(stmp, str); - return(stmp); -} - -/* -** To save time, NewConn and FreeConn maintain a cache of one RMPCONN -** in `LastFree' (defined below). -*/ - -static RMPCONN *LastFree = NULL; - -/* -** NewConn -- allocate memory for a new RMPCONN connection. -** -** Parameters: -** rconn - initialization template for new connection. -** -** Returns: -** Ptr to new RMPCONN or NULL if we ran out of memory. -** -** Side Effects: -** - Memory may be malloc'd for the new RMPCONN (if not cached). -** - If malloc() fails, a log message will be generated. -*/ -RMPCONN * -NewConn(rconn) - RMPCONN *rconn; -{ - RMPCONN *rtmp; - - if (LastFree == NULL) { /* nothing cached; make a new one */ - if ((rtmp = (RMPCONN *) malloc(sizeof(RMPCONN))) == NULL) { - syslog(LOG_ERR, "NewConn: out of memory (%s)", - EnetStr(rconn)); - return(NULL); - } - } else { /* use the cached RMPCONN */ - rtmp = LastFree; - LastFree = NULL; - } - - /* - * Copy template into `rtmp', init file descriptor to `-1' and - * set ptr to next elem NULL. - */ - bcopy((char *)rconn, (char *)rtmp, sizeof(RMPCONN)); - rtmp->bootfd = -1; - rtmp->next = NULL; - - return(rtmp); -} - -/* -** FreeConn -- Free memory associated with an RMPCONN connection. -** -** Parameters: -** rtmp - ptr to RMPCONN to be free'd. -** -** Returns: -** Nothing. -** -** Side Effects: -** - Memory associated with `rtmp' may be free'd (or cached). -** - File desc associated with `rtmp->bootfd' will be closed. -*/ -void -FreeConn(rtmp) - register RMPCONN *rtmp; -{ - /* - * If the file descriptor is in use, close the file. - */ - if (rtmp->bootfd >= 0) { - (void) close(rtmp->bootfd); - rtmp->bootfd = -1; - } - - if (LastFree == NULL) /* cache for next time */ - rtmp = LastFree; - else /* already one cached; free this one */ - free((char *)rtmp); -} - -/* -** FreeConns -- free linked list of RMPCONN connections. -** -** Parameters: -** None. -** -** Returns: -** Nothing. -** -** Side Effects: -** - All malloc'd memory associated with the linked list of -** connections will be free'd; `RmpConns' will be set to NULL. -** - If LastFree is != NULL, it too will be free'd & NULL'd. -** -** Warnings: -** - This routine must be called with SIGHUP blocked. -*/ -void -FreeConns() -{ - register RMPCONN *rtmp; - - while (RmpConns != NULL) { - rtmp = RmpConns; - RmpConns = RmpConns->next; - FreeConn(rtmp); - } - - if (LastFree != NULL) { - free((char *)LastFree); - LastFree = NULL; - } -} - -/* -** AddConn -- Add a connection to the linked list of connections. -** -** Parameters: -** rconn - connection to be added. -** -** Returns: -** Nothing. -** -** Side Effects: -** - RmpConn will point to new connection. -** -** Warnings: -** - This routine must be called with SIGHUP blocked. -*/ -void -AddConn(rconn) - register RMPCONN *rconn; -{ - if (RmpConns != NULL) - rconn->next = RmpConns; - RmpConns = rconn; -} - -/* -** FindConn -- Find a connection in the linked list of connections. -** -** We use the RMP (Ethernet) address as the basis for determining -** if this is the same connection. According to the Remote Maint -** Protocol, we can only have one connection with any machine. -** -** Parameters: -** rconn - connection to be found. -** -** Returns: -** Matching connection from linked list or NULL if not found. -** -** Side Effects: -** None. -** -** Warnings: -** - This routine must be called with SIGHUP blocked. -*/ -RMPCONN * -FindConn(rconn) - register RMPCONN *rconn; -{ - register RMPCONN *rtmp; - - for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) - if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], - (char *)&rtmp->rmp.hp_hdr.saddr[0], RMP_ADDRLEN) == 0) - break; - - return(rtmp); -} - -/* -** RemoveConn -- Remove a connection from the linked list of connections. -** -** Parameters: -** rconn - connection to be removed. -** -** Returns: -** Nothing. -** -** Side Effects: -** - If found, an RMPCONN will cease to exist and it will -** be removed from the linked list. -** -** Warnings: -** - This routine must be called with SIGHUP blocked. -*/ -void -RemoveConn(rconn) - register RMPCONN *rconn; -{ - register RMPCONN *thisrconn, *lastrconn; - - if (RmpConns == rconn) { /* easy case */ - RmpConns = RmpConns->next; - FreeConn(rconn); - } else { /* must traverse linked list */ - lastrconn = RmpConns; /* set back ptr */ - thisrconn = lastrconn->next; /* set current ptr */ - while (thisrconn != NULL) { - if (rconn == thisrconn) { /* found it */ - lastrconn->next = thisrconn->next; - FreeConn(thisrconn); - break; - } - lastrconn = thisrconn; - thisrconn = thisrconn->next; - } - } -} diff --git a/rlogin.tproj/krcmd.c b/rlogin.tproj/krcmd.c index cdbba26..51c5a66 100644 --- a/rlogin.tproj/krcmd.c +++ b/rlogin.tproj/krcmd.c @@ -56,7 +56,7 @@ /* - * $Source: /cvs/Darwin/Commands/NeXT/network_cmds/rlogin.tproj/krcmd.c,v $ + * $Source: /cvs/Darwin/src/live/network_cmds/rlogin.tproj/krcmd.c,v $ * $Header: /mit/kerberos/ucb/mit/kcmd/RCS/krcmd.c,v 5.1 * 89/07/25 15:38:44 kfall Exp Locker: kfall $ * static char *rcsid_kcmd_c = diff --git a/route.tproj/Makefile b/route.tproj/Makefile index d1a9e0e..caea41c 100644 --- a/route.tproj/Makefile +++ b/route.tproj/Makefile @@ -1,5 +1,5 @@ # -# Generated by the NeXT Project Builder. +# Generated by the Apple Project Builder. # # NOTE: Do NOT change this file -- Project Builder maintains it. # @@ -14,7 +14,7 @@ PROJECT_TYPE = Tool HFILES = keywords.h -CFILES = ccitt_addr.c route.c +CFILES = route.c OTHERSRCS = Makefile.preamble Makefile Makefile.postamble Makefile.dist\ route.8 diff --git a/route.tproj/Makefile.dist b/route.tproj/Makefile.dist index f7de878..f33afb2 100644 --- a/route.tproj/Makefile.dist +++ b/route.tproj/Makefile.dist @@ -2,7 +2,7 @@ PROG= route MAN8= route.0 -SRCS= route.c ccitt_addr.c +SRCS= route.c CFLAGS+=-I. CLEANFILES+=keywords.h BINOWN= root diff --git a/route.tproj/Makefile.postamble b/route.tproj/Makefile.postamble index 670967c..f2c16fc 100644 --- a/route.tproj/Makefile.postamble +++ b/route.tproj/Makefile.postamble @@ -1 +1,4 @@ INSTALL_PERMISSIONS = 4555 # If set, 'install' chmod's executable to this +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 route.8 "$(DSTROOT)/usr/share/man/man8/route.8" diff --git a/route.tproj/Makefile.preamble b/route.tproj/Makefile.preamble index dc05194..7d9931c 100644 --- a/route.tproj/Makefile.preamble +++ b/route.tproj/Makefile.preamble @@ -1,2 +1,4 @@ OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include +OTHER_CFLAGS += -DINET6 -DIPSEC +AFTER_INSTALL += install-man-page diff --git a/route.tproj/PB.project b/route.tproj/PB.project index f27333b..2121dda 100644 --- a/route.tproj/PB.project +++ b/route.tproj/PB.project @@ -6,7 +6,7 @@ H_FILES = (keywords.h); M_FILES = (); OTHER_LIBS = (); - OTHER_LINKED = (ccitt_addr.c, route.c); + OTHER_LINKED = (route.c); OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, Makefile.dist, route.8); PRECOMPILED_HEADERS = (); PROJECT_HEADERS = (); diff --git a/route.tproj/ccitt_addr.c b/route.tproj/ccitt_addr.c deleted file mode 100644 index 9c57be3..0000000 --- a/route.tproj/ccitt_addr.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 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. - * - * @(#)ccitt_addr.c 8.2 (Berkeley) 4/28/95 - */ - -/* - * parse CCITT addresses - * - * Addresses must have the format: [hpr],x121address[,userdata][,protocol] - * items enclosed with square brackets are optional - * 'h' or 'p' means hi priority (packet size = 128; specific to Datapac - * and necessary only for X.25(76) and non-negotiating X.25(80) DTE's) - * 'r' means reverse charge (remote DTE pays for call). - * The x121address consists of an optional netid and dot, followed - * by a dte address. - * - * Frank Pronk - * The University of British Columbia - * Laboratory for Computational Vision - * Copyright (c) 1984 - */ - -#include -#include -#include - -static char *copychar (); - -ccitt_addr (addr, xp) -char *addr; -register struct sockaddr_x25 *xp; -{ - register char *p, *ap, *limit; - int havenet = 0; - - memset(xp, 0, sizeof (*xp)); - xp->x25_family = AF_CCITT; - xp->x25_len = sizeof(*xp); - p = addr; - - /* - * process optional priority and reverse charging flags - */ - - if (*p == 'p' || *p == 'r' || *p == 'h') { - while (*p == 'p' || *p == 'r' || *p == 'h') { - if (*p == 'p' || *p == 'h') - xp->x25_opts.op_psize = X25_PS128; - else if (*p == 'r') - xp->x25_opts.op_flags |= X25_REVERSE_CHARGE; - p++; - } - if (*p != ',') - return (0); - p++; - } - if (*p == '\0') - return (0); - - /* - * [network id:]X.121 address - */ - - ap = xp->x25_addr; - limit = ap + sizeof (xp->x25_addr) - 1; - while (*p) { - if (*p == ',') - break; - if (*p == '.' || *p == ':') { - if (havenet) - return (0); - havenet++; - xp->x25_net = atoi (xp->x25_addr); - p++; - ap = xp->x25_addr; - *ap = '\0'; - } - if (*p < '0' || *p > '9') - return (0); - if (ap >= limit) - return (0); - *ap++ = *p++; - } - if (*p == '\0') - return (1); - - /* - * optional user data, bytes 4 to 16 - */ - - p++; - ap = xp->x25_udata + 4; /* first four bytes are protocol id */ - limit = ap + sizeof (xp->x25_udata) - 4; - xp->x25_udlen = 4; - while (*p) { - if (*p == ',') - break; - if (ap >= limit) - return (0); - p = copychar (p, ap++); - xp->x25_udlen++; - } - if (xp->x25_udlen == 4) - xp->x25_udlen = 0; - if (*p == '\0') - return (1); - - p++; - ap = xp->x25_udata; /* protocol id */ - limit = ap + (xp->x25_udlen ? 4 : sizeof(xp->x25_udata)); - while (*p) { - if (*p == ',') - return (0); - if (ap >= limit) - return (0); - p = copychar (p, ap++); - } - if (xp->x25_udlen == 0) - xp->x25_udlen = ap - xp->x25_udata; - return (1); -} - -static char * -copychar (from, to) -register char *from, *to; -{ - register int n; - - if (*from != '\\' || from[1] < '0' || from[1] > '7') { - *to = *from++; - return (from); - } - n = *++from - '0'; - from++; - if (*from >= '0' && *from <= '7') { - register int n1; - - n = n*8 + *from++ - '0'; - if (*from >= '0' && *from <= '7' && (n1 = n*8 + *from-'0') < 256) { - n = n1; - from++; - } - } - *to = n; - return (from); -} diff --git a/route.tproj/keywords.h b/route.tproj/keywords.h index bb5eebd..84e5531 100644 --- a/route.tproj/keywords.h +++ b/route.tproj/keywords.h @@ -57,53 +57,57 @@ {"ifp", K_IFP}, #define K_INET 18 {"inet", K_INET}, -#define K_ISO 19 +#define K_INET6 19 + {"inet6", K_INET6}, +#define K_ISO 20 {"iso", K_ISO}, -#define K_LINK 20 +#define K_LINK 21 {"link", K_LINK}, -#define K_LOCK 21 +#define K_LLINFO 22 + {"llinfo", K_LLINFO}, +#define K_LOCK 23 {"lock", K_LOCK}, -#define K_LOCKREST 22 +#define K_LOCKREST 24 {"lockrest", K_LOCKREST}, -#define K_MASK 23 +#define K_MASK 25 {"mask", K_MASK}, -#define K_MONITOR 24 +#define K_MONITOR 26 {"monitor", K_MONITOR}, -#define K_MTU 25 +#define K_MTU 27 {"mtu", K_MTU}, -#define K_NET 26 +#define K_NET 28 {"net", K_NET}, -#define K_NETMASK 27 +#define K_NETMASK 29 {"netmask", K_NETMASK}, -#define K_NOSTATIC 28 +#define K_NOSTATIC 30 {"nostatic", K_NOSTATIC}, -#define K_OSI 29 +#define K_OSI 31 {"osi", K_OSI}, -#define K_PROTO1 30 +#define K_PREFIXLEN 32 + {"prefixlen", K_PREFIXLEN}, +#define K_PROTO1 33 {"proto1", K_PROTO1}, -#define K_PROTO2 31 +#define K_PROTO2 34 {"proto2", K_PROTO2}, -#define K_RECVPIPE 32 +#define K_RECVPIPE 35 {"recvpipe", K_RECVPIPE}, -#define K_REJECT 33 +#define K_REJECT 36 {"reject", K_REJECT}, -#define K_RTT 34 +#define K_RTT 37 {"rtt", K_RTT}, -#define K_RTTVAR 35 +#define K_RTTVAR 38 {"rttvar", K_RTTVAR}, -#define K_SA 36 +#define K_SA 39 {"sa", K_SA}, -#define K_SENDPIPE 37 +#define K_SENDPIPE 40 {"sendpipe", K_SENDPIPE}, -#define K_SSTHRESH 38 +#define K_SSTHRESH 41 {"ssthresh", K_SSTHRESH}, -#define K_STATIC 39 +#define K_STATIC 42 {"static", K_STATIC}, -#define K_X25 40 +#define K_X25 43 {"x25", K_X25}, -#define K_XNS 41 +#define K_XNS 44 {"xns", K_XNS}, -#define K_XRESOLVE 42 +#define K_XRESOLVE 45 {"xresolve", K_XRESOLVE}, -#define K_LLINFO 43 - {"llinfo", K_LLINFO}, diff --git a/route.tproj/route.8 b/route.tproj/route.8 index 62b9cfe..81f5e31 100644 --- a/route.tproj/route.8 +++ b/route.tproj/route.8 @@ -29,17 +29,18 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)route.8 8.4 (Berkeley) 6/1/94 +.\" @(#)route.8 8.3 (Berkeley) 3/19/94 +.\" $FreeBSD: src/sbin/route/route.8,v 1.17.2.7 2001/10/02 10:04:01 ru Exp $ .\" -.Dd June 1, 1994 +.Dd June 8, 2001 .Dt ROUTE 8 .Os BSD 4.4 .Sh NAME .Nm route -.Nd manually manipulate the routing tables. +.Nd manually manipulate the routing tables .Sh SYNOPSIS -.Nm route -.Op Fl nqv +.Nm +.Op Fl dnqtv .Ar command .Oo .Op Ar modifiers @@ -54,20 +55,21 @@ system routing table management daemon such as should tend to this task. .Pp The -.Nm route : +.Nm utility supports a limited number of general options, but a rich command language, enabling the user to specify any arbitrary request that could be delivered via the -programmatic interface discussed in +programmatic interface discussed in .Xr route 4 . .Pp -.Bl -tag -width Ds +The following options are available: +.Bl -tag -width indent .It Fl n -Bypasses attempts to print host and network names symbolically +Bypass attempts to print host and network names symbolically when reporting actions. (The process of translating between symbolic names and numerical equivalents can be quite time consuming, and may require correct operation of the network; thus it may be expedient -to forgo this, especially when attempting to repair networking operations), +to forget this, especially when attempting to repair networking operations). .It Fl v (verbose) Print additional details. .It Fl q @@ -75,7 +77,7 @@ Suppress all output. .El .Pp The -.Nm route : +.Nm utility provides six commands: .Pp .Bl -tag -width Fl -compact @@ -94,29 +96,33 @@ Continuously report any changes to the routing information base, routing lookup misses, or suspected network partitionings. .El .Pp -The monitor command has the syntax +The monitor command has the syntax: .Pp -.Bd -filled -offset indent -compact -.Nm route Op Fl n +.Bd -ragged -offset indent -compact +.Nm +.Op Fl n .Cm monitor .Ed .Pp -The flush command has the syntax +The flush command has the syntax: .Pp -.Bd -filled -offset indent -compact -.Nm route Op Fl n +.Bd -ragged -offset indent -compact +.Nm +.Op Fl n .Cm flush .Op Ar family .Ed .Pp -If the +If the .Cm flush -command is specified, -.Nm route +command is specified, +.Nm will ``flush'' the routing tables of all gateway entries. When the address family may is specified by any of the .Fl osi , .Fl xns , +.Fl atalk , +.Fl inet6 , or .Fl inet modifiers, only routes having destinations with addresses in the @@ -124,11 +130,13 @@ delineated family will be deleted. .Pp The other commands have the following syntax: .Pp -.Bd -filled -offset indent -compact -.Nm route Op Fl n +.Bd -ragged -offset indent -compact +.Nm +.Op Fl n .Ar command .Op Fl net No \&| Fl host .Ar destination gateway +.Op Ar netmask .Ed .Pp where @@ -138,21 +146,30 @@ is the destination host or network, is the next-hop intermediary via which packets should be routed. Routes to a particular host may be distinguished from those to a network by interpreting the Internet address specified as the -.Ar destination argument. +.Ar destination +argument. The optional modifiers .Fl net and .Fl host force the destination to be interpreted as a network or a host, respectively. -Otherwise, if the +Otherwise, if the .Ar destination -has a ``local address part'' of -INADDR_ANY , +has a +.Dq local address part +of +INADDR_ANY +.Pq Li 0.0.0.0 , or if the .Ar destination is the symbolic name of a network, then the route is assumed to be to a network; otherwise, it is presumed to be a route to a host. +Optionally, the +.Ar destination +could also be specified in the +.Ar net Ns / Ns Ar bits +format. .Pp For example, .Li 128.32 @@ -164,27 +181,43 @@ is interpreted as .Fl net Li 128.32 is interpreted as .Li 128.32.0.0; -and .Fl net Li 128.32.130 is interpreted as -.Li 128.32.130.0 . +.Li 128.32.130.0; +and +.Li 192.168.64/20 +is interpreted as +.Fl net Li 192.168.64 Fl netmask Li 255.255.240.0 . +.Pp +A +.Ar destination +of +.Ar default +is a synonym for +.Fl net Li 0.0.0.0 , +which is the default route. .Pp If the destination is directly reachable via an interface requiring -no intermediary system to act as a gateway, the +no intermediary system to act as a gateway, the .Fl interface modifier should be specified; the gateway given is the address of this host on the common network, indicating the interface to be used for transmission. +Alternately, if the interface is point to point the name of the interface +itself may be given, in which case the route remains valid even +if the local or remote addresses change. .Pp The optional modifiers .Fl xns , .Fl osi , and -.Fl link +.Fl link specify that all subsequent addresses are in the -.Tn XNS -.Tn OSI +.Tn XNS , +.Tn OSI , +or +.Tn AppleTalk address families, or are specified as link-level addresses, and the names must be numeric specifications rather than @@ -192,7 +225,7 @@ symbolic names. .Pp The optional .Fl netmask -qualifier is intended +modifier is intended to achieve the effect of an .Tn OSI .Tn ESIS @@ -205,6 +238,28 @@ One specifies an additional ensuing address parameter The implicit network mask generated in the AF_INET case can be overridden by making sure this option follows the destination parameter. .Pp +For +.Dv AF_INET6 , +the +.Fl prefixlen +qualifier +is available instead of the +.Fl mask +qualifier because non-continuous masks are not allowed in IPv6. +For example, +.Fl prefixlen Li 32 +specifies network mask of +.Li ffff:ffff:0000:0000:0000:0000:0000:0000 +to be used. +The default value of prefixlen is 64 to get along with +the aggregatable address. +But 0 is assumed if +.Cm default +is specified. +Note that the qualifier works only for +.Dv AF_INET6 +address family. +.Pp Routes have associated flags which influence operation of the protocols when sending to destinations matched by the routes. These flags may be set (or sometimes cleared) @@ -238,7 +293,7 @@ These may be individually locked by preceding each such modifier to be locked by the .Fl lock -meta-modifier, or one can +meta-modifier, or one can specify that all ensuing metrics may be locked by the .Fl lockrest meta-modifier. @@ -257,9 +312,19 @@ or .Fl ifa modifiers may be used to determine the interface or interface address. .Pp +The optional +.Fl proxy +modifier specifies that the +.Dv RTF_LLINFO +routing table entry is the +.Dq published (proxy-only) +.Tn ARP +entry, as reported by +.Xr arp 8 . +.Pp All symbolic names specified for a .Ar destination -or +or .Ar gateway are looked up first as a host name using .Xr gethostbyname 3 . @@ -269,51 +334,55 @@ is then used to interpret the name as that of a network. .Pp .Nm Route uses a routing socket and the new message types -RTM_ADD, -RTM_DELETE, -RTM_GET, +.Dv RTM_ADD , RTM_DELETE , RTM_GET , and -RTM_CHANGE. +.Dv RTM_CHANGE . As such, only the super-user may modify the routing tables. -.ne 1i .Sh DIAGNOSTICS -.Bl -tag -width Ds -.It Sy "add [host \&| network ] %s: gateway %s flags %x" +.Bl -diag +.It "add [host \&| network ] %s: gateway %s flags %x" The specified route is being added to the tables. The values printed are from the routing table entry supplied -in the +in the .Xr ioctl 2 call. If the gateway address used was not the primary address of the gateway (the first one returned by .Xr gethostbyname 3 ) , the gateway address is printed numerically as well as symbolically. -.It Sy "delete [ host &| network ] %s: gateway %s flags %x" +.It "delete [ host \&| network ] %s: gateway %s flags %x" As above, but when deleting an entry. -.It Sy "%s %s done" -When the +.It "%s %s done" +When the .Cm flush command is specified, each routing table entry deleted is indicated with a message of this form. -.It Sy "Network is unreachable" +.It "Network is unreachable" An attempt to add a route failed because the gateway listed was not on a directly-connected network. The next-hop gateway must be given. -.It Sy "not in table" +.It "not in table" A delete operation was attempted for an entry which wasn't present in the tables. -.It Sy "routing table overflow" +.It "routing table overflow" An add operation was attempted, but the system was low on resources and was unable to allocate memory to create the new entry. +.It "gateway uses the same route" +A +.Cm change +operation resulted in a route whose gateway uses the +same route as the one being changed. +The next-hop gateway should be reachable through a different route. .El +.Pp +.Ex -std .Sh SEE ALSO .Xr netintro 4 , .Xr route 4 , -.Xr esis 4 , -.Xr routed 8 , -.Xr XNSrouted 8 +.Xr arp 8 , +.Xr routed 8 .Sh HISTORY The .Nm @@ -321,5 +390,5 @@ command appeared in .Bx 4.2 . .Sh BUGS The first paragraph may have slightly exaggerated -.Xr routed Ns 's +.Xr routed 8 Ns 's abilities. diff --git a/route.tproj/route.c b/route.tproj/route.c index 9c53a27..4e8b4ee 100644 --- a/route.tproj/route.c +++ b/route.tproj/route.c @@ -65,7 +65,7 @@ static const char copyright[] = static char sccsid[] = "@(#)route.c 8.3 (Berkeley) 3/19/94"; #endif static const char rcsid[] = - "$Id: route.c,v 1.1.1.2 2000/01/11 01:49:18 wsanchez Exp $"; + "$Id: route.c,v 1.2 2002/03/05 20:35:16 lindak Exp $"; #endif /* not lint */ #include @@ -73,12 +73,13 @@ static const char rcsid[] = #include #include #include +#include #include #include #include #include -#ifdef AT +#ifndef __APPLE__ #include #endif #ifdef NS @@ -90,11 +91,13 @@ static const char rcsid[] = #include #include #include +#include #include #include #include #include #include +#include struct keytab { char *kt_cp; @@ -108,13 +111,17 @@ struct ortentry route; union sockunion { struct sockaddr sa; struct sockaddr_in sin; -#ifdef AT +#ifdef INET6 + struct sockaddr_in6 sin6; +#endif +#ifndef __APPLE__ struct sockaddr_at sat; #endif #ifdef NS struct sockaddr_ns sns; #endif struct sockaddr_dl sdl; + struct sockaddr_storage ss; /* added to avoid memory overrun */ } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; typedef union sockunion *sup; @@ -125,16 +132,16 @@ int iflag, verbose, aflen = sizeof (struct sockaddr_in); int locking, lockrest, debugonly; struct rt_metrics rt_metrics; u_long rtm_inits; -struct in_addr inet_makeaddr(); -#ifdef AT +#ifndef __APPLE__ int atalk_aton __P((const char *, struct at_addr *)); char *atalk_ntoa __P((struct at_addr)); #endif -char *routename(), *netname(); +const char *routename(), *netname(); void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf(); void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr(); int getaddr(), rtmsg(), x25_makemask(); -extern char *inet_ntoa(), *iso_ntoa(), *link_ntoa(); +int prefixlen(); +extern char *iso_ntoa(); void usage __P((const char *)); @@ -191,7 +198,7 @@ main(argc, argv) pid = getpid(); uid = getuid(); if (tflag) - s = open("/dev/null", O_WRONLY, 0); + s = open(_PATH_DEVNULL, O_WRONLY, 0); else s = socket(PF_ROUTE, SOCK_RAW, 0); if (s < 0) @@ -248,8 +255,12 @@ flushroutes(argc, argv) case K_INET: af = AF_INET; break; - -#ifdef +#ifdef INET6 + case K_INET6: + af = AF_INET6; + break; +#endif +#ifndef __APPLE__ case K_ATALK: af = AF_APPLETALK; break; @@ -314,14 +325,14 @@ bad: usage(*argv); struct sockaddr *sa = (struct sockaddr *)(rtm + 1); (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? routename(sa) : netname(sa)); - sa = (struct sockaddr *)(sa->sa_len + (char *)sa); + sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa); (void) printf("%-20.20s ", routename(sa)); (void) printf("done\n"); } } } -char * +const char * routename(sa) struct sockaddr *sa; { @@ -377,12 +388,47 @@ routename(sa) } break; } -#ifdef AT + +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 sin6; /* use static var for safety */ + int niflags = 0; +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#endif + + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + + return(line); + } +#endif +#ifndef __APPLE__ case AF_APPLETALK: (void) snprintf(line, sizeof(line), "atalk %s", atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); break; #endif + #ifdef NS case AF_NS: return (ns_print((struct sockaddr_ns *)sa)); @@ -409,7 +455,7 @@ routename(sa) * Return the name of the network whose address is given. * The address is assumed to be that of a net or subnet, not a host. */ -char * +const char * netname(sa) struct sockaddr *sa; { @@ -474,12 +520,48 @@ netname(sa) C(in.s_addr)); break; } -#ifdef AT + +#ifdef INET6 + case AF_INET6: + { + struct sockaddr_in6 sin6; /* use static var for safety */ + int niflags = 0; +#ifdef NI_WITHSCOPEID + niflags = NI_WITHSCOPEID; +#endif + + memset(&sin6, 0, sizeof(sin6)); + memcpy(&sin6, sa, sa->sa_len); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; +#ifdef __KAME__ + if (sa->sa_len == sizeof(struct sockaddr_in6) && + (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) && + sin6.sin6_scope_id == 0) { + sin6.sin6_scope_id = + ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); + sin6.sin6_addr.s6_addr[2] = 0; + sin6.sin6_addr.s6_addr[3] = 0; + } +#endif + if (nflag) + niflags |= NI_NUMERICHOST; + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, niflags) != 0) + strncpy(line, "invalid", sizeof(line)); + + return(line); + } +#endif + +#ifndef __APPLE__ case AF_APPLETALK: (void) snprintf(line, sizeof(line), "atalk %s", atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr)); break; #endif + #ifdef NS case AF_NS: return (ns_print((struct sockaddr_ns *)sa)); @@ -558,7 +640,13 @@ newroute(argc, argv) af = AF_INET; aflen = sizeof(struct sockaddr_in); break; -#ifdef AT +#ifdef INET6 + case K_INET6: + af = AF_INET6; + aflen = sizeof(struct sockaddr_in6); + break; +#endif +#ifndef __APPLE__ case K_ATALK: af = AF_APPLETALK; aflen = sizeof(struct sockaddr_at); @@ -581,11 +669,9 @@ newroute(argc, argv) case K_NOSTATIC: flags &= ~RTF_STATIC; break; - case K_LLINFO: flags |= RTF_LLINFO; break; - case K_LOCK: locking = 1; break; @@ -617,33 +703,50 @@ newroute(argc, argv) flags |= RTF_STATIC; break; case K_IFA: - argc--; + if (!--argc) + usage((char *)NULL); (void) getaddr(RTA_IFA, *++argv, 0); break; case K_IFP: - argc--; + if (!--argc) + usage((char *)NULL); (void) getaddr(RTA_IFP, *++argv, 0); break; case K_GENMASK: - argc--; + if (!--argc) + usage((char *)NULL); (void) getaddr(RTA_GENMASK, *++argv, 0); break; case K_GATEWAY: - argc--; + if (!--argc) + usage((char *)NULL); (void) getaddr(RTA_GATEWAY, *++argv, 0); break; case K_DST: - argc--; + if (!--argc) + usage((char *)NULL); ishost = getaddr(RTA_DST, *++argv, &hp); dest = *argv; break; case K_NETMASK: - argc--; + if (!--argc) + usage((char *)NULL); (void) getaddr(RTA_NETMASK, *++argv, 0); /* FALLTHROUGH */ case K_NET: forcenet++; break; + case K_PREFIXLEN: + if (!--argc) + usage((char *)NULL); + if (prefixlen(*++argv) == -1) { + forcenet = 0; + ishost = 1; + } else { + forcenet = 1; + ishost = 0; + } + break; case K_MTU: case K_HOPCOUNT: case K_EXPIRE: @@ -652,7 +755,8 @@ newroute(argc, argv) case K_SSTHRESH: case K_RTT: case K_RTTVAR: - argc--; + if (!--argc) + usage((char *)NULL); set_metric(*++argv, key); break; default: @@ -670,8 +774,15 @@ newroute(argc, argv) } } } - if (forcehost) + if (forcehost) { ishost = 1; +#ifdef INET6 + if (af == AF_INET6) { + rtm_addrs &= ~RTA_NETMASK; + memset((void *)&so_mask, 0, sizeof(so_mask)); + } +#endif + } if (forcenet) ishost = 0; flags |= RTF_UP; @@ -732,12 +843,12 @@ inet_makenetandmask(net, sin, bits) register char *cp; rtm_addrs |= RTA_NETMASK; - if (net == 0) - mask = addr = 0; - else if (bits) { + if (bits) { addr = net; mask = 0xffffffff << (32 - bits); - } else if (net < 128) { + } else if (net == 0) + mask = addr = 0; + else if (net < 128) { addr = net << IN_CLASSA_NSHIFT; mask = IN_CLASSA_NET; } else if (net < 65536) { @@ -779,18 +890,17 @@ getaddr(which, s, hpp) struct hostent **hpp; { register sup su; -#ifdef NS - struct ns_addr ns_addr(); -#endif struct hostent *hp; struct netent *np; u_long val; - char *q,qs; + char *q; + int afamily; /* local copy of af so we can change it */ if (af == 0) { af = AF_INET; aflen = sizeof(struct sockaddr_in); } + afamily = af; rtm_addrs |= which; switch (which) { case RTA_DST: @@ -799,46 +909,34 @@ getaddr(which, s, hpp) case RTA_GATEWAY: su = &so_gate; if (iflag) { - #define MAX_IFACES 400 - int sock; - struct ifreq iflist[MAX_IFACES]; - struct ifconf ifconf; - struct ifreq *ifr, *ifr_end; - struct sockaddr_dl *dl, *sdl = NULL; - - /* Get socket */ - if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - err(1, "socket"); - - /* Get interface list */ - ifconf.ifc_req = iflist; - ifconf.ifc_len = sizeof(iflist); - if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0) - err(1, "ioctl(SIOCGIFCONF)"); - close(sock); - - /* Look for this interface in the list */ - for (ifr = ifconf.ifc_req, - ifr_end = (struct ifreq *) - (ifconf.ifc_buf + ifconf.ifc_len); - ifr < ifr_end; - ifr = (struct ifreq *) ((char *) &ifr->ifr_addr - + ifr->ifr_addr.sa_len)) { - dl = (struct sockaddr_dl *)&ifr->ifr_addr; - if (ifr->ifr_addr.sa_family == AF_LINK - && (ifr->ifr_flags & IFF_POINTOPOINT) - && !strncmp(s, dl->sdl_data, dl->sdl_nlen) - && s[dl->sdl_nlen] == 0) { - sdl = dl; - break; - } - } + struct ifaddrs *ifap, *ifa; + struct sockaddr_dl *sdl = NULL; + + if (getifaddrs(&ifap)) + err(1, "getifaddrs"); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + + if (strcmp(s, ifa->ifa_name)) + continue; + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + } /* If we found it, then use it */ if (sdl) { - su->sdl = *sdl; - return(1); + /* + * Copy is safe since we have a + * sockaddr_storage member in sockunion{}. + * Note that we need to copy before calling + * freeifaddrs(). + */ + memcpy(&su->sdl, sdl, sdl->sdl_len); } + freeifaddrs(ifap); + if (sdl) + return(1); } break; case RTA_NETMASK: @@ -849,6 +947,7 @@ getaddr(which, s, hpp) break; case RTA_IFP: su = &so_ifp; + afamily = AF_LINK; break; case RTA_IFA: su = &so_ifa; @@ -858,7 +957,7 @@ getaddr(which, s, hpp) /*NOTREACHED*/ } su->sa.sa_len = aflen; - su->sa.sa_family = af; /* cases that don't want it have left already */ + su->sa.sa_family = afamily; /* cases that don't want it have left already */ if (strcmp(s, "default") == 0) { /* * Default is net 0.0.0.0/0 @@ -869,15 +968,44 @@ getaddr(which, s, hpp) /* bzero(su, sizeof(*su)); *//* for readability */ (void) getaddr(RTA_NETMASK, s, 0); break; -#if 0 case RTA_NETMASK: case RTA_GENMASK: /* bzero(su, sizeof(*su)); *//* for readability */ -#endif + break; } return (0); } - switch (af) { + switch (afamily) { +#ifdef INET6 + case AF_INET6: + { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = afamily; /*AF_INET6*/ + hints.ai_flags = AI_NUMERICHOST; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + if (getaddrinfo(s, "0", &hints, &res) != 0 || + res->ai_family != AF_INET6 || + res->ai_addrlen != sizeof(su->sin6)) { + (void) fprintf(stderr, "%s: bad value\n", s); + exit(1); + } + memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); +#ifdef __KAME__ + if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || + IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr)) && + su->sin6.sin6_scope_id) { + *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = + htons(su->sin6.sin6_scope_id); + su->sin6.sin6_scope_id = 0; + } +#endif + freeaddrinfo(res); + return (0); + } +#endif /* INET6 */ + #ifdef NS case AF_NS: if (which == RTA_DST) { @@ -893,13 +1021,15 @@ getaddr(which, s, hpp) return (!ns_nullhost(su->sns.sns_addr)); #endif -#ifdef AT + +#ifndef __APPLE__ case AF_APPLETALK: if (!atalk_aton(s, &su->sat.sat_addr)) errx(EX_NOHOST, "bad address: %s", s); rtm_addrs |= RTA_NETMASK; return(forcehost || su->sat.sat_addr.s_node != 0); #endif + case AF_LINK: link_addr(s, &su->sdl); return (1); @@ -921,31 +1051,30 @@ getaddr(which, s, hpp) q = strchr(s,'/'); if (q && which == RTA_DST) { - qs = *q; *q = '\0'; - if (((val = inet_addr(s)) != INADDR_NONE)) { + if ((val = inet_addr(s)) != INADDR_NONE) { inet_makenetandmask( - htonl(val), &su->sin, strtoul(q+1, 0, 0)); + ntohl(val), &su->sin, strtoul(q+1, 0, 0)); return (0); } - *q =qs; + *q = '/'; } - if (((val = inet_addr(s)) != INADDR_NONE) && - (which != RTA_DST || forcenet == 0)) { + if ((which != RTA_DST || forcenet == 0) && + (val = inet_addr(s)) != INADDR_NONE) { su->sin.sin_addr.s_addr = val; - if (inet_lnaof(su->sin.sin_addr) != INADDR_ANY) + if (which != RTA_DST || + inet_lnaof(su->sin.sin_addr) != INADDR_ANY) return (1); else { val = ntohl(val); goto netdone; } } - if ((val = inet_network(s)) != INADDR_NONE || - (forcehost == 0 && (np = getnetbyname(s)) != NULL && - (val = np->n_net) != 0)) { + if (which == RTA_DST && forcehost == 0 && + ((val = inet_network(s)) != INADDR_NONE || + ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) { netdone: - if (which == RTA_DST) - inet_makenetandmask(val, &su->sin, 0); + inet_makenetandmask(val, &su->sin, 0); return (0); } hp = gethostbyname(s); @@ -959,6 +1088,51 @@ netdone: errx(EX_NOHOST, "bad address: %s", s); } +int +prefixlen(s) + char *s; +{ + int len = atoi(s), q, r; + int max; + char *p; + + rtm_addrs |= RTA_NETMASK; + switch (af) { +#ifdef INET6 + case AF_INET6: + max = 128; + p = (char *)&so_mask.sin6.sin6_addr; + break; +#endif + case AF_INET: + max = 32; + p = (char *)&so_mask.sin.sin_addr; + break; + default: + (void) fprintf(stderr, "prefixlen not supported in this af\n"); + exit(1); + /*NOTREACHED*/ + } + + if (len < 0 || max < len) { + (void) fprintf(stderr, "%s: bad value\n", s); + exit(1); + } + + q = len >> 3; + r = len & 7; + so_mask.sa.sa_family = af; + so_mask.sa.sa_len = aflen; + memset((void *)p, 0, max / 8); + if (q > 0) + memset((void *)p, 0xff, q); + if (r > 0) + *((u_char *)p + q) = (0xff00 >> r) & 0xff; + if (len == max) + return -1; + else + return len; +} #ifdef NS short ns_nullh[] = {0,0,0}; @@ -1004,9 +1178,9 @@ ns_print(sns) else *cport = 0; - (void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s", - (unsigned long)ntohl(net.long_e), - host, cport); + (void) snprintf(mybuf, sizeof(mybuf), "%lxH.%s%s", + (unsigned long)ntohl(net.long_e), + host, cport); return (mybuf); } #endif @@ -1050,8 +1224,10 @@ monitor() exit(0); } for(;;) { + time_t now; n = read(s, msg, 2048); - (void) printf("got message of size %d\n", n); + now = time(NULL); + (void) printf("\ngot message of size %d on %s", n, ctime(&now)); print_rtmsg((struct rt_msghdr *)msg, n); } } @@ -1148,6 +1324,9 @@ mask_addr() case AF_NS: #endif case AF_INET: +#ifdef INET6 + case AF_INET6: +#endif case AF_APPLETALK: case 0: return; @@ -1360,8 +1539,10 @@ pmsg_addrs(cp, addrs) register struct sockaddr *sa; int i; - if (addrs == 0) + if (addrs == 0) { + (void) putchar('\n'); return; + } (void) printf("\nsockaddrs: "); bprintf(stdout, addrs, addrnames); (void) putchar('\n'); @@ -1429,7 +1610,7 @@ sodump(su, which) (void) printf("%s: inet %s; ", which, inet_ntoa(su->sin.sin_addr)); break; -#ifdef AT +#ifndef __APPLE__ case AF_APPLETALK: (void) printf("%s: atalk %s; ", which, atalk_ntoa(su->sat.sat_addr)); @@ -1498,7 +1679,7 @@ sockaddr(addr, sa) sa->sa_len = cp - (char *)sa; } -#ifdef AT +#ifndef __APPLE__ int atalk_aton(const char *text, struct at_addr *addr) { diff --git a/routed.tproj/Makefile b/routed.tproj/Makefile index 78e1951..00a172a 100644 --- a/routed.tproj/Makefile +++ b/routed.tproj/Makefile @@ -17,7 +17,7 @@ HFILES = af.h defs.h interface.h pathnames.h table.h trace.h CFILES = af.c defs.c if.c inet.c input.c main.c output.c startup.c\ tables.c timer.c trace.c -OTHERSRCS = Makefile.preamble Makefile Makefile.dist routed.8 +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble Makefile.dist routed.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/routed.tproj/Makefile.postamble b/routed.tproj/Makefile.postamble new file mode 100644 index 0000000..e615993 --- /dev/null +++ b/routed.tproj/Makefile.postamble @@ -0,0 +1,3 @@ +install-man-page: + install -d $(DSTROOT)/usr/share/man/man8 + install -c -m 444 routed.8 $(DSTROOT)/usr/share/man/man8/routed.8 diff --git a/routed.tproj/Makefile.preamble b/routed.tproj/Makefile.preamble index dc05194..eede713 100644 --- a/routed.tproj/Makefile.preamble +++ b/routed.tproj/Makefile.preamble @@ -1,2 +1,5 @@ OTHER_GENERATED_OFILES = $(VERS_OFILE) +AFTER_INSTALL += install-man-page -include ../Makefile.include + + diff --git a/routed.tproj/PB.project b/routed.tproj/PB.project index 23f9195..d1f16a2 100644 --- a/routed.tproj/PB.project +++ b/routed.tproj/PB.project @@ -18,7 +18,7 @@ timer.c, trace.c ); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.dist, routed.8); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, Makefile.dist, routed.8); SUBPROJECTS = (); }; LANGUAGE = English; diff --git a/routed.tproj/routed.8 b/routed.tproj/routed.8 index 8d9ea20..e45f9fe 100644 --- a/routed.tproj/routed.8 +++ b/routed.tproj/routed.8 @@ -1,3 +1,5 @@ +.\" $OpenBSD: routed.8,v 1.8 1997/01/28 07:16:41 deraadt Exp $ +.\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -31,324 +33,566 @@ .\" .\" @(#)routed.8 8.2 (Berkeley) 12/11/93 .\" -.Dd December 11, 1993 +.Dd June 1, 1996 .Dt ROUTED 8 -.Os BSD 4.2 +.Os BSD 4.4 .Sh NAME .Nm routed -.Nd network routing daemon +.Nd network RIP and router discovery routing daemon .Sh SYNOPSIS -.Nm routed -.Op Fl d -.Op Fl g -.Op Fl q -.Op Fl s -.Op Fl t -.Op Ar logfile +.Nm +.Op Fl sqdghmpAt +.Op Fl T Ar tracefile +.Oo +.Fl F +.Ar net Ns Op /mask Ns Op ,metric +.Oc +.OP Fl P Ar parms .Sh DESCRIPTION .Nm Routed -is invoked at boot time to manage the network routing tables. -The routing daemon uses a variant of the Xerox NS Routing -Information Protocol in maintaining up to date kernel routing -table entries. -It used a generalized protocol capable of use with multiple -address types, but is currently used only for Internet routing -within a cluster of networks. -.Pp -In normal operation -.Nm routed -listens on the +is a daemon invoked at boot time to manage the network +routing tables. +It uses Routing Information Protocol, RIPv1 (RFC\ 1058), +RIPv2 (RFC\ 1723), +and Internet Router Discovery Protocol (RFC 1256) +to maintain the kernel routing table. +The RIPv1 protocol is based on the reference 4.3BSD daemon. +.Pp +It listens on the .Xr udp 4 socket for the .Xr route 8 service (see .Xr services 5 ) -for routing information packets. If the host is an -internetwork router, it periodically supplies copies -of its routing tables to any directly connected hosts -and networks. +for Routing Information Protocol packets. +It also sends and receives multicast Router Discovery ICMP messages. +If the host is a router, +.Nm +periodically supplies copies +of its routing tables to any directly connected hosts and networks. +It also advertise or solicits default routes using Router Discovery +ICMP messages. .Pp -When -.Nm routed -is started, it uses the -.Dv SIOCGIFCONF -.Xr ioctl 2 -to find those +When started (or when a network interface is later turned on), +.Nm +uses an AF_ROUTE address family facility to find those directly connected interfaces configured into the -system and marked ``up'' (the software loopback interface -is ignored). If multiple interfaces -are present, it is assumed that the host will forward packets -between networks. -.Nm Routed -then transmits a -.Em request -packet on each interface (using a broadcast packet if -the interface supports it) and enters a loop, listening -for +system and marked "up". +It adds necessary routes for the interfaces +to the kernel routing table. +Soon after being first started, and provided there is at least one +interface on which RIP has not been disabled, +.Nm +deletes all pre-existing +non-static routes in kernel table. +Static routes in the kernel table are preserved and +included in RIP responses if they have a valid RIP metric +(see +.Xr route 8 ). +.Pp +If more than one interface is present (not counting the loopback interface), +it is assumed that the host should forward packets among the +connected networks. +After transmitting a RIP .Em request and -.Em response -packets from other hosts. +Router Discovery Advertisements or Solicitations on a new interface, +the daemon enters a loop, listening for +RIP request and response and Router Discover packets from other hosts. .Pp When a .Em request -packet is received, -.Nm routed +packet is received, +.Nm formulates a reply based on the information maintained in its -internal tables. The +internal tables. +The .Em response packet generated contains a list of known routes, each marked -with a ``hop count'' metric (a count of 16, or greater, is -considered ``infinite''). The metric associated with each -route returned provides a metric -.Em relative to the sender . +with a "hop count" metric (a count of 16 or greater is +considered "infinite"). +Advertised metrics reflect the metric associated with interface +(see +.Xr ifconfig 8 ), +so setting the metric on an interface +is an effective way to steer traffic. .Pp -.Em Response -packets received by -.Nm routed -are used to update the routing tables if one of the following -conditions is satisfied: -.Bl -enum -.It -No routing table entry exists for the destination network -or host, and the metric indicates the destination is ``reachable'' -(i.e. the hop count is not infinite). -.It -The source host of the packet is the same as the router in the -existing routing table entry. That is, updated information is -being received from the very internetwork router through which -packets for the destination are being routed. -.It -The existing entry in the routing table has not been updated for -some time (defined to be 90 seconds) and the route is at least -as cost effective as the current route. -.It -The new route describes a shorter route to the destination than -the one currently stored in the routing tables; the metric of -the new route is compared against the one stored in the table -to decide this. -.El +Responses do not contain routes with a first hop on the requesting +network to implement in part +.Em split-horizon . +Requests from query programs +such as +.Xr rtquery 8 +are answered with the complete table. +.Pp +The routing table maintained by the daemon +includes space for several gateways for each destination +to speed recovery from a failing router. +RIP +.Em response +packets received are used to update the routing tables provided they are +from one of the several currently recognized gateways or +advertise a better metric than at least one of the existing +gateways. .Pp When an update is applied, -.Nm routed -records the change in its internal tables and updates the kernel -routing table. -The change is reflected in the next +.Nm +records the change in its own tables and updates the kernel routing table +if the best route to the destination changes. +The change in the kernel routing table is reflected in the next batch of .Em response -packet sent. +packets sent. +If the next response is not scheduled for a while, a +.Em flash update +response containing only recently changed routes is sent. .Pp In addition to processing incoming packets, -.Nm routed +.Nm also periodically checks the routing table entries. If an entry has not been updated for 3 minutes, the entry's metric -is set to infinity and marked for deletion. Deletions are delayed -an additional 60 seconds to insure the invalidation is propagated -throughout the local internet. +is set to infinity and marked for deletion. +Deletions are delayed until the route has been advertised with +an infinite metric to insure the invalidation +is propagated throughout the local internet. +This is a form of +.Em poison reverse . +.Pp +Routes in the kernel table that are added or changed as a result +of ICMP Redirect messages are deleted after a while to minimize +.Em black-holes . +When a TCP connection suffers a timeout, +the kernel tells +.Nm routed , +which deletes all redirected routes +through the gateway involved, advances the age of all RIP routes through +the gateway to allow an alternate to be chosen, and advances of the +age of any relevant Router Discovery Protocol default routes. .Pp Hosts acting as internetwork routers gratuitously supply their routing tables every 30 seconds to all directly connected hosts and networks. -The response is sent to the broadcast address on nets capable of that function, +These RIP responses are sent to the broadcast address on nets that support +broadcasting, to the destination address on point-to-point links, and to the router's own address on other networks. -The normal routing tables are bypassed when sending gratuitous responses. -The reception of responses on each network is used to determine that the -network and interface are functioning correctly. -If no response is received on an interface, another route may be chosen -to route around the interface, or the route may be dropped if no alternative -is available. +If RIPv2 is enabled, multicast packets are sent on interfaces that +support multicasting. +.Pp +If no response is received on a remote interface, if there are errors +while sending responses, +or if there are more errors than input or output (see +.Xr netstat 8 ), +then the cable or some other part of the interface is assumed to be +disconnected or broken, and routes are adjusted appropriately. +.Pp +The +.Em Internet Router Discovery Protocol +is handled similarly. +When the daemon is supplying RIP routes, it also listens for +Router Discovery Solicitations and sends Advertisements. +When it is quiet and only listening to other RIP routers, it +sends Solicitations and listens for Advertisements. +If it receives +a good Advertisement, it stops listening for broadcast or multicast +RIP responses. +It tracks several advertising routers to speed recovery when the +currently chosen router dies. +If all discovered routers disappear, +the daemon resumes listening to RIP responses. +.Pp +While using Router Discovery (which happens by default when +the system has a single network interface and a Router Discover Advertisement +is received), there is a single default route and a variable number of +redirected host routes in the kernel table. +.Pp +The Router Discover standard requires that advertisements +have a default "lifetime" of 30 minutes. That means should +something happen, a client can be without a good route for +30 minutes. It is a good idea to reduce the default to 45 +seconds using +.Fl P Cm rdisc_interval=45 +on the command line or +.Cm rdisc_interval=45 +in the +.Pa /etc/gateways +file. +.Pp +See the +.Cm pm_rdisc +facility described below to support "legacy" systems +that can handle neither RIPv2 nor Router Discovery. +.Pp +By default, neither Router Discovery advertisements nor solicitations +are sent over point to point links (e.g. PPP). + .Pp Options supported by .Nm routed : .Bl -tag -width Ds +.It Fl s +this option forces +.Nm +to supply routing information. +This is the default if multiple network interfaces are present on which +RIP or Router Discovery have not been disabled, and if the kernel switch +ipforwarding=1. +.It Fl q +is the opposite of the +.Fl s +option. .It Fl d -Enable additional debugging information to be logged, -such as bad packets received. +Do not run in the background. +This option is meant for interactive use. .It Fl g This flag is used on internetwork routers to offer a route -to the ``default'' destination. +to the "default" destination. +It is equivalent to +.Fl F +.Cm 0/0,1 +and is present mostly for historical reasons. +A better choice is +.Fl P Cm pm_rdisc +on the command line or +.Cm pm_rdisc in the +.Pa /etc/gateways +file. +since a larger metric +will be used, reducing the spread of the potentially dangerous +default route. This is typically used on a gateway to the Internet, or on a gateway that uses another routing protocol whose routes are not reported to other local routers. -.It Fl s -Supplying this -option forces +Notice that because a metric of 1 is used, this feature is +dangerous. It is more commonly accidently used to create chaos with routing +loop than to solve problems. +.It Fl h +This causes host or point-to-point routes to not be advertised, +provided there is a network route going the same direction. +That is a limited kind of aggregation. +This option is useful on gateways to ethernets that have other gateway +machines connected with point-to-point links such as SLIP. +.It Fl m +This causes the machine to advertise a host or point-to-point route to +its primary interface. +It is useful on multi-homed machines such as NFS servers. +This option should not be used except when the cost of +the host routes it generates is justified by the popularity of +the server. +It is effective only when the machine is supplying +routing information, because there is more than one interface. +The +.Fl m +option overrides the +.Fl q +option to the limited extent of advertising the host route. +.It Fl A +do not ignore RIPv2 authentication if we do not care about RIPv2 +authentication. +This option is required for conformance with RFC 1723. +However, it makes no sense and breaks using RIP as a discovery protocol +to ignore all RIPv2 packets that carry authentication when this machine +does not care about authentication. +.It Fl T Ar tracefile +increases the debugging level to at least 1 and +causes debugging information to be appended to the trace file. +Note that because of security concerns, it is wisest to not run .Nm routed -to supply routing information whether it is acting as an internetwork -router or not. -This is the default if multiple network interfaces are present, -or if a point-to-point link is in use. -.It Fl q -This -is the opposite of the -.Fl s -option. +routinely with tracing directed to a file. .It Fl t -If the -.Fl t -option is specified, all packets sent or received are -printed on the standard output. In addition, -.Nm routed -will not divorce itself from the controlling terminal -so that interrupts from the keyboard will kill the process. +increases the debugging level, which causes more information to be logged +on the tracefile specified with +.Fl T +or standard out. +The debugging level can be increased or decreased +with the +.Em SIGUSR1 +or +.Em SIGUSR2 +signals or with the +.Xr rtquery +command. +.It Fl F Ar net[/mask][,metric] +minimize routes in transmissions via interfaces with addresses that match +.Em net/mask , +and synthesizes a default route to this machine with the +.Em metric . +The intent is to reduce RIP traffic on slow, point-to-point links +such as PPP links by replacing many large UDP packets of RIP information +with a single, small packet containing a "fake" default route. +If +.Em metric +is absent, a value of 14 is assumed to limit +the spread of the "fake" default route. + +This is a dangerous feature that when used carelessly can cause routing +loops. +Notice also that more than one interface can match the specified network +number and mask. +See also +.Fl g . +.It Fl P Ar parms +is equivalent to adding the parameter +line +.Em parms +to the +.Pa /etc/gateways +file. .El .Pp Any other argument supplied is interpreted as the name -of file in which -.Nm routed Ns \'s -actions should be logged. This log contains information -about any changes to the routing tables and, if not tracing all packets, -a history of recent messages sent and received which are related to -the changed route. -.Pp -In addition to the facilities described above, -.Nm routed -supports the notion of ``distant'' +of a file in which the actions of +.Nm +should be logged. +It is better to use +.Fl T +instead of +appending the name of the trace file to the command. +.Pp +.Nm +also supports the notion of +"distant" .Em passive -and +or .Em active -gateways. When -.Nm routed -is started up, it reads the file +gateways. +When +.Nm +is started, it reads the file .Pa /etc/gateways -to find gateways which may not be located using -only information from the -.Dv SIOGIFCONF -.Xr ioctl 2 . +to find such distant gateways which may not be located using +only information from a routing socket, to discover if some +of the local gateways are +.Em passive , +and to obtain other parameters. Gateways specified in this manner should be marked passive if they are not expected to exchange routing information, while gateways marked active -should be willing to exchange routing information (i.e. -they should have a -.Nm routed -process running on the machine). -Routes through passive gateways are installed in the -kernel's routing tables once upon startup. -Such routes are not included in -any routing information transmitted. -Active gateways are treated equally to network -interfaces. Routing information is distributed -to the gateway and if no routing information is -received for a period of time, the associated -route is deleted. +should be willing to exchange RIP packets. +Routes through +.Em passive +gateways are installed in the +kernel's routing tables once upon startup and are not included in +transmitted RIP responses. +.Pp +Distant active gateways are treated like network interfaces. +RIP responses are sent +to the distant +.Em active +gateway. +If no responses are received, the associated route is deleted from +the kernel table and RIP responses advertised via other interfaces. +If the distant gateway resumes sending RIP responses, the associated +route is restored. +.Pp +Such gateways can be useful on media that do not support broadcasts +or multicasts but otherwise act like classic shared media like +Ethernets such as some ATM networks. +One can list all RIP routers reachable on the ATM network in +.Pa /etc/gateways +with a series of +"host" lines. +.Pp Gateways marked .Em external are also passive, but are not placed in the kernel routing table nor are they included in routing updates. -The function of external entries is to inform -.Nm routed +The function of external entries is to indicate that another routing process -will install such a route, and that alternate routes to that destination -should not be installed. +will install such a route if necessary, +and that alternate routes to that destination should not be installed +by +.Nm routed . Such entries are only required when both routers may learn of routes to the same destination. .Pp -The +The .Pa /etc/gateways -is comprised of a series of lines, each in -the following format: +file is comprised of a series of lines, each in +one of the following formats or consist of parameters described below: +.Pp .Bd -ragged -.Pf < Cm net No \&| -.Cm host Ns > -.Ar name1 +.Cm net +.Ar Nname[/mask] .Cm gateway -.Ar name2 +.Ar Gname .Cm metric .Ar value .Pf < Cm passive No \&| .Cm active No \&| -.Cm external Ns > +.Cm extern Ns > .Ed -.Pp -The -.Cm net -or +.Bd -ragged .Cm host -keyword indicates if the route is to a network or specific host. +.Ar Hname +.Cm gateway +.Ar Gname +.Cm metric +.Ar value +.Pf < Cm passive No \&| +.Cm active No \&| +.Cm extern Ns > +.Ed .Pp -.Ar Name1 -is the name of the destination network or host. This may be a -symbolic name located in +.Ar Nname +or +.Ar Hname +is the name of the destination network or host. +It may be a symbolic network name or an Internet address +specified in "dot" notation (see +.Xr inet 3 ). +(If it is a name, then it must either be defined in .Pa /etc/networks or -.Pa /etc/hosts -(or, if started after +.Pa /etc/hosts , +or .Xr named 8 , -known to the name server), -or an Internet address specified in ``dot'' notation; see -.Xr inet 3 . +must have been started before +.Nm routed Ns .) +.Pp +.Ar mask +is an optional number between 1 and 32 indicating the netmask associated +with +.Ar Nname . .Pp -.Ar Name2 -is the name or address of the gateway to which messages should +.Ar Gname +is the name or address of the gateway to which RIP responses should be forwarded. .Pp .Ar Value -is a metric indicating the hop count to the destination host -or network. +is the hop count to the destination host or network. +.Ar " host hname " +is equivalent to +.Ar " net nname/32 ". .Pp One of the keywords .Cm passive , .Cm active or .Cm external -indicates if the gateway should be treated as -.Em passive +must be present to indicate whether the gateway should be treated as +.Cm passive or -.Em active +.Cm active (as described above), or whether the gateway is -.Em external -to the scope of the +.Cm external +to the scope of the RIP protocol. +.Pp +Lines that start with neither "net" nor "host" must consist of one +or more of the following parameter settings, separated by commas or +blanks: +.Bl -tag -width Ds +.It Cm if Ns \&= Ns Ar ifname +indicates that the other parameters on the line apply to the interface +name +.Ar ifname . +.It Cm subnet Ns \&= Ns Ar nname[/mask][,metric] +advertises a route to network +.Ar nname +with mask +.Ar mask +and the supplied metric (default 1). +This is useful for filling "holes" in CIDR allocations. +This parameter must appear by itself on a line. +.Pp +Do not use this feature unless necessary. It is dangerous. +.It Cm passwd Ns \&= Ns Ar XXX +specifies a RIPv2 password that will be included on all RIPv2 +responses sent and checked on all RIPv2 responses received. +The password must not contain any blanks, tab characters, commas +or '#' characters. +.It Cm no_ag +turns off aggregation of subnets in RIPv1 and RIPv2 responses. +.It Cm no_super_ag +turns off aggregation of networks into supernets in RIPv2 responses. +.It Cm passive +is equivalent +.Cm no_rip Cm no_rdisc . +.It Cm no_rip +disables all RIP processing on the specified interface. +If no interfaces are allowed to process RIP packets, +.Nm +acts purely as a router discovery daemon. +.Cm No_rip +is equivalent to +.Cm no_ripv1_in no_ripv2_in no_ripv1_out no_ripv2_out . + +Note that turning off RIP without explicitly turning on router +discovery advertisements with +.Cm rdisc_adv +or +.Fl s +causes .Nm routed -protocol. -.Pp -Internetwork routers that are directly attached to the Arpanet or Milnet -should use the Exterior Gateway Protocol -.Pq Tn EGP -to gather routing information -rather then using a static routing table of passive gateways. -.Tn EGP -is required in order to provide routes for local networks to the rest -of the Internet system. +to act as a client router discovery daemon, not advertising. +.It Cm no_ripv1_in +causes RIPv1 received responses to be ignored. +.It Cm no_ripv2_in +causes RIPv2 received responses to be ignored. +.It Cm ripv2_out +turns off RIPv1 output and causes RIPv2 advertisements to be +multicast when possible. +.It Cm no_rdisc +disables the Internet Router Discovery Protocol. +.It Cm no_solicit +disables the transmission of Router Discovery Solicitations. +.It Cm send_solicit +specifies that Router Discovery solicitations should be sent, +even on point-to-point links, +which by default only listen to Router Discovery messages. +.It Cm no_rdisc_adv +disables the transmission of Router Discovery Advertisements +.It Cm rdisc_adv +specifies that Router Discovery advertisements should be sent, +even on point-to-point links, +which by default only listen to Router Discovery messages +.It Cm bcast_rdisc +specifies that Router Discovery packets should be broadcast instead of +multicast. +.It Cm rdisc_pref Ns \&= Ns Ar N +sets the preference in Router Discovery Advertisements to the integer +.Ar N . +.It Cm rdisc_interval Ns \&= Ns Ar N +sets the nominal interval with which Router Discovery Advertisements +are transmitted to N seconds and their lifetime to 3*N. +.It Cm fake_default Ns \&= Ns Ar metric +has an identical effect to +.Fl F Ar net[/mask][,metric] +with the network and mask coming from the specified interface. +.It Cm pm_rdisc +is similar to +.Cm fake_default . +When RIPv2 routes are multicast, so that RIPv1 listeners cannot +receive them, this feature causes a RIPv1 default route to be +broadcast to RIPv1 listeners. +Unless modified with +.Cm fake_default , +the default route is broadcast with a metric of 14. +That serves as a "poor man's router discovery" protocol. +.El +.Pp +Note that the netmask associated with point-to-point links (such as SLIP +or PPP, with the IFF_POINTOPOINT flag) is used by +.Nm routed +to infer the netmask used by the remote system when RIPv1 is used. +.Pp .Sh FILES .Bl -tag -width /etc/gateways -compact .It Pa /etc/gateways for distant gateways .El .Sh SEE ALSO +.Xr gated 8 , .Xr udp 4 , .Xr icmp 4 , -.Xr XNSrouted 8 , -.Xr htable 8 +.Xr htable 8 , +.Xr rtquery 8 . .Rs .%T Internet Transport Protocols .%R XSIS 028112 .%Q Xerox System Integration Standard .Re .Sh BUGS -The kernel's routing tables may not correspond to those of -.Nm routed -when redirects change or add routes. -.Nm Routed -should note any redirects received by reading -the -.Tn ICMP -packets received via a raw socket. -.Pp -.Nm Routed -should incorporate other routing protocols, -such as Xerox -.Tn \&NS -.Pq Xr XNSrouted 8 -and -.Tn EGP . -Using separate processes for each requires configuration options -to avoid redundant or competing routes. -.Pp -.Nm Routed -should listen to intelligent interfaces, such as an -.Tn IMP , -to gather more information. It does not always detect unidirectional failures in network interfaces (e.g., when the output side fails). .Sh HISTORY diff --git a/rsh.tproj/rsh.c b/rsh.tproj/rsh.c index 9474164..8e290a2 100644 --- a/rsh.tproj/rsh.c +++ b/rsh.tproj/rsh.c @@ -56,8 +56,8 @@ /* - * $Source: /cvs/Darwin/Commands/NeXT/network_cmds/rsh.tproj/rsh.c,v $ - * $Header: /cvs/Darwin/Commands/NeXT/network_cmds/rsh.tproj/rsh.c,v 1.1.1.1 1999/05/02 03:58:17 wsanchez Exp $ + * $Source: /cvs/Darwin/src/live/network_cmds/rsh.tproj/rsh.c,v $ + * $Header: /cvs/Darwin/src/live/network_cmds/rsh.tproj/rsh.c,v 1.1.1.1 1999/05/02 03:58:17 wsanchez Exp $ */ #include diff --git a/ftpd.tproj/Makefile b/rtadvd.tproj/Makefile similarity index 68% rename from ftpd.tproj/Makefile rename to rtadvd.tproj/Makefile index 9f8a1d3..9a18eb3 100644 --- a/ftpd.tproj/Makefile +++ b/rtadvd.tproj/Makefile @@ -7,34 +7,32 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = ftpd +NAME = rtadvd PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -HFILES = ls.h ls_extern.h extern.h pathnames.h +CFILES = advcap.c config.c dump.c if.c rrenum.c rtadvd.c timer.c +HFILES = advcap.h config.h dump.h if.h pathnames.h rrenum.h rtadvd.h timer.h -OTHERLINKED = ftpcmd.y +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble \ + rtadvd.8 rtadvd.conf.5 rtadvd.conf -CFILES = ftpd.c logwtmp.c popen.c ls.c util.c cmp.c print.c - -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble ftpd.8 - -OTHERLINKEDOFILES = ftpcmd.o MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC MAKEFILE = tool.make -NEXTSTEP_INSTALLDIR = /usr/libexec -WINDOWS_INSTALLDIR = /usr/libexec -PDO_UNIX_INSTALLDIR = /usr/libexec -LIBS = +NEXTSTEP_INSTALLDIR = /usr/sbin +WINDOWS_INSTALLDIR = /usr/sbin +PDO_UNIX_INSTALLDIR = /usr/sbin DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) +NEXTSTEP_BUILD_OUTPUT_DIR = /$(USER)/BUILD + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc diff --git a/rtadvd.tproj/Makefile.postamble b/rtadvd.tproj/Makefile.postamble new file mode 100644 index 0000000..239664c --- /dev/null +++ b/rtadvd.tproj/Makefile.postamble @@ -0,0 +1,11 @@ +INSTALL_PERMISSIONS = 0555 # If set, 'install' chmod's executable to this +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 rtadvd.8 "$(DSTROOT)/usr/share/man/man8/rtadvd.8" + install -d "$(DSTROOT)/usr/share/man/man5" + install -c -m 644 rtadvd.conf.5 "$(DSTROOT)/usr/share/man/man5/rtadvd.conf.5" + +install-config-files: + install -d "$(DSTROOT)/private/etc" + install -c -m 644 rtadvd.conf "$(DSTROOT)/private/etc/rtadvd.conf" + diff --git a/rtadvd.tproj/Makefile.preamble b/rtadvd.tproj/Makefile.preamble new file mode 100644 index 0000000..f35d314 --- /dev/null +++ b/rtadvd.tproj/Makefile.preamble @@ -0,0 +1,4 @@ +OTHER_GENERATED_OFILES = $(VERS_OFILE) +-include ../Makefile.include +LOCAL_CFLAGS= -DINET6 -DHAVE_GETIFADDRS +AFTER_INSTALL += install-man-page install-config-files diff --git a/rtadvd.tproj/PB.project b/rtadvd.tproj/PB.project new file mode 100644 index 0000000..3a4c944 --- /dev/null +++ b/rtadvd.tproj/PB.project @@ -0,0 +1,31 @@ +{ + APPCLASS = NSApplication; + FILESTABLE = { + FRAMEWORKS = (); + H_FILES = (advcap.h, config.h, if.h, pathnames.h, rrenum.h, rtadvd.h, timer.h); + M_FILES = (); + OTHER_LIBS = (); + OTHER_LINKED = (advcap.c, config.c, dump.c, if.c, rrenum.c, rtadvd.c, timer.c); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, rtadvd.8, rtadvd.conf.5, rtadvd.conf); + SUBPROJECTS = (); + }; + LANGUAGE = English; + LOCALIZABLE_FILES = {}; + NEXTSTEP_BUILDDIR = "/$(USER)/BUILD"; + NEXTSTEP_BUILDTOOL = /bin/gnumake; + NEXTSTEP_INSTALLDIR = /usr/sbin; + NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; + NEXTSTEP_MAINNIB = rtadvd; + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; + PDO_UNIX_INSTALLDIR = /usr/sbin; + PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; + PDO_UNIX_MAINNIB = rtadvd; + PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; + PROJECTNAME = rtadvd; + PROJECTTYPE = Tool; + PROJECTVERSION = 2.8; + WINDOWS_INSTALLDIR = /usr/sbin; + WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; + WINDOWS_MAINNIB = rtadvd; + WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; +} diff --git a/rtadvd.tproj/advcap.c b/rtadvd.tproj/advcap.c new file mode 100644 index 0000000..2a52ff2 --- /dev/null +++ b/rtadvd.tproj/advcap.c @@ -0,0 +1,455 @@ +/* $KAME: advcap.c,v 1.5 2001/02/01 09:12:08 jinmei Exp $ */ + +/* + * Copyright (c) 1983 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/advcap.c,v 1.1.2.2 2001/07/03 11:02:13 ume Exp $ + */ + +/* + * remcap - routines for dealing with the remote host data base + * + * derived from termcap + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pathnames.h" + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif +#define MAXHOP 32 /* max number of tc= indirections */ + +#define tgetent agetent +#define tnchktc anchktc +#define tnamatch anamatch +#define tgetnum agetnum +#define tgetflag agetflag +#define tgetstr agetstr + +#if 0 +#define V_TERMCAP "REMOTE" +#define V_TERM "HOST" +#endif + +char *RM; + +/* + * termcap - routines for dealing with the terminal capability data base + * + * BUG: Should use a "last" pointer in tbuf, so that searching + * for capabilities alphabetically would not be a n**2/2 + * process when large numbers of capabilities are given. + * Note: If we add a last pointer now we will screw up the + * tc capability. We really should compile termcap. + * + * Essentially all the work here is scanning and decoding escapes + * in string capabilities. We don't use stdio because the editor + * doesn't, and because living w/o it is not hard. + */ + +static char *tbuf; +static int hopcount; /* detect infinite loops in termcap, init 0 */ + +static char *remotefile; + +extern char *conffile; + +int tgetent __P((char *, char *)); +int getent __P((char *, char *, char *)); +int tnchktc __P((void)); +int tnamatch __P((char *)); +static char *tskip __P((char *)); +long long tgetnum __P((char *)); +int tgetflag __P((char *)); +char *tgetstr __P((char *, char **)); +static char *tdecode __P((char *, char **)); + +/* + * Get an entry for terminal name in buffer bp, + * from the termcap file. Parse is very rudimentary; + * we just notice escaped newlines. + */ +int +tgetent(bp, name) + char *bp, *name; +{ + char *cp; + + remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF; + return (getent(bp, name, cp)); +} + +int +getent(bp, name, cp) + char *bp, *name, *cp; +{ + register int c; + register int i = 0, cnt = 0; + char ibuf[BUFSIZ]; + int tf; + + tbuf = bp; + tf = 0; + /* + * TERMCAP can have one of two things in it. It can be the + * name of a file to use instead of /etc/termcap. In this + * case it better start with a "/". Or it can be an entry to + * use so we don't have to read the file. In this case it + * has to already have the newlines crunched out. + */ + if (cp && *cp) { + tf = open(RM = cp, O_RDONLY); + } + if (tf < 0) { + syslog(LOG_INFO, + "<%s> open: %s", __FUNCTION__, strerror(errno)); + return (-2); + } + for (;;) { + cp = bp; + for (;;) { + if (i == cnt) { + cnt = read(tf, ibuf, BUFSIZ); + if (cnt <= 0) { + close(tf); + return (0); + } + i = 0; + } + c = ibuf[i++]; + if (c == '\n') { + if (cp > bp && cp[-1] == '\\') { + cp--; + continue; + } + break; + } + if (cp >= bp+BUFSIZ) { + write(2,"Remcap entry too long\n", 23); + break; + } else + *cp++ = c; + } + *cp = 0; + + /* + * The real work for the match. + */ + if (tnamatch(name)) { + close(tf); + return (tnchktc()); + } + } +} + +/* + * tnchktc: check the last entry, see if it's tc=xxx. If so, + * recursively find xxx and append that entry (minus the names) + * to take the place of the tc=xxx entry. This allows termcap + * entries to say "like an HP2621 but doesn't turn on the labels". + * Note that this works because of the left to right scan. + */ +int +tnchktc() +{ + register char *p, *q; + char tcname[16]; /* name of similar terminal */ + char tcbuf[BUFSIZ]; + char *holdtbuf = tbuf; + int l; + + p = tbuf + strlen(tbuf) - 2; /* before the last colon */ + while (*--p != ':') + if (p MAXHOP) { + write(2, "Infinite tc= loop\n", 18); + return (0); + } + if (getent(tcbuf, tcname, remotefile) != 1) { + return (0); + } + for (q = tcbuf; *q++ != ':'; ) + ; + l = p - holdtbuf + strlen(q); + if (l > BUFSIZ) { + write(2, "Remcap entry too long\n", 23); + q[BUFSIZ - (p-holdtbuf)] = 0; + } + strcpy(p, q); + tbuf = holdtbuf; + return (1); +} + +/* + * Tnamatch deals with name matching. The first field of the termcap + * entry is a sequence of names separated by |'s, so we compare + * against each such name. The normal : terminator after the last + * name (before the first field) stops us. + */ +int +tnamatch(np) + char *np; +{ + register char *Np, *Bp; + + Bp = tbuf; + if (*Bp == '#') + return (0); + for (;;) { + for (Np = np; *Np && *Bp == *Np; Bp++, Np++) + continue; + if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) + return (1); + while (*Bp && *Bp != ':' && *Bp != '|') + Bp++; + if (*Bp == 0 || *Bp == ':') + return (0); + Bp++; + } +} + +/* + * Skip to the next field. Notice that this is very dumb, not + * knowing about \: escapes or any such. If necessary, :'s can be put + * into the termcap file in octal. + */ +static char * +tskip(bp) + register char *bp; +{ + int dquote; + + dquote = 0; + while (*bp) { + switch (*bp) { + case ':': + if (!dquote) + goto breakbreak; + else + bp++; + break; + case '\\': + bp++; + if (isdigit(*bp)) { + while (isdigit(*bp++)) + ; + } else + bp++; + case '"': + dquote = (dquote ? 1 : 0); + bp++; + break; + default: + bp++; + break; + } + } +breakbreak: + if (*bp == ':') + bp++; + return (bp); +} + +/* + * Return the (numeric) option id. + * Numeric options look like + * li#80 + * i.e. the option string is separated from the numeric value by + * a # character. If the option is not found we return -1. + * Note that we handle octal numbers beginning with 0. + */ +long long +tgetnum(id) + char *id; +{ + register long long i; + register int base; + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (*bp == 0) + return (-1); + if (strncmp(bp, id, strlen(id)) != 0) + continue; + bp += strlen(id); + if (*bp == '@') + return (-1); + if (*bp != '#') + continue; + bp++; + base = 10; + if (*bp == '0') + base = 8; + i = 0; + while (isdigit(*bp)) + i *= base, i += *bp++ - '0'; + return (i); + } +} + +/* + * Handle a flag option. + * Flag options are given "naked", i.e. followed by a : or the end + * of the buffer. Return 1 if we find the option, or 0 if it is + * not given. + */ +int +tgetflag(id) + char *id; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (strncmp(bp, id, strlen(id)) == 0) { + bp += strlen(id); + if (!*bp || *bp == ':') + return (1); + else if (*bp == '@') + return (0); + } + } +} + +/* + * Get a string valued option. + * These are given as + * cl=^Z + * Much decoding is done on the strings, and the strings are + * placed in area, which is a ref parameter which is updated. + * No checking on area overflow. + */ +char * +tgetstr(id, area) + char *id, **area; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (strncmp(bp, id, strlen(id)) != 0) + continue; + bp += strlen(id); + if (*bp == '@') + return (0); + if (*bp != '=') + continue; + bp++; + return (tdecode(bp, area)); + } +} + +/* + * Tdecode does the grung work to decode the + * string capability escapes. + */ +static char * +tdecode(str, area) + register char *str; + char **area; +{ + register char *cp; + register int c; + register char *dp; + int i; + char term; + + term = ':'; + cp = *area; +again: + if (*str == '"') { + term = '"'; + str++; + } + while ((c = *str++) && c != term) { + switch (c) { + + case '^': + c = *str++ & 037; + break; + + case '\\': + dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\""; + c = *str++; +nextc: + if (*dp++ == c) { + c = *dp++; + break; + } + dp++; + if (*dp) + goto nextc; + if (isdigit(c)) { + c -= '0', i = 2; + do + c <<= 3, c |= *str++ - '0'; + while (--i && isdigit(*str)); + } + break; + } + *cp++ = c; + } + if (c == term && term != ':') { + term = ':'; + goto again; + } + *cp++ = 0; + str = *area; + *area = cp; + return (str); +} diff --git a/rtadvd.tproj/advcap.h b/rtadvd.tproj/advcap.h new file mode 100644 index 0000000..44d90e6 --- /dev/null +++ b/rtadvd.tproj/advcap.h @@ -0,0 +1,47 @@ +/* $KAME: advcap.h,v 1.3 2001/02/01 09:12:08 jinmei Exp $ */ + +/* + * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/advcap.h,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +/* Based on Id: termcap.h,v 1.8 1996/09/10 12:42:10 peter Exp */ + +#ifndef _ADVCAP_H_ +#define _ADVCAP_H_ + +#include + +__BEGIN_DECLS + +extern int agetent __P((char *, const char *)); +extern int agetflag __P((const char *)); +extern long long agetnum __P((const char *)); +extern char *agetstr __P((const char *, char **)); + +__END_DECLS + +#endif /* _ADVCAP_H_ */ diff --git a/rtadvd.tproj/config.c b/rtadvd.tproj/config.c new file mode 100644 index 0000000..bdcf5b7 --- /dev/null +++ b/rtadvd.tproj/config.c @@ -0,0 +1,987 @@ +/* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */ + +/* + * Copyright (C) 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/config.c,v 1.3.2.3 2001/07/03 11:02:14 ume Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif /* __FreeBSD__ >= 3 */ +#include +#include + +#include +#include +#include +#include +#include +#ifdef MIP6 +#include +#endif + +#include + +#include +#include +#include +#include +#include +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include +#endif +#include +#include + +#include "rtadvd.h" +#include "advcap.h" +#include "timer.h" +#include "if.h" +#include "config.h" + +static void makeentry __P((char *, int, char *, int)); +static void get_prefix __P((struct rainfo *)); +static int getinet6sysctl __P((int)); + +extern struct rainfo *ralist; + +void +getconfig(intface) + char *intface; +{ + int stat, pfxs, i; + char tbuf[BUFSIZ]; + struct rainfo *tmp; + long val; + long long val64; + char buf[BUFSIZ]; + char *bp = buf; + char *addr; + static int forwarding = -1; + +#define MUSTHAVE(var, cap) \ + do { \ + int t; \ + if ((t = agetnum(cap)) < 0) { \ + fprintf(stderr, "rtadvd: need %s for interface %s\n", \ + cap, intface); \ + exit(1); \ + } \ + var = t; \ + } while (0) +#define MAYHAVE(var, cap, def) \ + do { \ + if ((var = agetnum(cap)) < 0) \ + var = def; \ + } while (0) + + if ((stat = agetent(tbuf, intface)) <= 0) { + memset(tbuf, 0, sizeof(tbuf)); + syslog(LOG_INFO, + "<%s> %s isn't defined in the configuration file" + " or the configuration file doesn't exist." + " Treat it as default", + __FUNCTION__, intface); + } + + tmp = (struct rainfo *)malloc(sizeof(*ralist)); + memset(tmp, 0, sizeof(*tmp)); + tmp->prefix.next = tmp->prefix.prev = &tmp->prefix; + tmp->route.next = tmp->route.prev = &tmp->route; + + /* check if we are allowed to forward packets (if not determined) */ + if (forwarding < 0) { + if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0) + exit(1); + } + + /* get interface information */ + if (agetflag("nolladdr")) + tmp->advlinkopt = 0; + else + tmp->advlinkopt = 1; + if (tmp->advlinkopt) { + if ((tmp->sdl = if_nametosdl(intface)) == NULL) { + syslog(LOG_ERR, + "<%s> can't get information of %s", + __FUNCTION__, intface); + exit(1); + } + tmp->ifindex = tmp->sdl->sdl_index; + } else + tmp->ifindex = if_nametoindex(intface); + strncpy(tmp->ifname, intface, sizeof(tmp->ifname)); + if ((tmp->phymtu = if_getmtu(intface)) == 0) { + tmp->phymtu = IPV6_MMTU; + syslog(LOG_WARNING, + "<%s> can't get interface mtu of %s. Treat as %d", + __FUNCTION__, intface, IPV6_MMTU); + } + + /* + * set router configuration variables. + */ + MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL); + if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) { + syslog(LOG_ERR, + "<%s> maxinterval must be between %e and %u", + __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL); + exit(1); + } + tmp->maxinterval = (u_int)val; + MAYHAVE(val, "mininterval", tmp->maxinterval/3); + if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) { + syslog(LOG_ERR, + "<%s> mininterval must be between %e and %d", + __FUNCTION__, + MIN_MININTERVAL, + (tmp->maxinterval * 3) / 4); + exit(1); + } + tmp->mininterval = (u_int)val; + + MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT); + tmp->hoplimit = val & 0xff; + + MAYHAVE(val, "raflags", 0); + tmp->managedflg = val & ND_RA_FLAG_MANAGED; + tmp->otherflg = val & ND_RA_FLAG_OTHER; +#ifdef MIP6 + if (mobileip6) + tmp->haflg = val & ND_RA_FLAG_HA; +#endif +#ifndef ND_RA_FLAG_RTPREF_MASK +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ +#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ +#endif + tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) { + syslog(LOG_ERR, "<%s> invalid router preference on %s", + __FUNCTION__, intface); + exit(1); + } + + MAYHAVE(val, "rltime", tmp->maxinterval * 3); + if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) { + syslog(LOG_ERR, + "<%s> router lifetime on %s must be 0 or" + " between %d and %d", + __FUNCTION__, intface, + tmp->maxinterval, MAXROUTERLIFETIME); + exit(1); + } + /* + * Basically, hosts MUST NOT send Router Advertisement messages at any + * time (RFC 2461, Section 6.2.3). However, it would sometimes be + * useful to allow hosts to advertise some parameters such as prefix + * information and link MTU. Thus, we allow hosts to invoke rtadvd + * only when router lifetime (on every advertising interface) is + * explicitly set zero. (see also the above section) + */ + if (val && forwarding == 0) { + syslog(LOG_WARNING, + "<%s> non zero router lifetime is specified for %s, " + "which must not be allowed for hosts.", + __FUNCTION__, intface); + exit(1); + } + tmp->lifetime = val & 0xffff; + + MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME); + if (val > MAXREACHABLETIME) { + syslog(LOG_ERR, + "<%s> reachable time must be no greater than %d", + __FUNCTION__, MAXREACHABLETIME); + exit(1); + } + tmp->reachabletime = (u_int32_t)val; + + MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER); + if (val64 < 0 || val64 > 0xffffffff) { + syslog(LOG_ERR, + "<%s> retrans time out of range", __FUNCTION__); + exit(1); + } + tmp->retranstimer = (u_int32_t)val64; + +#ifndef MIP6 + if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { + syslog(LOG_ERR, + "<%s> mobile-ip6 configuration not supported", + __FUNCTION__); + exit(1); + } +#else + if (!mobileip6) { + if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) { + syslog(LOG_ERR, + "<%s> mobile-ip6 configuration without " + "proper command line option", + __FUNCTION__); + exit(1); + } + } else { + tmp->hapref = 0; + if ((val = agetnum("hapref")) >= 0) + tmp->hapref = (int16_t)val; + if (tmp->hapref != 0) { + tmp->hatime = 0; + MUSTHAVE(val, "hatime"); + tmp->hatime = (u_int16_t)val; + if (tmp->hatime <= 0) { + syslog(LOG_ERR, + "<%s> home agent lifetime must be greater than 0", + __FUNCTION__); + exit(1); + } + } + } +#endif + + /* prefix information */ + + /* + * This is an implementation specific parameter to consinder + * link propagation delays and poorly synchronized clocks when + * checking consistency of advertised lifetimes. + */ + MAYHAVE(val, "clockskew", 0); + tmp->clockskew = val; + + if ((pfxs = agetnum("addrs")) < 0) { + /* auto configure prefix information */ + if (agetstr("addr", &bp) || agetstr("addr1", &bp)) { + syslog(LOG_ERR, + "<%s> conflicting prefix configuration for %s: " + "automatic and manual config at the same time", + __FUNCTION__, intface); + exit(1); + } + get_prefix(tmp); + } + else { + tmp->pfxs = pfxs; + for (i = 0; i < pfxs; i++) { + struct prefix *pfx; + char entbuf[256]; + int added = (pfxs > 1) ? 1 : 0; + + /* allocate memory to store prefix information */ + if ((pfx = malloc(sizeof(struct prefix))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate enough memory", + __FUNCTION__); + exit(1); + } + memset(pfx, 0, sizeof(*pfx)); + + /* link into chain */ + insque(pfx, &tmp->prefix); + + pfx->origin = PREFIX_FROM_CONFIG; + + makeentry(entbuf, i, "prefixlen", added); + MAYHAVE(val, entbuf, 64); + if (val < 0 || val > 128) { + syslog(LOG_ERR, + "<%s> prefixlen out of range", + __FUNCTION__); + exit(1); + } + pfx->prefixlen = (int)val; + + makeentry(entbuf, i, "pinfoflags", added); +#ifdef MIP6 + if (mobileip6) + { + MAYHAVE(val, entbuf, + (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO| + ND_OPT_PI_FLAG_ROUTER)); + } else +#endif + { + MAYHAVE(val, entbuf, + (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO)); + } + pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK; + pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO; +#ifdef MIP6 + pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER; +#endif + + makeentry(entbuf, i, "vltime", added); + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { + syslog(LOG_ERR, + "<%s> vltime out of range", + __FUNCTION__); + exit(1); + } + pfx->validlifetime = (u_int32_t)val64; + + makeentry(entbuf, i, "vltimedecr", added); + if (agetflag(entbuf)) { + struct timeval now; + gettimeofday(&now, 0); + pfx->vltimeexpire = + now.tv_sec + pfx->validlifetime; + } + + makeentry(entbuf, i, "pltime", added); + MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { + syslog(LOG_ERR, + "<%s> pltime out of range", + __FUNCTION__); + exit(1); + } + pfx->preflifetime = (u_int32_t)val64; + + makeentry(entbuf, i, "pltimedecr", added); + if (agetflag(entbuf)) { + struct timeval now; + gettimeofday(&now, 0); + pfx->pltimeexpire = + now.tv_sec + pfx->preflifetime; + } + + makeentry(entbuf, i, "addr", added); + addr = (char *)agetstr(entbuf, &bp); + if (addr == NULL) { + syslog(LOG_ERR, + "<%s> need %s as an prefix for " + "interface %s", + __FUNCTION__, entbuf, intface); + exit(1); + } + if (inet_pton(AF_INET6, addr, + &pfx->prefix) != 1) { + syslog(LOG_ERR, + "<%s> inet_pton failed for %s", + __FUNCTION__, addr); + exit(1); + } + if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) { + syslog(LOG_ERR, + "<%s> multicast prefix(%s) must " + "not be advertised (IF=%s)", + __FUNCTION__, addr, intface); + exit(1); + } + if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix)) + syslog(LOG_NOTICE, + "<%s> link-local prefix(%s) will be" + " advertised on %s", + __FUNCTION__, addr, intface); + } + } + + MAYHAVE(val, "mtu", 0); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> mtu out of range", __FUNCTION__); + exit(1); + } + tmp->linkmtu = (u_int32_t)val; + if (tmp->linkmtu == 0) { + char *mtustr; + + if ((mtustr = (char *)agetstr("mtu", &bp)) && + strcmp(mtustr, "auto") == 0) + tmp->linkmtu = tmp->phymtu; + } + else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) { + syslog(LOG_ERR, + "<%s> advertised link mtu must be between" + " least MTU and physical link MTU", + __FUNCTION__); + exit(1); + } + + /* route information */ + + MAYHAVE(val, "routes", 0); + if (val < 0 || val > 0xffffffff) { + syslog(LOG_ERR, + "<%s> number of route information improper", __FUNCTION__); + exit(1); + } + tmp->routes = val; + for (i = 0; i < tmp->routes; i++) { + struct rtinfo *rti; + char entbuf[256]; + int added = (tmp->routes > 1) ? 1 : 0; + + /* allocate memory to store prefix information */ + if ((rti = malloc(sizeof(struct rtinfo))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate enough memory", + __FUNCTION__); + exit(1); + } + memset(rti, 0, sizeof(*rti)); + + /* link into chain */ + insque(rti, &tmp->route); + + makeentry(entbuf, i, "rtrplen", added); + MAYHAVE(val, entbuf, 64); + if (val < 0 || val > 128) { + syslog(LOG_ERR, + "<%s> prefixlen out of range", + __FUNCTION__); + exit(1); + } + rti->prefixlen = (int)val; + + makeentry(entbuf, i, "rtrflags", added); + MAYHAVE(val, entbuf, 0); + rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK; + if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) { + syslog(LOG_ERR, "<%s> invalid router preference", + __FUNCTION__); + exit(1); + } + + makeentry(entbuf, i, "rtrltime", added); + /* + * XXX: since default value of route lifetime is not defined in + * draft-draves-route-selection-01.txt, I took the default + * value of valid lifetime of prefix as its default. + * It need be much considered. + */ + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (val64 < 0 || val64 > 0xffffffff) { + syslog(LOG_ERR, + "<%s> rtrltime out of range", + __FUNCTION__); + exit(1); + } + rti->ltime = (u_int32_t)val64; + + makeentry(entbuf, i, "rtrprefix", added); + addr = (char *)agetstr(entbuf, &bp); + if (addr == NULL) { + syslog(LOG_ERR, + "<%s> need %s as an route for " + "interface %s", + __FUNCTION__, entbuf, intface); + exit(1); + } + if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) { + syslog(LOG_ERR, + "<%s> inet_pton failed for %s", + __FUNCTION__, addr); + exit(1); + } +#if 0 + /* + * XXX: currently there's no restriction in route information + * prefix according to draft-draves-route-selection-01.txt, + * however I think the similar restriction be necessary. + */ + MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME); + if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) { + syslog(LOG_ERR, + "<%s> multicast route (%s) must " + "not be advertised (IF=%s)", + __FUNCTION__, addr, intface); + exit(1); + } + if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) { + syslog(LOG_NOTICE, + "<%s> link-local route (%s) must " + "not be advertised on %s", + __FUNCTION__, addr, intface); + exit(1); + } +#endif + } + + /* okey */ + tmp->next = ralist; + ralist = tmp; + + /* construct the sending packet */ + make_packet(tmp); + + /* set timer */ + tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update, + tmp, tmp); + ra_timer_update((void *)tmp, &tmp->timer->tm); + rtadvd_set_timer(&tmp->timer->tm, tmp->timer); +} + +static void +get_prefix(struct rainfo *rai) +{ + struct ifaddrs *ifap, *ifa; + struct prefix *pp; + struct in6_addr *a; + u_char *p, *ep, *m, *lim; + u_char ntopbuf[INET6_ADDRSTRLEN]; + + if (getifaddrs(&ifap) < 0) { + syslog(LOG_ERR, + "<%s> can't get interface addresses", + __FUNCTION__); + exit(1); + } + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, rai->ifname) != 0) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr; + if (IN6_IS_ADDR_LINKLOCAL(a)) + continue; + + /* allocate memory to store prefix info. */ + if ((pp = malloc(sizeof(*pp))) == NULL) { + syslog(LOG_ERR, + "<%s> can't get allocate buffer for prefix", + __FUNCTION__); + exit(1); + } + memset(pp, 0, sizeof(*pp)); + + /* set prefix length */ + m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr; + lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len; + pp->prefixlen = prefixlen(m, lim); + if (pp->prefixlen < 0 || pp->prefixlen > 128) { + syslog(LOG_ERR, + "<%s> failed to get prefixlen " + "or prefix is invalid", + __FUNCTION__); + exit(1); + } + + /* set prefix, sweep bits outside of prefixlen */ + memcpy(&pp->prefix, a, sizeof(*a)); + p = (u_char *)&pp->prefix; + ep = (u_char *)(&pp->prefix + 1); + while (m < lim) + *p++ &= *m++; + while (p < ep) + *p++ = 0x00; + + if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf, + sizeof(ntopbuf))) { + syslog(LOG_ERR, "<%s> inet_ntop failed", __FUNCTION__); + exit(1); + } + syslog(LOG_DEBUG, + "<%s> add %s/%d to prefix list on %s", + __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname); + + /* set other fields with protocol defaults */ + pp->validlifetime = DEF_ADVVALIDLIFETIME; + pp->preflifetime = DEF_ADVPREFERREDLIFETIME; + pp->onlinkflg = 1; + pp->autoconfflg = 1; + pp->origin = PREFIX_FROM_KERNEL; + + /* link into chain */ + insque(pp, &rai->prefix); + + /* counter increment */ + rai->pfxs++; + } + + freeifaddrs(ifap); +} + +static void +makeentry(buf, id, string, add) + char *buf, *string; + int id, add; +{ + strcpy(buf, string); + if (add) { + char *cp; + + cp = (char *)index(buf, '\0'); + cp += sprintf(cp, "%d", id); + *cp = '\0'; + } +} + +/* + * Add a prefix to the list of specified interface and reconstruct + * the outgoing packet. + * The prefix must not be in the list. + * XXX: other parameter of the prefix(e.g. lifetime) shoule be + * able to be specified. + */ +static void +add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr) +{ + struct prefix *prefix; + u_char ntopbuf[INET6_ADDRSTRLEN]; + + if ((prefix = malloc(sizeof(*prefix))) == NULL) { + syslog(LOG_ERR, "<%s> memory allocation failed", + __FUNCTION__); + return; /* XXX: error or exit? */ + } + memset(prefix, 0, sizeof(*prefix)); + prefix->prefix = ipr->ipr_prefix.sin6_addr; + prefix->prefixlen = ipr->ipr_plen; + prefix->validlifetime = ipr->ipr_vltime; + prefix->preflifetime = ipr->ipr_pltime; + prefix->onlinkflg = ipr->ipr_raf_onlink; + prefix->autoconfflg = ipr->ipr_raf_auto; + prefix->origin = PREFIX_FROM_DYNAMIC; + + insque(prefix, &rai->prefix); + + syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s", + __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + ipr->ipr_plen, rai->ifname); + + /* free the previous packet */ + free(rai->ra_data); + rai->ra_data = NULL; + + /* reconstruct the packet */ + rai->pfxs++; + make_packet(rai); + + /* + * reset the timer so that the new prefix will be advertised quickly. + */ + rai->initcounter = 0; + ra_timer_update((void *)rai, &rai->timer->tm); + rtadvd_set_timer(&rai->timer->tm, rai->timer); +} + +/* + * Delete a prefix to the list of specified interface and reconstruct + * the outgoing packet. + * The prefix must be in the list. + */ +void +delete_prefix(struct rainfo *rai, struct prefix *prefix) +{ + u_char ntopbuf[INET6_ADDRSTRLEN]; + + remque(prefix); + syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s", + __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix, + ntopbuf, INET6_ADDRSTRLEN), + prefix->prefixlen, rai->ifname); + free(prefix); + rai->pfxs--; + make_packet(rai); +} + +/* + * Try to get an in6_prefixreq contents for a prefix which matches + * ipr->ipr_prefix and ipr->ipr_plen and belongs to + * the interface whose name is ipr->ipr_name[]. + */ +static int +init_prefix(struct in6_prefixreq *ipr) +{ + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + + if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) { + syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__, + strerror(errno)); + + ipr->ipr_vltime = DEF_ADVVALIDLIFETIME; + ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME; + ipr->ipr_raf_onlink = 1; + ipr->ipr_raf_auto = 1; + /* omit other field initialization */ + } + else if (ipr->ipr_origin < PR_ORIG_RR) { + u_char ntopbuf[INET6_ADDRSTRLEN]; + + syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is" + "lower than PR_ORIG_RR(router renumbering)." + "This should not happen if I am router", __FUNCTION__, + inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf, + sizeof(ntopbuf)), ipr->ipr_origin); + close(s); + return 1; + } + + close(s); + return 0; +} + +void +make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen) +{ + struct in6_prefixreq ipr; + + memset(&ipr, 0, sizeof(ipr)); + if (if_indextoname(ifindex, ipr.ipr_name) == NULL) { + syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't" + "exist. This should not happen! %s", __FUNCTION__, + ifindex, strerror(errno)); + exit(1); + } + ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix); + ipr.ipr_prefix.sin6_family = AF_INET6; + ipr.ipr_prefix.sin6_addr = *addr; + ipr.ipr_plen = plen; + + if (init_prefix(&ipr)) + return; /* init failed by some error */ + add_prefix(rai, &ipr); +} + +void +make_packet(struct rainfo *rainfo) +{ + size_t packlen, lladdroptlen = 0; + char *buf; + struct nd_router_advert *ra; + struct nd_opt_prefix_info *ndopt_pi; + struct nd_opt_mtu *ndopt_mtu; +#ifdef MIP6 + struct nd_opt_advinterval *ndopt_advint; + struct nd_opt_homeagent_info *ndopt_hai; +#endif + struct nd_opt_route_info *ndopt_rti; + struct prefix *pfx; + struct rtinfo *rti; + + /* calculate total length */ + packlen = sizeof(struct nd_router_advert); + if (rainfo->advlinkopt) { + if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) { + syslog(LOG_INFO, + "<%s> link-layer address option has" + " null length on %s." + " Treat as not included.", + __FUNCTION__, rainfo->ifname); + rainfo->advlinkopt = 0; + } + packlen += lladdroptlen; + } + if (rainfo->pfxs) + packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; + if (rainfo->linkmtu) + packlen += sizeof(struct nd_opt_mtu); +#ifdef MIP6 + if (mobileip6 && rainfo->maxinterval) + packlen += sizeof(struct nd_opt_advinterval); + if (mobileip6 && rainfo->hatime) + packlen += sizeof(struct nd_opt_homeagent_info); +#endif +#ifdef ND_OPT_ROUTE_INFO + for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) + packlen += sizeof(struct nd_opt_route_info) + + ((rti->prefixlen + 0x3f) >> 6) * 8; +#endif + + /* allocate memory for the packet */ + if ((buf = malloc(packlen)) == NULL) { + syslog(LOG_ERR, + "<%s> can't get enough memory for an RA packet", + __FUNCTION__); + exit(1); + } + if (rainfo->ra_data) { + /* free the previous packet */ + free(rainfo->ra_data); + rainfo->ra_data = NULL; + } + rainfo->ra_data = buf; + /* XXX: what if packlen > 576? */ + rainfo->ra_datalen = packlen; + + /* + * construct the packet + */ + ra = (struct nd_router_advert *)buf; + ra->nd_ra_type = ND_ROUTER_ADVERT; + ra->nd_ra_code = 0; + ra->nd_ra_cksum = 0; + ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit); + ra->nd_ra_flags_reserved = 0; /* just in case */ + /* + * XXX: the router preference field, which is a 2-bit field, should be + * initialized before other fields. + */ + ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref; + ra->nd_ra_flags_reserved |= + rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0; + ra->nd_ra_flags_reserved |= + rainfo->otherflg ? ND_RA_FLAG_OTHER : 0; +#ifdef MIP6 + ra->nd_ra_flags_reserved |= + rainfo->haflg ? ND_RA_FLAG_HA : 0; +#endif + ra->nd_ra_router_lifetime = htons(rainfo->lifetime); + ra->nd_ra_reachable = htonl(rainfo->reachabletime); + ra->nd_ra_retransmit = htonl(rainfo->retranstimer); + buf += sizeof(*ra); + + if (rainfo->advlinkopt) { + lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf); + buf += lladdroptlen; + } + + if (rainfo->linkmtu) { + ndopt_mtu = (struct nd_opt_mtu *)buf; + ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU; + ndopt_mtu->nd_opt_mtu_len = 1; + ndopt_mtu->nd_opt_mtu_reserved = 0; + ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu); + buf += sizeof(struct nd_opt_mtu); + } + +#ifdef MIP6 + if (mobileip6 && rainfo->maxinterval) { + ndopt_advint = (struct nd_opt_advinterval *)buf; + ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL; + ndopt_advint->nd_opt_adv_len = 1; + ndopt_advint->nd_opt_adv_reserved = 0; + ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval * + 1000); + buf += sizeof(struct nd_opt_advinterval); + } +#endif + +#ifdef MIP6 + if (rainfo->hatime) { + ndopt_hai = (struct nd_opt_homeagent_info *)buf; + ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO; + ndopt_hai->nd_opt_hai_len = 1; + ndopt_hai->nd_opt_hai_reserved = 0; + ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref); + ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime); + buf += sizeof(struct nd_opt_homeagent_info); + } +#endif + + for (pfx = rainfo->prefix.next; + pfx != &rainfo->prefix; pfx = pfx->next) { + u_int32_t vltime, pltime; + struct timeval now; + + ndopt_pi = (struct nd_opt_prefix_info *)buf; + ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; + ndopt_pi->nd_opt_pi_len = 4; + ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen; + ndopt_pi->nd_opt_pi_flags_reserved = 0; + if (pfx->onlinkflg) + ndopt_pi->nd_opt_pi_flags_reserved |= + ND_OPT_PI_FLAG_ONLINK; + if (pfx->autoconfflg) + ndopt_pi->nd_opt_pi_flags_reserved |= + ND_OPT_PI_FLAG_AUTO; +#ifdef MIP6 + if (pfx->routeraddr) + ndopt_pi->nd_opt_pi_flags_reserved |= + ND_OPT_PI_FLAG_ROUTER; +#endif + if (pfx->vltimeexpire || pfx->pltimeexpire) + gettimeofday(&now, NULL); + if (pfx->vltimeexpire == 0) + vltime = pfx->validlifetime; + else + vltime = (pfx->vltimeexpire > now.tv_sec) ? + pfx->vltimeexpire - now.tv_sec : 0; + if (pfx->pltimeexpire == 0) + pltime = pfx->preflifetime; + else + pltime = (pfx->pltimeexpire > now.tv_sec) ? + pfx->pltimeexpire - now.tv_sec : 0; + if (vltime < pltime) { + /* + * this can happen if vltime is decrement but pltime + * is not. + */ + pltime = vltime; + } + ndopt_pi->nd_opt_pi_valid_time = htonl(vltime); + ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime); + ndopt_pi->nd_opt_pi_reserved2 = 0; + ndopt_pi->nd_opt_pi_prefix = pfx->prefix; + + buf += sizeof(struct nd_opt_prefix_info); + } + +#ifdef ND_OPT_ROUTE_INFO + for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) { + u_int8_t psize = (rti->prefixlen + 0x3f) >> 6; + + ndopt_rti = (struct nd_opt_route_info *)buf; + ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO; + ndopt_rti->nd_opt_rti_len = 1 + psize; + ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen; + ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref; + ndopt_rti->nd_opt_rti_lifetime = rti->ltime; + memcpy(ndopt_rti + 1, &rti->prefix, psize * 8); + buf += sizeof(struct nd_opt_route_info) + psize * 8; + } +#endif + + return; +} + +static int +getinet6sysctl(int code) +{ + int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; + int value; + size_t size; + + mib[3] = code; + size = sizeof(value); + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) + < 0) { + syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s", + __FUNCTION__, code, + strerror(errno)); + return(-1); + } + else + return(value); +} diff --git a/rtadvd.tproj/config.h b/rtadvd.tproj/config.h new file mode 100644 index 0000000..f6bd083 --- /dev/null +++ b/rtadvd.tproj/config.h @@ -0,0 +1,37 @@ +/* $KAME: config.h,v 1.3 2000/05/16 13:34:13 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/config.h,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +extern void getconfig __P((char *)); +extern void delete_prefix __P((struct rainfo *, struct prefix *)); +extern void make_prefix __P((struct rainfo *, int, struct in6_addr *, int)); +extern void make_packet __P((struct rainfo *)); diff --git a/rtadvd.tproj/dump.c b/rtadvd.tproj/dump.c new file mode 100644 index 0000000..435830f --- /dev/null +++ b/rtadvd.tproj/dump.c @@ -0,0 +1,243 @@ +/* $KAME: dump.c,v 1.16 2001/03/21 17:41:13 jinmei Exp $ */ + +/* + * Copyright (C) 2000 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/dump.c,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ +#include +#include +#include + +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif /* __FreeBSD__ >= 3 */ +#include + +#include + +/* XXX: the following two are non-standard include files */ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "rtadvd.h" +#include "timer.h" +#include "if.h" +#include "dump.h" + +static FILE *fp; + +extern struct rainfo *ralist; + +static char *ether_str __P((struct sockaddr_dl *)); +static void if_dump __P((void)); + +#ifdef __FreeBSD__ /* XXX: see PORTABILITY */ +#define LONGLONG "%qu" +#else +#define LONGLONG "%llu" +#endif + +static char *rtpref_str[] = { + "medium", /* 00 */ + "high", /* 01 */ + "rsv", /* 10 */ + "low" /* 11 */ +}; + +static char * +ether_str(sdl) + struct sockaddr_dl *sdl; +{ + static char ebuf[32]; + u_char *cp; + + if (sdl->sdl_alen && sdl->sdl_alen > 5) { + cp = (u_char *)LLADDR(sdl); + sprintf(ebuf, "%x:%x:%x:%x:%x:%x", + cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); + } + else { + sprintf(ebuf, "NONE"); + } + + return(ebuf); +} + +static void +if_dump() +{ + struct rainfo *rai; + struct prefix *pfx; + char prefixbuf[INET6_ADDRSTRLEN]; + int first; + struct timeval now; + + gettimeofday(&now, NULL); /* XXX: unused in most cases */ + for (rai = ralist; rai; rai = rai->next) { + fprintf(fp, "%s:\n", rai->ifname); + + fprintf(fp, " Status: %s\n", + (iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" : + "DOWN"); + + /* control information */ + if (rai->lastsent.tv_sec) { + /* note that ctime() appends CR by itself */ + fprintf(fp, " Last RA sent: %s", + ctime((time_t *)&rai->lastsent.tv_sec)); + } + if (rai->timer) { + fprintf(fp, " Next RA will be sent: %s", + ctime((time_t *)&rai->timer->tm.tv_sec)); + } + else + fprintf(fp, " RA timer is stopped"); + fprintf(fp, " waits: %d, initcount: %d\n", + rai->waiting, rai->initcounter); + + /* statistics */ + fprintf(fp, + " statistics: RA(out/in/inconsistent): " + LONGLONG "/" LONGLONG "/" LONGLONG ", ", + (unsigned long long)rai->raoutput, + (unsigned long long)rai->rainput, + (unsigned long long)rai->rainconsistent); + fprintf(fp, "RS(input): " LONGLONG "\n", + (unsigned long long)rai->rsinput); + + /* interface information */ + if (rai->advlinkopt) + fprintf(fp, " Link-layer address: %s\n", + ether_str(rai->sdl)); + fprintf(fp, " MTU: %d\n", rai->phymtu); + + /* Router configuration variables */ + fprintf(fp, + " DefaultLifetime: %d, MaxAdvInterval: %d, " + "MinAdvInterval: %d\n", + rai->lifetime, rai->maxinterval, rai->mininterval); + fprintf(fp, " Flags: %s%s%s, ", + rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", +#ifdef MIP6 + rai->haflg ? "H" : +#endif + ""); + fprintf(fp, "Preference: %s, ", + rtpref_str[(rai->rtpref >> 3) & 0xff]); + fprintf(fp, "MTU: %d\n", rai->linkmtu); + fprintf(fp, " ReachableTime: %d, RetransTimer: %d, " + "CurHopLimit: %d\n", rai->reachabletime, + rai->retranstimer, rai->hoplimit); +#ifdef MIP6 + fprintf(fp, " HAPreference: %d, HALifetime: %d\n", + rai->hapref, rai->hatime); +#endif + + if (rai->clockskew) + fprintf(fp, " Clock skew: %ldsec\n", + rai->clockskew); + for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix; + pfx = pfx->next) { + if (first) { + fprintf(fp, " Prefixes:\n"); + first = 0; + } + fprintf(fp, " %s/%d(", + inet_ntop(AF_INET6, &pfx->prefix, + prefixbuf, sizeof(prefixbuf)), + pfx->prefixlen); + switch(pfx->origin) { + case PREFIX_FROM_KERNEL: + fprintf(fp, "KERNEL, "); + break; + case PREFIX_FROM_CONFIG: + fprintf(fp, "CONFIG, "); + break; + case PREFIX_FROM_DYNAMIC: + fprintf(fp, "DYNAMIC, "); + break; + } + if (pfx->validlifetime == ND6_INFINITE_LIFETIME) + fprintf(fp, "vltime: infinity"); + else + fprintf(fp, "vltime: %ld", + (long)pfx->validlifetime); + if (pfx->vltimeexpire != 0) + fprintf(fp, "(decr,expire %ld), ", (long) + pfx->vltimeexpire > now.tv_sec ? + pfx->vltimeexpire - now.tv_sec : 0); + else + fprintf(fp, ", "); + if (pfx->preflifetime == ND6_INFINITE_LIFETIME) + fprintf(fp, "pltime: infinity"); + else + fprintf(fp, "pltime: %ld", + (long)pfx->preflifetime); + if (pfx->pltimeexpire != 0) + fprintf(fp, "(decr,expire %ld), ", (long) + pfx->pltimeexpire > now.tv_sec ? + pfx->pltimeexpire - now.tv_sec : 0); + else + fprintf(fp, ", "); + fprintf(fp, "flags: %s%s%s", + pfx->onlinkflg ? "L" : "", + pfx->autoconfflg ? "A" : "", +#ifdef MIP6 + pfx->routeraddr ? "R" : +#endif + ""); + fprintf(fp, ")\n"); + } + } +} + +void +rtadvd_dump_file(dumpfile) + char *dumpfile; +{ + if ((fp = fopen(dumpfile, "w")) == NULL) { + syslog(LOG_WARNING, "<%s> open a dump file(%s)", + __FUNCTION__, dumpfile); + return; + } + + if_dump(); + + fclose(fp); +} diff --git a/rtadvd.tproj/dump.h b/rtadvd.tproj/dump.h new file mode 100644 index 0000000..eb73c36 --- /dev/null +++ b/rtadvd.tproj/dump.h @@ -0,0 +1,34 @@ +/* $KAME: dump.h,v 1.1 2000/05/23 11:31:26 itojun Exp $ */ + +/* + * Copyright (C) 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/dump.h,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +extern void rtadvd_dump_file __P((char *)); diff --git a/rtadvd.tproj/if.c b/rtadvd.tproj/if.c new file mode 100644 index 0000000..ba5c5f0 --- /dev/null +++ b/rtadvd.tproj/if.c @@ -0,0 +1,590 @@ +/* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/if.c,v 1.2.2.3 2001/07/03 11:02:14 ume Exp $ + */ + +#include +#include +#include +#include +#include +#include +#if defined(__FreeBSD__) || defined (__APPLE__) +# include +#endif +#include +#ifdef __NetBSD__ +#include +#endif +#include +#include +#include +#include +#ifdef __bsdi__ +# include +#endif +#ifdef __OpenBSD__ +#include +#endif +#include +#include +#include +#include +#include +#include "rtadvd.h" +#include "if.h" + +#define ROUNDUP(a, size) \ + (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) + +#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ + ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ + sizeof(u_long)) :\ + sizeof(u_long))) + +struct if_msghdr **iflist; +int iflist_init_ok; +size_t ifblock_size; +char *ifblock; + +static void get_iflist __P((char **buf, size_t *size)); +static void parse_iflist __P((struct if_msghdr ***ifmlist_p, char *buf, + size_t bufsize)); + +static void +get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) +{ + int i; + + for (i = 0; i < RTAX_MAX; i++) { + if (addrs & (1 << i)) { + rti_info[i] = sa; + NEXT_SA(sa); + } + else + rti_info[i] = NULL; + } +} + +struct sockaddr_dl * +if_nametosdl(char *name) +{ + int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; + char *buf, *next, *lim; + size_t len; + struct if_msghdr *ifm; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_dl *sdl = NULL, *ret_sdl; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return(NULL); + if ((buf = malloc(len)) == NULL) + return(NULL); + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + free(buf); + return(NULL); + } + + lim = buf + len; + for (next = buf; next < lim; next += ifm->ifm_msglen) { + ifm = (struct if_msghdr *)next; + if (ifm->ifm_type == RTM_IFINFO) { + sa = (struct sockaddr *)(ifm + 1); + get_rtaddrs(ifm->ifm_addrs, sa, rti_info); + if ((sa = rti_info[RTAX_IFP]) != NULL) { + if (sa->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)sa; + if (strlen(name) != sdl->sdl_nlen) + continue; /* not same len */ + if (strncmp(&sdl->sdl_data[0], + name, + sdl->sdl_nlen) == 0) { + break; + } + } + } + } + } + if (next == lim) { + /* search failed */ + free(buf); + return(NULL); + } + + if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) + return(NULL); + memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); + return(ret_sdl); +} + +int +if_getmtu(char *name) +{ + struct ifaddrs *ifap, *ifa; + struct if_data *ifd; + u_long mtu = 0; + + if (getifaddrs(&ifap) < 0) + return(0); + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strcmp(ifa->ifa_name, name) == 0) { + ifd = ifa->ifa_data; + if (ifd) + mtu = ifd->ifi_mtu; + break; + } + } + freeifaddrs(ifap); + +#ifdef SIOCGIFMTU /* XXX: this ifdef may not be necessary */ + if (mtu == 0) { + struct ifreq ifr; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) + return(0); + + ifr.ifr_addr.sa_family = AF_INET6; + strncpy(ifr.ifr_name, name, + sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) { + close(s); + return(0); + } + close(s); + + mtu = ifr.ifr_mtu; + } +#endif + + return(mtu); +} + +/* give interface index and its old flags, then new flags returned */ +int +if_getflags(int ifindex, int oifflags) +{ + struct ifreq ifr; + int s; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + return (oifflags & ~IFF_UP); + } + + if_indextoname(ifindex, ifr.ifr_name); + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s", + __FUNCTION__, ifr.ifr_name); + close(s); + return (oifflags & ~IFF_UP); + } + close(s); + return (ifr.ifr_flags); +} + +#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) +int +lladdropt_length(struct sockaddr_dl *sdl) +{ + switch(sdl->sdl_type) { + case IFT_ETHER: + return(ROUNDUP8(ETHER_ADDR_LEN + 2)); + default: + return(0); + } +} + +void +lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) +{ + char *addr; + + ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ + + switch(sdl->sdl_type) { + case IFT_ETHER: + ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; + addr = (char *)(ndopt + 1); + memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); + break; + default: + syslog(LOG_ERR, + "<%s> unsupported link type(%d)", + __FUNCTION__, sdl->sdl_type); + exit(1); + } + + return; +} + +int +rtbuf_len() +{ + size_t len; + + int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0}; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return(-1); + + return(len); +} + +#define FILTER_MATCH(type, filter) ((0x1 << type) & filter) +#define SIN6(s) ((struct sockaddr_in6 *)(s)) +#define SDL(s) ((struct sockaddr_dl *)(s)) +char * +get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter) +{ + struct rt_msghdr *rtm; + struct ifa_msghdr *ifam; + struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX]; + + *lenp = 0; + for (rtm = (struct rt_msghdr *)buf; + rtm < (struct rt_msghdr *)lim; + rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) { + /* just for safety */ + if (!rtm->rtm_msglen) { + syslog(LOG_WARNING, "<%s> rtm_msglen is 0 " + "(buf=%p lim=%p rtm=%p)", __FUNCTION__, + buf, lim, rtm); + break; + } + if (FILTER_MATCH(rtm->rtm_type, filter) == 0) { + continue; + } + + switch (rtm->rtm_type) { + case RTM_GET: + case RTM_ADD: + case RTM_DELETE: + /* address related checks */ + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + if ((dst = rti_info[RTAX_DST]) == NULL || + dst->sa_family != AF_INET6) + continue; + + if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr)) + continue; + + if ((gw = rti_info[RTAX_GATEWAY]) == NULL || + gw->sa_family != AF_LINK) + continue; + if (ifindex && SDL(gw)->sdl_index != ifindex) + continue; + + if (rti_info[RTAX_NETMASK] == NULL) + continue; + + /* found */ + *lenp = rtm->rtm_msglen; + return (char *)rtm; + /* NOTREACHED */ + case RTM_NEWADDR: + case RTM_DELADDR: + ifam = (struct ifa_msghdr *)rtm; + + /* address related checks */ + sa = (struct sockaddr *)(ifam + 1); + get_rtaddrs(ifam->ifam_addrs, sa, rti_info); + if ((ifa = rti_info[RTAX_IFA]) == NULL || + (ifa->sa_family != AF_INET && + ifa->sa_family != AF_INET6)) + continue; + + if (ifa->sa_family == AF_INET6 && + (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) || + IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr))) + continue; + + if (ifindex && ifam->ifam_index != ifindex) + continue; + + /* found */ + *lenp = ifam->ifam_msglen; + return (char *)rtm; + /* NOTREACHED */ + case RTM_IFINFO: + /* found */ + *lenp = rtm->rtm_msglen; + return (char *)rtm; + /* NOTREACHED */ + } + } + + return (char *)rtm; +} +#undef FILTER_MATCH + +struct in6_addr * +get_addr(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + + return(&SIN6(rti_info[RTAX_DST])->sin6_addr); +} + +int +get_rtm_ifindex(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + + return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index); +} + +int +get_ifm_ifindex(char *buf) +{ + struct if_msghdr *ifm = (struct if_msghdr *)buf; + + return ((int)ifm->ifm_index); +} + +int +get_ifam_ifindex(char *buf) +{ + struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf; + + return ((int)ifam->ifam_index); +} + +int +get_ifm_flags(char *buf) +{ + struct if_msghdr *ifm = (struct if_msghdr *)buf; + + return (ifm->ifm_flags); +} + +int +get_prefixlen(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + u_char *p, *lim; + + sa = (struct sockaddr *)(rtm + 1); + get_rtaddrs(rtm->rtm_addrs, sa, rti_info); + sa = rti_info[RTAX_NETMASK]; + + p = (u_char *)(&SIN6(sa)->sin6_addr); + lim = (u_char *)sa + sa->sa_len; + return prefixlen(p, lim); +} + +int +prefixlen(u_char *p, u_char *lim) +{ + int masklen; + + for (masklen = 0; p < lim; p++) { + switch (*p) { + case 0xff: + masklen += 8; + break; + case 0xfe: + masklen += 7; + break; + case 0xfc: + masklen += 6; + break; + case 0xf8: + masklen += 5; + break; + case 0xf0: + masklen += 4; + break; + case 0xe0: + masklen += 3; + break; + case 0xc0: + masklen += 2; + break; + case 0x80: + masklen += 1; + break; + case 0x00: + break; + default: + return(-1); + } + } + + return(masklen); +} + +int +rtmsg_type(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + + return(rtm->rtm_type); +} + +int +rtmsg_len(char *buf) +{ + struct rt_msghdr *rtm = (struct rt_msghdr *)buf; + + return(rtm->rtm_msglen); +} + +int +ifmsg_len(char *buf) +{ + struct if_msghdr *ifm = (struct if_msghdr *)buf; + + return(ifm->ifm_msglen); +} + +/* + * alloc buffer and get if_msghdrs block from kernel, + * and put them into the buffer + */ +static void +get_iflist(char **buf, size_t *size) +{ + int mib[6]; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET6; + mib[4] = NET_RT_IFLIST; + mib[5] = 0; + + if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) { + syslog(LOG_ERR, "<%s> sysctl: iflist size get failed", + __FUNCTION__); + exit(1); + } + if ((*buf = malloc(*size)) == NULL) { + syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); + exit(1); + } + if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) { + syslog(LOG_ERR, "<%s> sysctl: iflist get failed", + __FUNCTION__); + exit(1); + } + return; +} + +/* + * alloc buffer and parse if_msghdrs block passed as arg, + * and init the buffer as list of pointers ot each of the if_msghdr. + */ +static void +parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize) +{ + int iflentry_size, malloc_size; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + char *lim; + + /* + * Estimate least size of an iflist entry, to be obtained from kernel. + * Should add sizeof(sockaddr) ?? + */ + iflentry_size = sizeof(struct if_msghdr); + /* roughly estimate max list size of pointers to each if_msghdr */ + malloc_size = (bufsize/iflentry_size) * sizeof(size_t); + if ((*ifmlist_p = (struct if_msghdr **)malloc(malloc_size)) == NULL) { + syslog(LOG_ERR, "<%s> malloc failed", __FUNCTION__); + exit(1); + } + + lim = buf + bufsize; + for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) { + if (ifm->ifm_msglen == 0) { + syslog(LOG_WARNING, "<%s> ifm_msglen is 0 " + "(buf=%p lim=%p ifm=%p)", __FUNCTION__, + buf, lim, ifm); + return; + } + + if (ifm->ifm_type == RTM_IFINFO) { + (*ifmlist_p)[ifm->ifm_index] = ifm; + } else { + syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n" + "expected %d, got %d\n msglen = %d\n" + "buf:%p, ifm:%p, lim:%p\n", + RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, + buf, ifm, lim); + exit (1); + } + for (ifam = (struct ifa_msghdr *) + ((char *)ifm + ifm->ifm_msglen); + ifam < (struct ifa_msghdr *)lim; + ifam = (struct ifa_msghdr *) + ((char *)ifam + ifam->ifam_msglen)) { + /* just for safety */ + if (!ifam->ifam_msglen) { + syslog(LOG_WARNING, "<%s> ifa_msglen is 0 " + "(buf=%p lim=%p ifam=%p)", __FUNCTION__, + buf, lim, ifam); + return; + } + if (ifam->ifam_type != RTM_NEWADDR) + break; + } + ifm = (struct if_msghdr *)ifam; + } +} + +void +init_iflist() +{ + if (ifblock) { + free(ifblock); + ifblock_size = 0; + } + if (iflist) + free(iflist); + /* get iflist block from kernel */ + get_iflist(&ifblock, &ifblock_size); + + /* make list of pointers to each if_msghdr */ + parse_iflist(&iflist, ifblock, ifblock_size); +} diff --git a/rtadvd.tproj/if.h b/rtadvd.tproj/if.h new file mode 100644 index 0000000..06d2d72 --- /dev/null +++ b/rtadvd.tproj/if.h @@ -0,0 +1,59 @@ +/* $KAME: if.h,v 1.6 2001/01/21 15:37:14 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/if.h,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +#define RTADV_TYPE2BITMASK(type) (0x1 << type) + +extern struct if_msghdr **iflist; +extern size_t ifblock_size; +extern char *ifblock; + +struct nd_opt_hdr; +struct sockaddr_dl *if_nametosdl __P((char *)); +int if_getmtu __P((char *)); +int if_getflags __P((int, int)); +int lladdropt_length __P((struct sockaddr_dl *)); +void lladdropt_fill __P((struct sockaddr_dl *, struct nd_opt_hdr *)); +int rtbuf_len __P((void)); +char *get_next_msg __P((char *, char *, int, size_t *, int)); +struct in6_addr *get_addr __P((char *)); +int get_rtm_ifindex __P((char *)); +int get_ifm_ifindex __P((char *)); +int get_ifam_ifindex __P((char *)); +int get_ifm_flags __P((char *)); +int get_prefixlen __P((char *)); +int prefixlen __P((u_char *, u_char *)); +int rtmsg_type __P((char *)); +int ifmsg_type __P((char *)); +int rtmsg_len __P((char *)); +int ifmsg_len __P((char *)); +void init_iflist __P((void)); diff --git a/rtadvd.tproj/pathnames.h b/rtadvd.tproj/pathnames.h new file mode 100644 index 0000000..d288ab9 --- /dev/null +++ b/rtadvd.tproj/pathnames.h @@ -0,0 +1,4 @@ +/* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */ +/* $FreeBSD: src/usr.sbin/rtadvd/pathnames.h,v 1.2.2.2 2001/07/03 11:02:14 ume Exp $ */ + +#define _PATH_RTADVDCONF "/etc/rtadvd.conf" diff --git a/rtadvd.tproj/rrenum.c b/rtadvd.tproj/rrenum.c new file mode 100644 index 0000000..a33670b --- /dev/null +++ b/rtadvd.tproj/rrenum.c @@ -0,0 +1,489 @@ +/* $KAME: rrenum.c,v 1.10 2001/01/21 15:32:16 itojun 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/rrenum.c,v 1.2.2.2 2001/07/03 11:02:14 ume Exp $ + */ +#include +#include +#include +#include +#include + +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif /* __FreeBSD__ >= 3 */ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include "rtadvd.h" +#include "rrenum.h" +#include "if.h" + +#define RR_ISSET_SEGNUM(segnum_bits, segnum) \ + ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0) +#define RR_SET_SEGNUM(segnum_bits, segnum) \ + (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31))) + +struct rr_operation { + u_long rro_seqnum; + u_long rro_segnum_bits[8]; +}; + +static struct rr_operation rro; +static int rr_rcvifindex; +static int rrcmd2pco[RPM_PCO_MAX] = { + 0, + SIOCAIFPREFIX_IN6, + SIOCCIFPREFIX_IN6, + SIOCSGIFPREFIX_IN6 +}; +static int s = -1; + +/* + * Check validity of a Prefix Control Operation(PCO). + * Return 0 on success, 1 on failure. + */ +static int +rr_pco_check(int len, struct rr_pco_match *rpm) +{ + struct rr_pco_use *rpu, *rpulim; + int checklen; + + /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */ + if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */ + (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */ + syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3", + __FUNCTION__, rpm->rpm_len); + return 1; + } + /* rpm->rpm_code must be valid value */ + switch(rpm->rpm_code) { + case RPM_PCO_ADD: + case RPM_PCO_CHANGE: + case RPM_PCO_SETGLOBAL: + break; + default: + syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __FUNCTION__, + rpm->rpm_code); + return 1; + } + /* rpm->rpm_matchlen must be 0 to 128 inclusive */ + if (rpm->rpm_matchlen > 128) { + syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128", + __FUNCTION__, rpm->rpm_matchlen); + return 1; + } + + /* + * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be + * between 0 and 128 inclusive + */ + for (rpu = (struct rr_pco_use *)(rpm + 1), + rpulim = (struct rr_pco_use *)((char *)rpm + len); + rpu < rpulim; + rpu += 1) { + checklen = rpu->rpu_uselen; + checklen += rpu->rpu_keeplen; + /* + * omit these check, because either of rpu_uselen + * and rpu_keeplen is unsigned char + * (128 > rpu_uselen > 0) + * (128 > rpu_keeplen > 0) + * (rpu_uselen + rpu_keeplen > 0) + */ + if (checklen > 128) { + syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and" + " rpu_keeplen %d is %d(over 128)", + __FUNCTION__, rpu->rpu_uselen, + rpu->rpu_keeplen, + rpu->rpu_uselen + rpu->rpu_keeplen); + return 1; + } + } + return 0; +} + +static void +do_use_prefix(int len, struct rr_pco_match *rpm, + struct in6_rrenumreq *irr, int ifindex) +{ + struct rr_pco_use *rpu, *rpulim; + struct rainfo *rai; + struct prefix *pp; + + rpu = (struct rr_pco_use *)(rpm + 1); + rpulim = (struct rr_pco_use *)((char *)rpm + len); + + if (rpu == rpulim) { /* no use prefix */ + if (rpm->rpm_code == RPM_PCO_ADD) + return; + + irr->irr_u_uselen = 0; + irr->irr_u_keeplen = 0; + irr->irr_raf_mask_onlink = 0; + irr->irr_raf_mask_auto = 0; + irr->irr_vltime = 0; + irr->irr_pltime = 0; + memset(&irr->irr_flags, 0, sizeof(irr->irr_flags)); + irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */ + irr->irr_useprefix.sin6_family = 0; + irr->irr_useprefix.sin6_addr = in6addr_any; + if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && + errno != EADDRNOTAVAIL) + syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, + strerror(errno)); + return; + } + + for (rpu = (struct rr_pco_use *)(rpm + 1), + rpulim = (struct rr_pco_use *)((char *)rpm + len); + rpu < rpulim; + rpu += 1) { + /* init in6_rrenumreq fields */ + irr->irr_u_uselen = rpu->rpu_uselen; + irr->irr_u_keeplen = rpu->rpu_keeplen; + irr->irr_raf_mask_onlink = + (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK); + irr->irr_raf_mask_auto = + (rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO); + irr->irr_vltime = ntohl(rpu->rpu_vltime); + irr->irr_pltime = ntohl(rpu->rpu_pltime); + irr->irr_raf_onlink = + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1; + irr->irr_raf_auto = + (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1; + irr->irr_rrf_decrvalid = + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1; + irr->irr_rrf_decrprefd = + (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1; + irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix); + irr->irr_useprefix.sin6_family = AF_INET6; + irr->irr_useprefix.sin6_addr = rpu->rpu_prefix; + + if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 && + errno != EADDRNOTAVAIL) + syslog(LOG_ERR, "<%s> ioctl: %s", __FUNCTION__, + strerror(errno)); + + /* very adhoc: should be rewritten */ + if (rpm->rpm_code == RPM_PCO_CHANGE && + IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) && + rpm->rpm_matchlen == rpu->rpu_uselen && + rpu->rpu_uselen == rpu->rpu_keeplen) { + if ((rai = if_indextorainfo(ifindex)) == NULL) + continue; /* non-advertising IF */ + + for (pp = rai->prefix.next; pp != &rai->prefix; + pp = pp->next) { + struct timeval now; + + if (prefix_match(&pp->prefix, pp->prefixlen, + &rpm->rpm_prefix, + rpm->rpm_matchlen)) { + /* change parameters */ + pp->validlifetime = ntohl(rpu->rpu_vltime); + pp->preflifetime = ntohl(rpu->rpu_pltime); + if (irr->irr_rrf_decrvalid) { + gettimeofday(&now, 0); + pp->vltimeexpire = + now.tv_sec + pp->validlifetime; + } else + pp->vltimeexpire = 0; + if (irr->irr_rrf_decrprefd) { + gettimeofday(&now, 0); + pp->pltimeexpire = + now.tv_sec + pp->preflifetime; + } else + pp->pltimeexpire = 0; + } + } + } + } +} + +/* + * process a Prefix Control Operation(PCO). + * return 0 on success, 1 on failure + */ +static int +do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm) +{ + int ifindex = 0; + struct in6_rrenumreq irr; + + if ((rr_pco_check(len, rpm) != NULL)) + return 1; + + if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + + memset(&irr, 0, sizeof(irr)); + irr.irr_origin = PR_ORIG_RR; + irr.irr_m_len = rpm->rpm_matchlen; + irr.irr_m_minlen = rpm->rpm_minlen; + irr.irr_m_maxlen = rpm->rpm_maxlen; + irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix); + irr.irr_matchprefix.sin6_family = AF_INET6; + irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix; + + while (if_indextoname(++ifindex, irr.irr_name)) { + /* + * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off, + * the interface is not applied + */ + if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 && + (iflist[ifindex]->ifm_flags & IFF_UP) == 0) + continue; + /* TODO: interface scope check */ + do_use_prefix(len, rpm, &irr, ifindex); + } + if (errno == ENXIO) + return 0; + else if (errno) { + syslog(LOG_ERR, "<%s> if_indextoname: %s", __FUNCTION__, + strerror(errno)); + return 1; + } + return 0; +} + +/* + * call do_pco() for each Prefix Control Operations(PCOs) in a received + * Router Renumbering Command packet. + * return 0 on success, 1 on failure + */ +static int +do_rr(int len, struct icmp6_router_renum *rr) +{ + struct rr_pco_match *rpm; + char *cp, *lim; + + lim = (char *)rr + len; + cp = (char *)(rr + 1); + len -= sizeof(struct icmp6_router_renum); + + /* get iflist block from kernel again, to get up-to-date information */ + init_iflist(); + + while (cp < lim) { + int rpmlen; + + rpm = (struct rr_pco_match *)cp; + if (len < sizeof(struct rr_pco_match)) { + tooshort: + syslog(LOG_ERR, "<%s> pkt too short. left len = %d. " + "gabage at end of pkt?", __FUNCTION__, len); + return 1; + } + rpmlen = rpm->rpm_len << 3; + if (len < rpmlen) + goto tooshort; + + if (do_pco(rr, rpmlen, rpm)) { + syslog(LOG_WARNING, "<%s> invalid PCO", __FUNCTION__); + goto next; + } + + next: + cp += rpmlen; + len -= rpmlen; + } + + return 0; +} + +/* + * check validity of a router renumbering command packet + * return 0 on success, 1 on failure + */ +static int +rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from, + struct in6_addr *dst) +{ + u_char ntopbuf[INET6_ADDRSTRLEN]; + + /* omit rr minimal length check. hope kernel have done it. */ + /* rr_command length check */ + if (len < (sizeof(struct icmp6_router_renum) + + sizeof(struct rr_pco_match))) { + syslog(LOG_ERR, "<%s> rr_command len %d is too short", + __FUNCTION__, len); + return 1; + } + + /* destination check. only for multicast. omit unicast check. */ + if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) && + !IN6_IS_ADDR_MC_SITELOCAL(dst)) { + syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal", + __FUNCTION__, + inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN)); + return 1; + } + + /* seqnum and segnum check */ + if (rro.rro_seqnum > rr->rr_seqnum) { + syslog(LOG_WARNING, + "<%s> rcvd old seqnum %d from %s", + __FUNCTION__, (u_int32_t)ntohl(rr->rr_seqnum), + inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN)); + return 1; + } + if (rro.rro_seqnum == rr->rr_seqnum && + (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 && + RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) { + if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0) + syslog(LOG_WARNING, + "<%s> rcvd duped segnum %d from %s", + __FUNCTION__, rr->rr_segnum, + inet_ntop(AF_INET6, from, ntopbuf, + INET6_ADDRSTRLEN)); + return 0; + } + + /* update seqnum */ + if (rro.rro_seqnum != rr->rr_seqnum) { + /* then must be "<" */ + + /* init rro_segnum_bits */ + memset(rro.rro_segnum_bits, 0, + sizeof(rro.rro_segnum_bits)); + } + rro.rro_seqnum = rr->rr_seqnum; + + return 0; +} + +static void +rr_command_input(int len, struct icmp6_router_renum *rr, + struct in6_addr *from, struct in6_addr *dst) +{ + /* rr_command validity check */ + if (rr_command_check(len, rr, from, dst)) + goto failed; + if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) == + ICMP6_RR_FLAGS_TEST) + return; + + /* do router renumbering */ + if (do_rr(len, rr)) { + goto failed; + } + + /* update segnum */ + RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum); + + return; + + failed: + syslog(LOG_ERR, "<%s> received RR was invalid", __FUNCTION__); + return; +} + +void +rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi, + struct sockaddr_in6 *from, struct in6_addr *dst) +{ + u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + + syslog(LOG_DEBUG, + "<%s> RR received from %s to %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf[0], INET6_ADDRSTRLEN), + inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + /* packet validation based on Section 4.1 of RFC2894 */ + if (len < sizeof(struct icmp6_router_renum)) { + syslog(LOG_NOTICE, + "<%s>: RR short message (size %d) from %s to %s on %s", + __FUNCTION__, len, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf[0], INET6_ADDRSTRLEN), + inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + /* + * If the IPv6 destination address is neither an All Routers multicast + * address [AARCH] nor one of the receiving router's unicast addresses, + * the message MUST be discarded and SHOULD be logged to network + * management. + * We rely on the kernel input routine for unicast addresses, and thus + * check multicast destinations only. + */ + if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && + !IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) { + syslog(LOG_NOTICE, + "<%s>: RR message with invalid destination (%s) " + "from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN), + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf[1], INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + rr_rcvifindex = pi->ipi6_ifindex; + + switch (rr->rr_code) { + case ICMP6_ROUTER_RENUMBERING_COMMAND: + rr_command_input(len, rr, &from->sin6_addr, dst); + /* TODO: send reply msg */ + break; + case ICMP6_ROUTER_RENUMBERING_RESULT: + /* RESULT will be processed by rrenumd */ + break; + case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: + /* TODO: sequence number reset */ + break; + default: + syslog(LOG_ERR, "<%s> received unknown code %d", + __FUNCTION__, rr->rr_code); + break; + + } + + return; +} diff --git a/rtadvd.tproj/rrenum.h b/rtadvd.tproj/rrenum.h new file mode 100644 index 0000000..ad8db33 --- /dev/null +++ b/rtadvd.tproj/rrenum.h @@ -0,0 +1,35 @@ +/* $KAME: rrenum.h,v 1.3 2001/01/21 15:37:14 itojun Exp $ */ + +/* + * Copyright (C) 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/rrenum.h,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +void rr_input __P((int, struct icmp6_router_renum *, struct in6_pktinfo *, + struct sockaddr_in6 *, struct in6_addr *)); diff --git a/rtadvd.tproj/rtadvd.8 b/rtadvd.tproj/rtadvd.8 new file mode 100644 index 0000000..4ec5483 --- /dev/null +++ b/rtadvd.tproj/rtadvd.8 @@ -0,0 +1,179 @@ +.\" $FreeBSD: src/usr.sbin/rtadvd/rtadvd.8,v 1.3.2.6 2001/08/16 15:56:30 ru Exp $ +.\" $KAME: rtadvd.8,v 1.17 2001/02/04 05:34:38 jinmei 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. 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. +.\" +.Dd May 17, 1998 +.Dt RTADVD 8 +.Os +.Sh NAME +.Nm rtadvd +.Nd router advertisement daemon +.Sh SYNOPSIS +.Nm +.Op Fl dDfMRs +.Op Fl c Ar configfile +.Ar interface ... +.Sh DESCRIPTION +.Nm +sends router advertisement packets to the specified +.Ar interfaces . +.Pp +The program will daemonize itself on invocation. +It will then send router advertisement packets periodically, as well +as in response to router solicitation messages sent by end hosts. +.Pp +Router advertisements can be configured on a per-interface basis, as +described in +.Xr rtadvd.conf 5 . +.Pp +If there is no configuration file entry for an interface, +or if the configuration file does not exist altogether, +.Nm +sets all the parameters to their default values. +In particular, +.Nm +reads all the interface routes from the routing table and advertises +them as on-link prefixes. +.Pp +.Nm +also watches the routing table. +By default, if an interface direct route is +added/deleted on an advertising interface and no static prefixes are +specified by the configuration file, +.Nm +adds/deletes the corresponding prefix to/from its advertising list, +respectively. +The +.Fl s +option may be used to disable this behavior. +Moreover, if the status of an advertising interface changes, +.Nm +will start or stop sending router advertisements according +to the latest status. +.Pp +Basically, hosts MUST NOT send Router Advertisement messages at any +time (RFC 2461, Section 6.2.3). +However, it would sometimes be useful to allow hosts to advertise some +parameters such as prefix information and link MTU. +Thus, +.Nm +can be invoked if router lifetime is explicitly set zero on every +advertising interface. +.Pp +The command line options are: +.Bl -tag -width indent +.\" +.It Fl c +Specify an alternate location, +.Ar configfile , +for the configuration file. +By default, +.Pa /etc/rtadvd.conf +is used. +.It Fl d +Print debugging information. +.It Fl D +Even more debugging information is printed. +.It Fl f +Foreground mode (useful when debugging). +.It Fl M +Specify an interface to join the all-routers site-local multicast group. +By default, +.Nm +tries to join the first advertising interface appeared in the command +line. +This option has meaning only with the +.Fl R +option, which enables routing renumbering protocol support. +.\".It Fl m +.\"Enables mobile IPv6 support. +.\"This changes the content of router advertisement option, as well as +.\"permitted configuration directives. +.It Fl R +Accept router renumbering requests. +If you enable it, certain IPsec setup is suggested for security reasons. +On KAME-based systems, +.Xr rrenumd 8 +generates router renumbering request packets. +This option is currently disabled, and is ignored by +.Nm +with a warning message. +.It Fl s +Do not add or delete prefixes dynamically. +Only statically configured prefixes, if any, will be advertised. +.El +.Pp +Upon receipt of signal +.Dv SIGUSR1 , +.Nm +will dump the current internal state into +.Pa /var/run/rtadvd.dump . +.Pp +Use +.Dv SIGTERM +to kill +.Nm +gracefully. +In this case, +.Nm +will transmit router advertisement with router lifetime 0 +to all the interfaces +(in accordance with RFC2461 6.2.5). +.Sh DIAGNOSTICS +.Ex -std +.Sh FILES +.Bl -tag -width Pa -compact +.It Pa /etc/rtadvd.conf +The default configuration file. +.It Pa /var/run/rtadvd.pid +contains the pid of the currently running +.Nm . +.It Pa /var/run/rtadvd.dump +in which +.Nm +dumps its internal state. +.El +.Sh SEE ALSO +.Xr rtadvd.conf 5 , +.Xr rrenumd 8 , +.Xr rtsol 8 +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.Sh CAVEAT +There used to be some text that recommended users not to let +.Nm +advertise Router Advertisement messages on an upstream link to avoid +undesirable +.Xr icmp6 4 +redirect messages. +However, based on the later discussion in the IETF ipng working group, +all routers should rather advertise the messages regardless of +the network topology, in order to ensure reachability. diff --git a/rtadvd.tproj/rtadvd.c b/rtadvd.tproj/rtadvd.c new file mode 100644 index 0000000..0397394 --- /dev/null +++ b/rtadvd.tproj/rtadvd.c @@ -0,0 +1,1630 @@ +/* $KAME: rtadvd.c,v 1.50 2001/02/04 06:15:15 itojun 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/rtadvd.c,v 1.3.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtadvd.h" +#include "rrenum.h" +#include "advcap.h" +#include "timer.h" +#include "if.h" +#include "config.h" +#include "dump.h" + +struct msghdr rcvmhdr; +static u_char *rcvcmsgbuf; +static size_t rcvcmsgbuflen; +static u_char *sndcmsgbuf = NULL; +static size_t sndcmsgbuflen; +static int do_dump; +static int do_die; +struct msghdr sndmhdr; +struct iovec rcviov[2]; +struct iovec sndiov[2]; +struct sockaddr_in6 from; +struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6}; +struct in6_addr in6a_site_allrouters; +static char *dumpfilename = "/var/run/rtadvd.dump"; /* XXX: should be configurable */ +static char *pidfilename = "/var/run/rtadvd.pid"; /* should be configurable */ +static char *mcastif; +int sock; +int rtsock = -1; +#ifdef MIP6 +int mobileip6 = 0; +#endif +int accept_rr = 0; +int dflag = 0, sflag = 0; + +u_char *conffile = NULL; + +struct rainfo *ralist = NULL; +struct nd_optlist { + struct nd_optlist *next; + struct nd_opt_hdr *opt; +}; +union nd_opts { + struct nd_opt_hdr *nd_opt_array[7]; + struct { + struct nd_opt_hdr *zero; + struct nd_opt_hdr *src_lladdr; + struct nd_opt_hdr *tgt_lladdr; + struct nd_opt_prefix_info *pi; + struct nd_opt_rd_hdr *rh; + struct nd_opt_mtu *mtu; + struct nd_optlist *list; + } nd_opt_each; +}; +#define nd_opts_src_lladdr nd_opt_each.src_lladdr +#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr +#define nd_opts_pi nd_opt_each.pi +#define nd_opts_rh nd_opt_each.rh +#define nd_opts_mtu nd_opt_each.mtu +#define nd_opts_list nd_opt_each.list + +#define NDOPT_FLAG_SRCLINKADDR 0x1 +#define NDOPT_FLAG_TGTLINKADDR 0x2 +#define NDOPT_FLAG_PREFIXINFO 0x4 +#define NDOPT_FLAG_RDHDR 0x8 +#define NDOPT_FLAG_MTU 0x10 + +u_int32_t ndopt_flags[] = { + 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, + NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU +}; + +int main __P((int, char *[])); +static void set_die __P((int)); +static void die __P((void)); +static void sock_open __P((void)); +static void rtsock_open __P((void)); +static void rtadvd_input __P((void)); +static void rs_input __P((int, struct nd_router_solicit *, + struct in6_pktinfo *, struct sockaddr_in6 *)); +static void ra_input __P((int, struct nd_router_advert *, + struct in6_pktinfo *, struct sockaddr_in6 *)); +static int prefix_check __P((struct nd_opt_prefix_info *, struct rainfo *, + struct sockaddr_in6 *)); +static int nd6_options __P((struct nd_opt_hdr *, int, + union nd_opts *, u_int32_t)); +static void free_ndopts __P((union nd_opts *)); +static void ra_output __P((struct rainfo *)); +static void rtmsg_input __P((void)); +static void rtadvd_set_dump_file __P((void)); + +struct prefix *find_prefix __P((struct rainfo *, struct in6_addr *, int)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + fd_set fdset; + int maxfd = 0; + struct timeval *timeout; + int i, ch; + int fflag = 0; + FILE *pidfp; + pid_t pid; + + openlog("rtadvd", LOG_NDELAY|LOG_PID, LOG_DAEMON); + + /* get command line options and arguments */ +#ifdef MIP6 +#define OPTIONS "c:dDfM:mRs" +#else +#define OPTIONS "c:dDfM:Rs" +#endif + while ((ch = getopt(argc, argv, OPTIONS)) != -1) { +#undef OPTIONS + switch(ch) { + case 'c': + conffile = optarg; + break; + case 'd': + dflag = 1; + break; + case 'D': + dflag = 2; + break; + case 'f': + fflag = 1; + break; + case 'M': + mcastif = optarg; + break; +#ifdef MIP6 + case 'm': + mobileip6 = 1; + break; +#endif + case 'R': + fprintf(stderr, "rtadvd: " + "the -R option is currently ignored.\n"); + /* accept_rr = 1; */ + /* run anyway... */ + break; + case 's': + sflag = 1; + break; + } + } + argc -= optind; + argv += optind; + if (argc == 0) { + fprintf(stderr, +#ifdef MIP6 + "usage: rtadvd [-dDfMmRs] [-c conffile] " +#else + "usage: rtadvd [-dDfMRs] [-c conffile] " +#endif + "interfaces...\n"); + exit(1); + } + + /* set log level */ + if (dflag == 0) + (void)setlogmask(LOG_UPTO(LOG_ERR)); + if (dflag == 1) + (void)setlogmask(LOG_UPTO(LOG_INFO)); + + /* timer initialization */ + rtadvd_timer_init(); + + /* random value initialization */ + srandom((u_long)time(NULL)); + + /* get iflist block from kernel */ + init_iflist(); + + while (argc--) + getconfig(*argv++); + + if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) { + fprintf(stderr, "fatal: inet_pton failed\n"); + exit(1); + } + sock_open(); + + if (!fflag) + daemon(1, 0); + + /* record the current PID */ + pid = getpid(); + if ((pidfp = fopen(pidfilename, "w")) == NULL) + syslog(LOG_ERR, + "<%s> failed to open a log file(%s), run anyway.", + __FUNCTION__, pidfilename); + else { + fprintf(pidfp, "%d\n", pid); + fclose(pidfp); + } + + FD_ZERO(&fdset); + FD_SET(sock, &fdset); + maxfd = sock; + if (sflag == 0) { + rtsock_open(); + FD_SET(rtsock, &fdset); + if (rtsock > sock) + maxfd = rtsock; + } else + rtsock = -1; + + signal(SIGTERM, (void *)set_die); + signal(SIGUSR1, (void *)rtadvd_set_dump_file); + + while (1) { + struct fd_set select_fd = fdset; /* reinitialize */ + + if (do_dump) { /* SIGUSR1 */ + do_dump = 0; + rtadvd_dump_file(dumpfilename); + } + + if (do_die) { + die(); + /*NOTREACHED*/ + } + + /* timer expiration check and reset the timer */ + timeout = rtadvd_check_timer(); + + if (timeout != NULL) { + syslog(LOG_DEBUG, + "<%s> set timer to %ld:%ld. waiting for " + "inputs or timeout", + __FUNCTION__, + (long int)timeout->tv_sec, + (long int)timeout->tv_usec); + } else { + syslog(LOG_DEBUG, + "<%s> there's no timer. waiting for inputs", + __FUNCTION__); + } + + if ((i = select(maxfd + 1, &select_fd, + NULL, NULL, timeout)) < 0) { + /* EINTR would occur upon SIGUSR1 for status dump */ + if (errno != EINTR) + syslog(LOG_ERR, "<%s> select: %s", + __FUNCTION__, strerror(errno)); + continue; + } + if (i == 0) /* timeout */ + continue; + if (rtsock != -1 && FD_ISSET(rtsock, &select_fd)) + rtmsg_input(); + if (FD_ISSET(sock, &select_fd)) + rtadvd_input(); + } + exit(0); /* NOTREACHED */ +} + +static void +rtadvd_set_dump_file() +{ + do_dump = 1; +} + +static void +set_die(sig) + int sig; +{ + do_die = 1; +} + +static void +die() +{ + struct rainfo *ra; + int i; + const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS; + + if (dflag > 1) { + syslog(LOG_DEBUG, "<%s> cease to be an advertising router\n", + __FUNCTION__); + } + + for (ra = ralist; ra; ra = ra->next) { + ra->lifetime = 0; + make_packet(ra); + } + for (i = 0; i < retrans; i++) { + for (ra = ralist; ra; ra = ra->next) + ra_output(ra); + sleep(MIN_DELAY_BETWEEN_RAS); + } + exit(0); + /*NOTREACHED*/ +} + +static void +rtmsg_input() +{ + int n, type, ifindex = 0, plen; + size_t len; + char msg[2048], *next, *lim; + u_char ifname[IF_NAMESIZE]; + struct prefix *prefix; + struct rainfo *rai; + struct in6_addr *addr; + char addrbuf[INET6_ADDRSTRLEN]; + + n = read(rtsock, msg, sizeof(msg)); + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> received a routing message " + "(type = %d, len = %d)", + __FUNCTION__, + rtmsg_type(msg), n); + } + if (n > rtmsg_len(msg)) { + /* + * This usually won't happen for messages received on + * a routing socket. + */ + if (dflag > 1) + syslog(LOG_DEBUG, + "<%s> received data length is larger than" + "1st routing message len. multiple messages?" + " read %d bytes, but 1st msg len = %d", + __FUNCTION__, n, rtmsg_len(msg)); +#if 0 + /* adjust length */ + n = rtmsg_len(msg); +#endif + } + + lim = msg + n; + for (next = msg; next < lim; next += len) { + int oldifflags; + + next = get_next_msg(next, lim, 0, &len, + RTADV_TYPE2BITMASK(RTM_ADD) | + RTADV_TYPE2BITMASK(RTM_DELETE) | + RTADV_TYPE2BITMASK(RTM_NEWADDR) | + RTADV_TYPE2BITMASK(RTM_DELADDR) | + RTADV_TYPE2BITMASK(RTM_IFINFO)); + if (len == 0) + break; + type = rtmsg_type(next); + switch (type) { + case RTM_ADD: + case RTM_DELETE: + ifindex = get_rtm_ifindex(next); + break; + case RTM_NEWADDR: + case RTM_DELADDR: + ifindex = get_ifam_ifindex(next); + break; + case RTM_IFINFO: + ifindex = get_ifm_ifindex(next); + break; + default: + /* should not reach here */ + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __FUNCTION__, __LINE__, type, + if_indextoname(ifindex, ifname)); + } + continue; + } + + if ((rai = if_indextorainfo(ifindex)) == NULL) { + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> route changed on " + "non advertising interface(%s)", + __FUNCTION__, + if_indextoname(ifindex, ifname)); + } + continue; + } + oldifflags = iflist[ifindex]->ifm_flags; + + switch(type) { + case RTM_ADD: + /* init ifflags because it may have changed */ + iflist[ifindex]->ifm_flags = + if_getflags(ifindex, + iflist[ifindex]->ifm_flags); + + if (sflag) + break; /* we aren't interested in prefixes */ + + addr = get_addr(msg); + plen = get_prefixlen(msg); + /* sanity check for plen */ + if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ + || plen > 127) { + syslog(LOG_INFO, "<%s> new interface route's" + "plen %d is invalid for a prefix", + __FUNCTION__, plen); + break; + } + prefix = find_prefix(rai, addr, plen); + if (prefix) { + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> new prefix(%s/%d) " + "added on %s, " + "but it was already in list", + __FUNCTION__, + inet_ntop(AF_INET6, + addr, (char *)addrbuf, + INET6_ADDRSTRLEN), + plen, + rai->ifname); + } + break; + } + make_prefix(rai, ifindex, addr, plen); + break; + case RTM_DELETE: + /* init ifflags because it may have changed */ + iflist[ifindex]->ifm_flags = + if_getflags(ifindex, + iflist[ifindex]->ifm_flags); + + if (sflag) + break; + + addr = get_addr(msg); + plen = get_prefixlen(msg); + /* sanity check for plen */ + if (plen < 4 /* as RFC2373, prefixlen is at least 4 */ + || plen > 127) { + syslog(LOG_INFO, "<%s> deleted interface" + "route's" + "plen %d is invalid for a prefix", + __FUNCTION__, plen); + break; + } + prefix = find_prefix(rai, addr, plen); + if (prefix == NULL) { + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s> prefix(%s/%d) was " + "deleted on %s, " + "but it was not in list", + __FUNCTION__, + inet_ntop(AF_INET6, + addr, (char *)addrbuf, + INET6_ADDRSTRLEN), + plen, + rai->ifname); + } + break; + } + delete_prefix(rai, prefix); + break; + case RTM_NEWADDR: + case RTM_DELADDR: + /* init ifflags because it may have changed */ + iflist[ifindex]->ifm_flags = + if_getflags(ifindex, + iflist[ifindex]->ifm_flags); + break; + case RTM_IFINFO: + iflist[ifindex]->ifm_flags = get_ifm_flags(next); + break; + default: + /* should not reach here */ + if (dflag > 1) { + syslog(LOG_DEBUG, + "<%s:%d> unknown rtmsg %d on %s", + __FUNCTION__, __LINE__, type, + if_indextoname(ifindex, ifname)); + } + return; + } + + /* check if an interface flag is changed */ + if ((oldifflags & IFF_UP) != 0 && /* UP to DOWN */ + (iflist[ifindex]->ifm_flags & IFF_UP) == 0) { + syslog(LOG_INFO, + "<%s> interface %s becomes down. stop timer.", + __FUNCTION__, rai->ifname); + rtadvd_remove_timer(&rai->timer); + } + else if ((oldifflags & IFF_UP) == 0 && /* DOWN to UP */ + (iflist[ifindex]->ifm_flags & IFF_UP) != 0) { + syslog(LOG_INFO, + "<%s> interface %s becomes up. restart timer.", + __FUNCTION__, rai->ifname); + + rai->initcounter = 0; /* reset the counter */ + rai->waiting = 0; /* XXX */ + rai->timer = rtadvd_add_timer(ra_timeout, + ra_timer_update, + rai, rai); + ra_timer_update((void *)rai, &rai->timer->tm); + rtadvd_set_timer(&rai->timer->tm, rai->timer); + } + } + + return; +} + +void +rtadvd_input() +{ + int i; + int *hlimp = NULL; +#ifdef OLDRAWSOCKET + struct ip6_hdr *ip; +#endif + struct icmp6_hdr *icp; + int ifindex = 0; + struct cmsghdr *cm; + struct in6_pktinfo *pi = NULL; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + struct in6_addr dst = in6addr_any; + + /* + * Get message. We reset msg_controllen since the field could + * be modified if we had received a message before setting + * receive options. + */ + rcvmhdr.msg_controllen = rcvcmsgbuflen; + if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0) + return; + + /* extract optional information via Advanced API */ + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); + cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO && + cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { + pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); + ifindex = pi->ipi6_ifindex; + dst = pi->ipi6_addr; + } + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_HOPLIMIT && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + hlimp = (int *)CMSG_DATA(cm); + } + if (ifindex == 0) { + syslog(LOG_ERR, + "<%s> failed to get receiving interface", + __FUNCTION__); + return; + } + if (hlimp == NULL) { + syslog(LOG_ERR, + "<%s> failed to get receiving hop limit", + __FUNCTION__); + return; + } + + /* + * If we happen to receive data on an interface which is now down, + * just discard the data. + */ + if ((iflist[pi->ipi6_ifindex]->ifm_flags & IFF_UP) == 0) { + syslog(LOG_INFO, + "<%s> received data on a disabled interface (%s)", + __FUNCTION__, + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + +#ifdef OLDRAWSOCKET + if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) { + syslog(LOG_ERR, + "<%s> packet size(%d) is too short", + __FUNCTION__, i); + return; + } + + ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base; + icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */ +#else + if (i < sizeof(struct icmp6_hdr)) { + syslog(LOG_ERR, + "<%s> packet size(%d) is too short", + __FUNCTION__, i); + return; + } + + icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; +#endif + + switch(icp->icmp6_type) { + case ND_ROUTER_SOLICIT: + /* + * Message verification - RFC-2461 6.1.1 + * XXX: these checks must be done in the kernel as well, + * but we can't completely rely on them. + */ + if (*hlimp != 255) { + syslog(LOG_NOTICE, + "<%s> RS with invalid hop limit(%d) " + "received from %s on %s", + __FUNCTION__, *hlimp, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + if (icp->icmp6_code) { + syslog(LOG_NOTICE, + "<%s> RS with invalid ICMP6 code(%d) " + "received from %s on %s", + __FUNCTION__, icp->icmp6_code, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + if (i < sizeof(struct nd_router_solicit)) { + syslog(LOG_NOTICE, + "<%s> RS from %s on %s does not have enough " + "length (len = %d)", + __FUNCTION__, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); + return; + } + rs_input(i, (struct nd_router_solicit *)icp, pi, &from); + break; + case ND_ROUTER_ADVERT: + /* + * Message verification - RFC-2461 6.1.2 + * XXX: there's a same dilemma as above... + */ + if (*hlimp != 255) { + syslog(LOG_NOTICE, + "<%s> RA with invalid hop limit(%d) " + "received from %s on %s", + __FUNCTION__, *hlimp, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + if (icp->icmp6_code) { + syslog(LOG_NOTICE, + "<%s> RA with invalid ICMP6 code(%d) " + "received from %s on %s", + __FUNCTION__, icp->icmp6_code, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + if (i < sizeof(struct nd_router_advert)) { + syslog(LOG_NOTICE, + "<%s> RA from %s on %s does not have enough " + "length (len = %d)", + __FUNCTION__, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf), i); + return; + } + ra_input(i, (struct nd_router_advert *)icp, pi, &from); + break; + case ICMP6_ROUTER_RENUMBERING: + if (accept_rr == 0) { + syslog(LOG_ERR, + "<%s> received a router renumbering " + "message, but not allowed to be accepted", + __FUNCTION__); + break; + } + rr_input(i, (struct icmp6_router_renum *)icp, pi, &from, + &dst); + break; + default: + /* + * Note that this case is POSSIBLE, especially just + * after invocation of the daemon. This is because we + * could receive message after opening the socket and + * before setting ICMP6 type filter(see sock_open()). + */ + syslog(LOG_ERR, + "<%s> invalid icmp type(%d)", + __FUNCTION__, icp->icmp6_type); + return; + } + + return; +} + +static void +rs_input(int len, struct nd_router_solicit *rs, + struct in6_pktinfo *pi, struct sockaddr_in6 *from) +{ + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + union nd_opts ndopts; + struct rainfo *ra; + + syslog(LOG_DEBUG, + "<%s> RS received from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + /* ND option check */ + memset(&ndopts, 0, sizeof(ndopts)); + if (nd6_options((struct nd_opt_hdr *)(rs + 1), + len - sizeof(struct nd_router_solicit), + &ndopts, NDOPT_FLAG_SRCLINKADDR)) { + syslog(LOG_DEBUG, + "<%s> ND option check failed for an RS from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + /* + * If the IP source address is the unspecified address, there + * must be no source link-layer address option in the message. + * (RFC-2461 6.1.1) + */ + if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) && + ndopts.nd_opts_src_lladdr) { + syslog(LOG_ERR, + "<%s> RS from unspecified src on %s has a link-layer" + " address option", + __FUNCTION__, + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + goto done; + } + + ra = ralist; + while (ra != NULL) { + if (pi->ipi6_ifindex == ra->ifindex) + break; + ra = ra->next; + } + if (ra == NULL) { + syslog(LOG_INFO, + "<%s> RS received on non advertising interface(%s)", + __FUNCTION__, + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + goto done; + } + + ra->rsinput++; /* increment statistics */ + + /* + * Decide whether to send RA according to the rate-limit + * consideration. + */ + { + long delay; /* must not be greater than 1000000 */ + struct timeval interval, now, min_delay, tm_tmp, *rest; + struct soliciter *sol; + + /* + * record sockaddr waiting for RA, if possible + */ + sol = (struct soliciter *)malloc(sizeof(*sol)); + if (sol) { + sol->addr = *from; + /*XXX RFC2553 need clarification on flowinfo */ + sol->addr.sin6_flowinfo = 0; + sol->next = ra->soliciter; + ra->soliciter = sol->next; + } + + /* + * If there is already a waiting RS packet, don't + * update the timer. + */ + if (ra->waiting++) + goto done; + + /* + * Compute a random delay. If the computed value + * corresponds to a time later than the time the next + * multicast RA is scheduled to be sent, ignore the random + * delay and send the advertisement at the + * already-scheduled time. RFC-2461 6.2.6 + */ + delay = random() % MAX_RA_DELAY_TIME; + interval.tv_sec = 0; + interval.tv_usec = delay; + rest = rtadvd_timer_rest(ra->timer); + if (TIMEVAL_LT(*rest, interval)) { + syslog(LOG_DEBUG, + "<%s> random delay is larger than " + "the rest of normal timer", + __FUNCTION__); + interval = *rest; + } + + /* + * If we sent a multicast Router Advertisement within + * the last MIN_DELAY_BETWEEN_RAS seconds, schedule + * the advertisement to be sent at a time corresponding to + * MIN_DELAY_BETWEEN_RAS plus the random value after the + * previous advertisement was sent. + */ + gettimeofday(&now, NULL); + TIMEVAL_SUB(&now, &ra->lastsent, &tm_tmp); + min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS; + min_delay.tv_usec = 0; + if (TIMEVAL_LT(tm_tmp, min_delay)) { + TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay); + TIMEVAL_ADD(&min_delay, &interval, &interval); + } + rtadvd_set_timer(&interval, ra->timer); + goto done; + } + + done: + free_ndopts(&ndopts); + return; +} + +static void +ra_input(int len, struct nd_router_advert *ra, + struct in6_pktinfo *pi, struct sockaddr_in6 *from) +{ + struct rainfo *rai; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + union nd_opts ndopts; + char *on_off[] = {"OFF", "ON"}; + u_int32_t reachabletime, retranstimer, mtu; + int inconsistent = 0; + + syslog(LOG_DEBUG, + "<%s> RA received from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + + /* ND option check */ + memset(&ndopts, 0, sizeof(ndopts)); + if (nd6_options((struct nd_opt_hdr *)(ra + 1), + len - sizeof(struct nd_router_advert), + &ndopts, NDOPT_FLAG_SRCLINKADDR | + NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { + syslog(LOG_ERR, + "<%s> ND option check failed for an RA from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + /* + * RA consistency check according to RFC-2461 6.2.7 + */ + if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) { + syslog(LOG_INFO, + "<%s> received RA from %s on non-advertising" + " interface(%s)", + __FUNCTION__, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + goto done; + } + rai->rainput++; /* increment statistics */ + + /* Cur Hop Limit value */ + if (ra->nd_ra_curhoplimit && rai->hoplimit && + ra->nd_ra_curhoplimit != rai->hoplimit) { + syslog(LOG_INFO, + "<%s> CurHopLimit inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, + ra->nd_ra_curhoplimit, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->hoplimit); + inconsistent++; + } + /* M flag */ + if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) != + rai->managedflg) { + syslog(LOG_INFO, + "<%s> M flag inconsistent on %s:" + " %s from %s, %s from us", + __FUNCTION__, + rai->ifname, + on_off[!rai->managedflg], + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + on_off[rai->managedflg]); + inconsistent++; + } + /* O flag */ + if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) != + rai->otherflg) { + syslog(LOG_INFO, + "<%s> O flag inconsistent on %s:" + " %s from %s, %s from us", + __FUNCTION__, + rai->ifname, + on_off[!rai->otherflg], + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + on_off[rai->otherflg]); + inconsistent++; + } + /* Reachable Time */ + reachabletime = ntohl(ra->nd_ra_reachable); + if (reachabletime && rai->reachabletime && + reachabletime != rai->reachabletime) { + syslog(LOG_INFO, + "<%s> ReachableTime inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, + reachabletime, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->reachabletime); + inconsistent++; + } + /* Retrans Timer */ + retranstimer = ntohl(ra->nd_ra_retransmit); + if (retranstimer && rai->retranstimer && + retranstimer != rai->retranstimer) { + syslog(LOG_INFO, + "<%s> RetranceTimer inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, + retranstimer, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->retranstimer); + inconsistent++; + } + /* Values in the MTU options */ + if (ndopts.nd_opts_mtu) { + mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu); + if (mtu && rai->linkmtu && mtu != rai->linkmtu) { + syslog(LOG_INFO, + "<%s> MTU option value inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + rai->ifname, mtu, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->linkmtu); + inconsistent++; + } + } + /* Preferred and Valid Lifetimes for prefixes */ + { + struct nd_optlist *optp = ndopts.nd_opts_list; + + if (ndopts.nd_opts_pi) { + if (prefix_check(ndopts.nd_opts_pi, rai, from)) + inconsistent++; + } + while (optp) { + if (prefix_check((struct nd_opt_prefix_info *)optp->opt, + rai, from)) + inconsistent++; + optp = optp->next; + } + } + + if (inconsistent) + rai->rainconsistent++; + + done: + free_ndopts(&ndopts); + return; +} + +/* return a non-zero value if the received prefix is inconsitent with ours */ +static int +prefix_check(struct nd_opt_prefix_info *pinfo, + struct rainfo *rai, struct sockaddr_in6 *from) +{ + u_int32_t preferred_time, valid_time; + struct prefix *pp; + int inconsistent = 0; + u_char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN]; + struct timeval now; + +#if 0 /* impossible */ + if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION) + return(0); +#endif + + /* + * log if the adveritsed prefix has link-local scope(sanity check?) + */ + if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) { + syslog(LOG_INFO, + "<%s> link-local prefix %s/%d is advertised " + "from %s on %s", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->ifname); + } + + if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix, + pinfo->nd_opt_pi_prefix_len)) == NULL) { + syslog(LOG_INFO, + "<%s> prefix %s/%d from %s on %s is not in our list", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + rai->ifname); + return(0); + } + + preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time); + if (pp->pltimeexpire) { + /* + * The lifetime is decremented in real time, so we should + * compare the expiration time. + * (RFC 2461 Section 6.2.7.) + * XXX: can we really expect that all routers on the link + * have synchronized clocks? + */ + gettimeofday(&now, NULL); + preferred_time += now.tv_sec; + + if (rai->clockskew && + abs(preferred_time - pp->pltimeexpire) > rai->clockskew) { + syslog(LOG_INFO, + "<%s> prefeerred lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld from us", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + rai->ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + pp->pltimeexpire); + inconsistent++; + } + } + else if (preferred_time != pp->preflifetime) { + syslog(LOG_INFO, + "<%s> prefeerred lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + rai->ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + pp->preflifetime); + } + + valid_time = ntohl(pinfo->nd_opt_pi_valid_time); + if (pp->vltimeexpire) { + gettimeofday(&now, NULL); + valid_time += now.tv_sec; + + if (rai->clockskew && + abs(valid_time - pp->vltimeexpire) > rai->clockskew) { + syslog(LOG_INFO, + "<%s> valid lifetime for %s/%d" + " (decr. in real time) inconsistent on %s:" + " %d from %s, %ld from us", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + rai->ifname, preferred_time, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + pp->vltimeexpire); + inconsistent++; + } + } + else if (valid_time != pp->validlifetime) { + syslog(LOG_INFO, + "<%s> valid lifetime for %s/%d" + " inconsistent on %s:" + " %d from %s, %d from us", + __FUNCTION__, + inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix, + prefixbuf, INET6_ADDRSTRLEN), + pinfo->nd_opt_pi_prefix_len, + rai->ifname, valid_time, + inet_ntop(AF_INET6, &from->sin6_addr, + ntopbuf, INET6_ADDRSTRLEN), + pp->validlifetime); + inconsistent++; + } + + return(inconsistent); +} + +struct prefix * +find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen) +{ + struct prefix *pp; + int bytelen, bitlen; + + for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) { + if (plen != pp->prefixlen) + continue; + bytelen = plen / 8; + bitlen = plen % 8; + if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen)) + continue; + if (prefix->s6_addr[bytelen] >> (8 - bitlen) == + pp->prefix.s6_addr[bytelen] >> (8 - bitlen)) + return(pp); + } + + return(NULL); +} + +/* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */ +int +prefix_match(struct in6_addr *p0, int plen0, + struct in6_addr *p1, int plen1) +{ + int bytelen, bitlen; + + if (plen0 < plen1) + return(0); + bytelen = plen1 / 8; + bitlen = plen1 % 8; + if (memcmp((void *)p0, (void *)p1, bytelen)) + return(0); + if (p0->s6_addr[bytelen] >> (8 - bitlen) == + p1->s6_addr[bytelen] >> (8 - bitlen)) + return(1); + + return(0); +} + +static int +nd6_options(struct nd_opt_hdr *hdr, int limit, + union nd_opts *ndopts, u_int32_t optflags) +{ + int optlen = 0; + + for (; limit > 0; limit -= optlen) { + hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen); + optlen = hdr->nd_opt_len << 3; + if (hdr->nd_opt_len == 0) { + syslog(LOG_ERR, + "<%s> bad ND option length(0) (type = %d)", + __FUNCTION__, hdr->nd_opt_type); + goto bad; + } + + if (hdr->nd_opt_type > ND_OPT_MTU) { + syslog(LOG_INFO, + "<%s> unknown ND option(type %d)", + __FUNCTION__, + hdr->nd_opt_type); + continue; + } + + if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) { + syslog(LOG_INFO, + "<%s> unexpected ND option(type %d)", + __FUNCTION__, + hdr->nd_opt_type); + continue; + } + + switch(hdr->nd_opt_type) { + case ND_OPT_SOURCE_LINKADDR: + case ND_OPT_TARGET_LINKADDR: + case ND_OPT_REDIRECTED_HEADER: + case ND_OPT_MTU: + if (ndopts->nd_opt_array[hdr->nd_opt_type]) { + syslog(LOG_INFO, + "<%s> duplicated ND option" + " (type = %d)", + __FUNCTION__, + hdr->nd_opt_type); + } + ndopts->nd_opt_array[hdr->nd_opt_type] = hdr; + break; + case ND_OPT_PREFIX_INFORMATION: + { + struct nd_optlist *pfxlist; + + if (ndopts->nd_opts_pi == 0) { + ndopts->nd_opts_pi = + (struct nd_opt_prefix_info *)hdr; + continue; + } + if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate memory", + __FUNCTION__); + goto bad; + } + pfxlist->next = ndopts->nd_opts_list; + pfxlist->opt = hdr; + ndopts->nd_opts_list = pfxlist; + + break; + } + default: /* impossible */ + break; + } + } + + return(0); + + bad: + free_ndopts(ndopts); + + return(-1); +} + +static void +free_ndopts(union nd_opts *ndopts) +{ + struct nd_optlist *opt = ndopts->nd_opts_list, *next; + + while(opt) { + next = opt->next; + free(opt); + opt = next; + } +} + +void +sock_open() +{ + struct icmp6_filter filt; + struct ipv6_mreq mreq; + struct rainfo *ra = ralist; + int on; + /* XXX: should be max MTU attached to the node */ + static u_char answer[1500]; + + rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen); + if (rcvcmsgbuf == NULL) { + syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); + exit(1); + } + + sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen); + if (sndcmsgbuf == NULL) { + syslog(LOG_ERR, "<%s> not enough core", __FUNCTION__); + exit(1); + } + + if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__, + strerror(errno)); + exit(1); + } + + /* specify to tell receiving interface */ + on = 1; +#ifdef IPV6_RECVPKTINFO + if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVPKTINFO: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_PKTINFO: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } +#endif + + on = 1; + /* specify to tell value of hoplimit field of received IP6 hdr */ +#ifdef IPV6_RECVHOPLIMIT + if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_RECVHOPLIMIT: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, + sizeof(on)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_HOPLIMIT: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } +#endif + + ICMP6_FILTER_SETBLOCKALL(&filt); + ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt); + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); + if (accept_rr) + ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt); + if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + sizeof(filt)) < 0) { + syslog(LOG_ERR, "<%s> IICMP6_FILTER: %s", + __FUNCTION__, strerror(errno)); + exit(1); + } + + /* + * join all routers multicast address on each advertising interface. + */ + if (inet_pton(AF_INET6, ALLROUTERS_LINK, + &mreq.ipv6mr_multiaddr.s6_addr) + != 1) { + syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", + __FUNCTION__); + exit(1); + } + while(ra) { + mreq.ipv6mr_interface = ra->ifindex; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, + sizeof(mreq)) < 0) { + syslog(LOG_ERR, "<%s> IPV6_JOIN_GROUP(link) on %s: %s", + __FUNCTION__, ra->ifname, strerror(errno)); + exit(1); + } + ra = ra->next; + } + + /* + * When attending router renumbering, join all-routers site-local + * multicast group. + */ + if (accept_rr) { + if (inet_pton(AF_INET6, ALLROUTERS_SITE, + &in6a_site_allrouters) != 1) { + syslog(LOG_ERR, "<%s> inet_pton failed(library bug?)", + __FUNCTION__); + exit(1); + } + mreq.ipv6mr_multiaddr = in6a_site_allrouters; + if (mcastif) { + if ((mreq.ipv6mr_interface = if_nametoindex(mcastif)) + == 0) { + syslog(LOG_ERR, + "<%s> invalid interface: %s", + __FUNCTION__, mcastif); + exit(1); + } + } else + mreq.ipv6mr_interface = ralist->ifindex; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq, sizeof(mreq)) < 0) { + syslog(LOG_ERR, + "<%s> IPV6_JOIN_GROUP(site) on %s: %s", + __FUNCTION__, + mcastif ? mcastif : ralist->ifname, + strerror(errno)); + exit(1); + } + } + + /* initialize msghdr for receiving packets */ + rcviov[0].iov_base = (caddr_t)answer; + rcviov[0].iov_len = sizeof(answer); + rcvmhdr.msg_name = (caddr_t)&from; + rcvmhdr.msg_namelen = sizeof(from); + rcvmhdr.msg_iov = rcviov; + rcvmhdr.msg_iovlen = 1; + rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; + rcvmhdr.msg_controllen = rcvcmsgbuflen; + + /* initialize msghdr for sending packets */ + sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); + sndmhdr.msg_iov = sndiov; + sndmhdr.msg_iovlen = 1; + sndmhdr.msg_control = (caddr_t)sndcmsgbuf; + sndmhdr.msg_controllen = sndcmsgbuflen; + + return; +} + +/* open a routing socket to watch the routing table */ +static void +rtsock_open() +{ + if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { + syslog(LOG_ERR, + "<%s> socket: %s", __FUNCTION__, strerror(errno)); + exit(1); + } +} + +struct rainfo * +if_indextorainfo(int index) +{ + struct rainfo *rai = ralist; + + for (rai = ralist; rai; rai = rai->next) { + if (rai->ifindex == index) + return(rai); + } + + return(NULL); /* search failed */ +} + +static void +ra_output(rainfo) +struct rainfo *rainfo; +{ + int i; + struct cmsghdr *cm; + struct in6_pktinfo *pi; + struct soliciter *sol, *nextsol; + + if ((iflist[rainfo->ifindex]->ifm_flags & IFF_UP) == 0) { + syslog(LOG_DEBUG, "<%s> %s is not up, skip sending RA", + __FUNCTION__, rainfo->ifname); + return; + } + + make_packet(rainfo); /* XXX: inefficient */ + + sndmhdr.msg_name = (caddr_t)&sin6_allnodes; + sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data; + sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen; + + cm = CMSG_FIRSTHDR(&sndmhdr); + /* specify the outgoing interface */ + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pi = (struct in6_pktinfo *)CMSG_DATA(cm); + memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ + pi->ipi6_ifindex = rainfo->ifindex; + + /* specify the hop limit of the packet */ + { + int hoplimit = 255; + + cm = CMSG_NXTHDR(&sndmhdr, cm); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_HOPLIMIT; + cm->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); + } + + syslog(LOG_DEBUG, + "<%s> send RA on %s, # of waitings = %d", + __FUNCTION__, rainfo->ifname, rainfo->waiting); + + i = sendmsg(sock, &sndmhdr, 0); + + if (i < 0 || i != rainfo->ra_datalen) { + if (i < 0) { + syslog(LOG_ERR, "<%s> sendmsg on %s: %s", + __FUNCTION__, rainfo->ifname, + strerror(errno)); + } + } + + /* + * unicast advertisements + * XXX commented out. reason: though spec does not forbit it, unicast + * advert does not really help + */ + for (sol = rainfo->soliciter; sol; sol = nextsol) { + nextsol = sol->next; + +#if 0 + sndmhdr.msg_name = (caddr_t)&sol->addr; + i = sendmsg(sock, &sndmhdr, 0); + if (i < 0 || i != rainfo->ra_datalen) { + if (i < 0) { + syslog(LOG_ERR, + "<%s> unicast sendmsg on %s: %s", + __FUNCTION__, rainfo->ifname, + strerror(errno)); + } + } +#endif + + sol->next = NULL; + free(sol); + } + rainfo->soliciter = NULL; + + /* update counter */ + if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS) + rainfo->initcounter++; + rainfo->raoutput++; + + /* update timestamp */ + gettimeofday(&rainfo->lastsent, NULL); + + /* reset waiting conter */ + rainfo->waiting = 0; +} + +/* process RA timer */ +void +ra_timeout(void *data) +{ + struct rainfo *rai = (struct rainfo *)data; + +#ifdef notyet + /* if necessary, reconstruct the packet. */ +#endif + + syslog(LOG_DEBUG, + "<%s> RA timer on %s is expired", + __FUNCTION__, rai->ifname); + + ra_output(rai); +} + +/* update RA timer */ +void +ra_timer_update(void *data, struct timeval *tm) +{ + struct rainfo *rai = (struct rainfo *)data; + long interval; + + /* + * Whenever a multicast advertisement is sent from an interface, + * the timer is reset to a uniformly-distributed random value + * between the interface's configured MinRtrAdvInterval and + * MaxRtrAdvInterval (RFC2461 6.2.4). + */ + interval = rai->mininterval; + interval += random() % (rai->maxinterval - rai->mininterval); + + /* + * For the first few advertisements (up to + * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval + * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer + * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead. + * (RFC-2461 6.2.4) + */ + if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS && + interval > MAX_INITIAL_RTR_ADVERT_INTERVAL) + interval = MAX_INITIAL_RTR_ADVERT_INTERVAL; + + tm->tv_sec = interval; + tm->tv_usec = 0; + + syslog(LOG_DEBUG, + "<%s> RA timer on %s is set to %ld:%ld", + __FUNCTION__, rai->ifname, + (long int)tm->tv_sec, (long int)tm->tv_usec); + + return; +} diff --git a/rtadvd.tproj/rtadvd.conf b/rtadvd.tproj/rtadvd.conf new file mode 100644 index 0000000..4c653ed --- /dev/null +++ b/rtadvd.tproj/rtadvd.conf @@ -0,0 +1,21 @@ +# $FreeBSD: src/usr.sbin/rtadvd/rtadvd.conf,v 1.1.2.2 2001/02/22 07:51:05 ume Exp $ +# $KAME: rtadvd.conf,v 1.12 2001/01/21 14:56:38 itojun Exp $ +# +# Note: All of the following parameters have default values defined +# in specifications, and hence you usually do not have to set them +# by hand unless you need special non-default values. +# +# You even do not need to create the configuration file. rtadvd +# would usually work well without a configuration file. +# See also: rtadvd(8) + +# per-interface definitions. +# Mainly IPv6 prefixes are configured in this part. However, rtadvd +# automatically learns appropriate prefixes from the kernel's routing +# table, and advertises the prefixes, so you don't have to configure +# this part, either. +# If you don't want the automatic advertisement, (uncomment and) configure +# this part by hand, and then invoke rtadvd with the -s option. + +#ef0:\ +# :addrs#1:addr="3ffe:501:ffff:1000::":prefixlen#64: diff --git a/rtadvd.tproj/rtadvd.conf.5 b/rtadvd.tproj/rtadvd.conf.5 new file mode 100644 index 0000000..8922441 --- /dev/null +++ b/rtadvd.tproj/rtadvd.conf.5 @@ -0,0 +1,386 @@ +.\" $FreeBSD: src/usr.sbin/rtadvd/rtadvd.conf.5,v 1.1.2.8 2001/08/16 15:56:30 ru Exp $ +.\" $KAME: rtadvd.conf.5,v 1.35 2001/05/25 07:40:22 jinmei 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. 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. +.\" +.Dd May 17, 1998 +.Dt RTADVD.CONF 5 +.Os +.Sh NAME +.Nm rtadvd.conf +.Nd config file for router advertisement daemon +.Sh DESCRIPTION +This file describes how the router advertisement packets must be constructed +for each of the interfaces. +.Pp +As described in +.Xr rtadvd 8 , +you do not have to set this configuration file up at all, +unless you need some special configurations. +You may even omit the file as a whole. +In such cases, the +.Nm rtadvd +daemon will automatically configure itself using default values +specified in the specification. +.Pp +It obeys the famous +.Xr termcap 5 +file format. +Each line in the file describes a network interface. +Fields are separated by a colon +.Pq Sq \&: , +and each field contains one capability description. +Lines may be concatenated by the +.Sq \e +character. +The comment marker is the +.Sq \&# +character. +.Sh CAPABILITIES +Capabilities describe the value to be filled into ICMPv6 router +advertisement messages and to control +.Xr rtadvd 8 +behavior. +Therefore, you are encouraged to read IETF neighbor discovery documents +if you would like to modify the sample configuration file. +.Pp +Note that almost all items have default values. +If you omit an item, the default value of the item will be used. +.Pp +There are two items which control the interval of sending router advertisements. +These items can be omitted, then +.Nm rtadvd +will use the default values. +.Bl -tag -width indent +.It Cm \&maxinterval +(num) The maximum time allowed between sending unsolicited +multicast router advertisements +(unit: seconds). +The default value is 600. +Its value must be no less than 4 seconds +and no greater than 1800 seconds. +.It Cm \&mininterval +(num) The minimum time allowed between sending unsolicited multicast +router advertisements +(unit: seconds). +The default value is the one third of value of +.Cm maxinterval . +Its value must be no less than 3 seconds and no greater than .75 * +the value of +.Cm maxinterval . +.El +.Pp +The following items are for ICMPv6 router advertisement message +header. +These items can be omitted, then +.Nm rtadvd +will use the default values. +.Bl -tag -width indent +.It Cm \&chlim +(num) The value for Cur Hop Limit field. +The default value is 64. +.It Cm \&raflags +(num) Flags field in router advertisement message header. +Bit 7 +.Pq Li 0x80 +means Managed address configuration flag bit, +and Bit 6 +.Pq Li 0x40 +means Other stateful configuration flag bit. +Bit 4 +.Pq Li 0x10 +and Bit 3 +.Pq Li 0x08 +are used to encode router preference. +0x01 means high, 0x00 means medium, and 0x11 means low. +The default value is 0. +.It Cm \&rltime +(num) Router lifetime field +(unit: seconds). +Its value must be no greater than 3600000. +When +.Nm rtadvd +runs on a host, this value must explicitly set 0 on all the +advertising interfaces as described in +.Xr rtadvd 8 . +The default value is 1800. +.It Cm \&rtime +(num) Reachable time field +(unit: milliseconds). +The default value is 0, which means unspecified by this router. +.It Cm \&retrans +(num) Retrans Timer field +(unit: milliseconds). +The default value is 0, which means unspecified by this router. +.El +.Pp +The following items are for ICMPv6 prefix information option, +which will be attached to router advertisement header. +These items can be omitted, then +.Nm rtadvd +will automatically get appropriate prefixes from the kernel's routing table, +and advertise the prefixes with the default parameters. +.Bl -tag -width indent +.It Cm \&clockskew +(num) Time skew to adjust link propagation delays and clock skews +betwen routers on the link +(unit: seconds). +This value is used in consistency check for locally-configured and +advertised prefix lifetimes, and has its meaning when the local router +configures a prefix on the link with a lifetime that decrements in +real time. +If the value is 0, it means the consistency check will be skipped +for such prefixes. +The default value is 0. +.It Cm \&addrs +(num) Number of prefixes. +Its default is 0, so it must explicitly be set to positve values +if you want to specify any prefix information option. +If its value is 0, +.Xr rtadvd 8 +looks up the system routing table and +advertise the prefixes corresponding to interface routes +on the interface. +If its value is more than 1, you must specify the index of the prefix +for each item below. +Indices vary from 0 to N-1, where N is the +value of +.Cm addrs . +Each index shall follow the name of each item, e.g., +.Dq prefixlen2 . +.It Cm \&prefixlen +(num) Prefix length field. +The default value is 64. +.It Cm \&pinfoflags +(num) Flags field in prefix information option. +Bit 7 +.Pq Li 0x80 +means On-link flag bit, +and Bit 6 +.Pq Li 0x40 +means Autonomous address-configuration flag bit. +The default value is 0xc0, i.e., both bits are set. +.It Cm \&addr +(str) The address filled into Prefix field. +Since +.Dq \&: +is used for +.Xr termcap 5 +file format as well as IPv6 numeric address, the field MUST be quoted by +doublequote character. +This field cannot be +omitted if the value of +.Cm addrs +is more than 0. +.It Cm \&vltime +(num) Valid lifetime field +(unit: seconds). +The default value is 2592000 (30 days). +.It Cm \&vltimedecr +(bool) This item means the advertised valid lifetime will decrements +in real time, which is disabled by default. +.It Cm \&pltime +(num) Preferred lifetime field +(unit: seconds). +The default value is 604800 (7 days). +.It Cm \&pltimedecr +(bool) This item means the advertised preferred lifetime will decrements +in real time, which is disabled by default. +.El +.Pp +The following item is for ICMPv6 MTU option, +which will be attached to router advertisement header. +This item can be omitted, then +.Nm rtadvd +will use the default value. +.Bl -tag -width indent +.It Cm \&mtu +(num or str) MTU (maximum transmission unit) field. +If 0 is specified, it means that the option will not be included. +The default value is 0. +If the special string +.Dq auto +is specified for this item, MTU option will be included and its value +will be set to the interface MTU automatically. +.El +.Pp +The following item controls ICMPv6 source link-layer address option, +which will be attached to router advertisement header. +As noted above, you can just omit the item, then +.Nm rtadvd +will use the default value. +.Bl -tag -width indent +.It Cm \&nolladdr +(bool) By default +(if +.Cm \&nolladdr +is not specified), +.Xr rtadvd 8 +will try to get link-layer address for the interface from the kernel, +and attach that in source link-layer address option. +If this capability exists, +.Xr rtadvd 8 +will not attach source link-layer address option to +router advertisement packets. +.El +.Pp +The following item controls ICMPV6 home agent information option, +which was defined with mobile IPv6 support. +It will be attached to router advertisement header just like other options do. +.Bl -tag -width indent +.It Cm \&hapref +(num) Specifies home agent preference. +If set to non-zero, +.Cm \&hatime +must be present as well. +.It Cm \&hatime +(num) Specifies home agent lifetime. +.El +.Pp +When mobile IPv6 support is turned on for +.Xr rtadvd 8 , +advertisement interval option will be attached to router advertisement +packet, by configuring +.Cm \&maxinterval +explicitly. +.Pp +The following items are for ICMPv6 route information option, +which will be attached to router advertisement header. +These items are optional. +.Bl -tag -width indent +.It Cm \&routes +(num) Number of routes. +Its default is 0, so it must explicitly be set to positve values +if you want to specify any route information option. +If its value is 0, no route information is sent. +If its value is more than 1, you must specify the index of the routes +for each item below. +Indices vary from 0 to N-1, where N is the +value of +.Cm routes. +Each index shall follow the name of each item, e.g., +.Dq rtrplen2 . +.It Cm \&rtrplen +(num) Prefix length field in route information option. +The default value is 64. +.It Cm \&rtrflags +(num) Flags field in route information option. +Bit 4 +.Pq Li 0x10 +and +and Bit 3 +.Pq Li 0x08 +are used to encode router preference for the route. +The default value is 0x00, i.e. medium router preference. +.It Cm \&rtrprefix +(str) The prefix filled into the Prefix field of route information option. +Since +.Dq \&: +is used for +.Xr termcap 5 +file format as well as IPv6 numeric address, the field MUST be quoted by +doublequote character. +This field cannot be +omitted if the value of +.Cm addrs +is more than 0. +.It Cm \&rtrltime +(num) route lifetime field in route information option. +(unit: seconds). +The default value is 2592000 (30 days). (not specified in draft-draves-router-selection-01.txt now) +.El +You can also refer one line from another by using +.Cm tc +capability. +See +.Xr termcap 5 +for details on the capability. +.Sh EXAMPLES +As presented above, all of the advertised parameters have default values +defined in specifications, and hence you usually do not have to set them +by hand, unless you need special non-default values. +It can cause interoperability problem if you use an ill-configured +parameter. +.Pp +To override a configuration parameter, you can specify the parameter alone. +With the following configuration, +.Xr rtadvd 8 +overrides the router lifetime parameter for the +.Li ne0 +interface. +.Bd -literal -offset +ne0:\\ + :rltime#0: +.Ed +.Pp +The following example manually configures prefixes advertised from the +.Li ef0 +interface. +The configuration must be used with the +.Fl s +option to +.Xr rtadvd 8 . +.Bd -literal -offset +ef0:\\ + :addrs#1:addr="3ffe:501:ffff:1000::":prefixlen#64: +.Ed +.Pp +The following example presents the default values in an explicit manner. +The configuration is provided just for reference purposes; +YOU DO NOT NEED TO HAVE IT AT ALL. +.Bd -literal -offset +default:\\ + :chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\ + :pinfoflags#192:vltime#2592000:pltime#604800:mtu#0: +ef0:\\ + :addrs#1:addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default: +.Ed +.Sh SEE ALSO +.Xr termcap 5 , +.Xr rtadvd 8 , +.Xr rtsol 8 +.Pp +Thomas Narten, Erik Nordmark and W. A. Simpson, +.Do +Neighbor Discovery for IP version 6 (IPv6) +.Dc , +RFC 2461 +.Pp +Richard Draves, +.Do +Default Router Preferences and More-Specific Routes +.Dc , +draft-ietf-ipngwg-router-selection-01.txt +.Sh HISTORY +The +.Xr rtadvd 8 +and the configuration file +.Nm +first appeared in WIDE Hydrangea IPv6 protocol stack kit. +.\" .Sh BUGS +.\" (to be written) diff --git a/rtadvd.tproj/rtadvd.h b/rtadvd.tproj/rtadvd.h new file mode 100644 index 0000000..8845a2e --- /dev/null +++ b/rtadvd.tproj/rtadvd.h @@ -0,0 +1,172 @@ +/* $KAME: rtadvd.h,v 1.16 2001/04/10 15:08:31 suz Exp $ */ + +/* + * Copyright (C) 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/rtadvd.h,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +#define ALLNODES "ff02::1" +#define ALLROUTERS_LINK "ff02::2" +#define ALLROUTERS_SITE "ff05::2" +#define ANY "::" +#define RTSOLLEN 8 + +/* protocol constants and default values */ +#define DEF_MAXRTRADVINTERVAL 600 +#define DEF_ADVLINKMTU 0 +#define DEF_ADVREACHABLETIME 0 +#define DEF_ADVRETRANSTIMER 0 +#define DEF_ADVCURHOPLIMIT 64 +#define DEF_ADVVALIDLIFETIME 2592000 +#define DEF_ADVPREFERREDLIFETIME 604800 + +/*XXX int-to-double comparison for INTERVAL items */ +#ifndef MIP6 +#define mobileip6 0 +#endif + +#define MAXROUTERLIFETIME 9000 +#define MIN_MAXINTERVAL (mobileip6 ? 1.5 : 4.0) +#define MAX_MAXINTERVAL 1800 +#define MIN_MININTERVAL (mobileip6 ? 0.5 : 3) +#define MAXREACHABLETIME 3600000 + +#ifndef MIP6 +#undef miobileip6 +#endif + +#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 +#define MAX_INITIAL_RTR_ADVERTISEMENTS 3 +#define MAX_FINAL_RTR_ADVERTISEMENTS 3 +#define MIN_DELAY_BETWEEN_RAS 3 +#define MAX_RA_DELAY_TIME 500000 /* usec */ + +#define PREFIX_FROM_KERNEL 1 +#define PREFIX_FROM_CONFIG 2 +#define PREFIX_FROM_DYNAMIC 3 + +struct prefix { + struct prefix *next; /* forward link */ + struct prefix *prev; /* previous link */ + + u_int32_t validlifetime; /* AdvValidLifetime */ + long vltimeexpire; /* expiration of vltime; decrement case only */ + u_int32_t preflifetime; /* AdvPreferredLifetime */ + long pltimeexpire; /* expiration of pltime; decrement case only */ + u_int onlinkflg; /* bool: AdvOnLinkFlag */ + u_int autoconfflg; /* bool: AdvAutonomousFlag */ +#ifdef MIP6 + u_int routeraddr; /* bool: RouterAddress */ +#endif + int prefixlen; + int origin; /* from kernel or cofig */ + struct in6_addr prefix; +}; + +struct rtinfo { + struct rtinfo *prev; /* previous link */ + struct rtinfo *next; /* forward link */ + + u_int32_t ltime; /* route lifetime */ + u_int rtpref; /* router preference */ + int prefixlen; + struct in6_addr prefix; +}; + +struct soliciter { + struct soliciter *next; + struct sockaddr_in6 addr; +}; + +struct rainfo { + /* pointer for list */ + struct rainfo *next; + + /* timer related parameters */ + struct rtadvd_timer *timer; + int initcounter; /* counter for the first few advertisements */ + struct timeval lastsent; /* timestamp when the latest RA was sent */ + int waiting; /* number of RS waiting for RA */ + + /* interface information */ + int ifindex; + int advlinkopt; /* bool: whether include link-layer addr opt */ + struct sockaddr_dl *sdl; + char ifname[16]; + int phymtu; /* mtu of the physical interface */ + + /* Router configuration variables */ + u_short lifetime; /* AdvDefaultLifetime */ + u_int maxinterval; /* MaxRtrAdvInterval */ + u_int mininterval; /* MinRtrAdvInterval */ + int managedflg; /* AdvManagedFlag */ + int otherflg; /* AdvOtherConfigFlag */ +#ifdef MIP6 + int haflg; /* HAFlag */ +#endif + int rtpref; /* router preference */ + u_int32_t linkmtu; /* AdvLinkMTU */ + u_int32_t reachabletime; /* AdvReachableTime */ + u_int32_t retranstimer; /* AdvRetransTimer */ + u_int hoplimit; /* AdvCurHopLimit */ + struct prefix prefix; /* AdvPrefixList(link head) */ + int pfxs; /* number of prefixes */ + long clockskew; /* used for consisitency check of lifetimes */ + +#ifdef MIP6 + u_short hapref; /* Home Agent Preference */ + u_short hatime; /* Home Agent Lifetime */ +#endif + struct rtinfo route; /* route information option (link head) */ + int routes; /* number of route information options */ + + /* actual RA packet data and its length */ + size_t ra_datalen; + u_char *ra_data; + + /* statistics */ + u_quad_t raoutput; /* number of RAs sent */ + u_quad_t rainput; /* number of RAs received */ + u_quad_t rainconsistent; /* number of RAs inconsistent with ours */ + u_quad_t rsinput; /* number of RSs received */ + + /* info about soliciter */ + struct soliciter *soliciter; /* recent solication source */ +}; + +void ra_timeout __P((void *)); +void ra_timer_update __P((void *, struct timeval *)); + +int prefix_match __P((struct in6_addr *, int, struct in6_addr *, int)); +struct rainfo *if_indextorainfo __P((int)); + +extern struct in6_addr in6a_site_allrouters; +#ifdef MIP6 +extern int mobileip6; +#endif diff --git a/rtadvd.tproj/timer.c b/rtadvd.tproj/timer.c new file mode 100644 index 0000000..edfef55 --- /dev/null +++ b/rtadvd.tproj/timer.c @@ -0,0 +1,217 @@ +/* $KAME: timer.c,v 1.4 2000/05/27 11:30:43 jinmei Exp $ */ + +/* + * Copyright (C) 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/timer.c,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +#include + +#include +#include +#include +#include +#if defined(__NetBSD__) || defined(__OpenBSD__) +#include +#endif +#include "timer.h" + +static struct rtadvd_timer timer_head; + +#define MILLION 1000000 +#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\ + (t1)->tv_usec == (t2)->tv_usec) + +static struct timeval tm_max = {0x7fffffff, 0x7fffffff}; + +void +rtadvd_timer_init() +{ + memset(&timer_head, 0, sizeof(timer_head)); + + timer_head.next = timer_head.prev = &timer_head; + timer_head.tm = tm_max; +} + +struct rtadvd_timer * +rtadvd_add_timer(void (*timeout) __P((void *)), + void (*update) __P((void *, struct timeval *)), + void *timeodata, void *updatedata) +{ + struct rtadvd_timer *newtimer; + + if ((newtimer = malloc(sizeof(*newtimer))) == NULL) { + syslog(LOG_ERR, + "<%s> can't allocate memory", __FUNCTION__); + exit(1); + } + + memset(newtimer, 0, sizeof(*newtimer)); + + if (timeout == NULL) { + syslog(LOG_ERR, + "<%s> timeout function unspecfied", __FUNCTION__); + exit(1); + } + if (update == NULL) { + syslog(LOG_ERR, + "<%s> update function unspecfied", __FUNCTION__); + exit(1); + } + newtimer->expire = timeout; + newtimer->update = update; + newtimer->expire_data = timeodata; + newtimer->update_data = updatedata; + newtimer->tm = tm_max; + + /* link into chain */ + insque(newtimer, &timer_head); + + return(newtimer); +} + +void +rtadvd_remove_timer(struct rtadvd_timer **timer) +{ + remque(*timer); + free(*timer); + *timer = NULL; +} + +void +rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer) +{ + struct timeval now; + + /* reset the timer */ + gettimeofday(&now, NULL); + + TIMEVAL_ADD(&now, tm, &timer->tm); + + /* update the next expiration time */ + if (TIMEVAL_LT(timer->tm, timer_head.tm)) + timer_head.tm = timer->tm; + + return; +} + +/* + * Check expiration for each timer. If a timer is expired, + * call the expire function for the timer and update the timer. + * Return the next interval for select() call. + */ +struct timeval * +rtadvd_check_timer() +{ + static struct timeval returnval; + struct timeval now; + struct rtadvd_timer *tm = timer_head.next; + + gettimeofday(&now, NULL); + + timer_head.tm = tm_max; + + while(tm != &timer_head) { + if (TIMEVAL_LEQ(tm->tm, now)) { + (*tm->expire)(tm->expire_data); + (*tm->update)(tm->update_data, &tm->tm); + TIMEVAL_ADD(&tm->tm, &now, &tm->tm); + } + + if (TIMEVAL_LT(tm->tm, timer_head.tm)) + timer_head.tm = tm->tm; + + tm = tm->next; + } + + if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) { + /* no need to timeout */ + return(NULL); + } + else if (TIMEVAL_LT(timer_head.tm, now)) { + /* this may occur when the interval is too small */ + returnval.tv_sec = returnval.tv_usec = 0; + } + else + TIMEVAL_SUB(&timer_head.tm, &now, &returnval); + return(&returnval); +} + +struct timeval * +rtadvd_timer_rest(struct rtadvd_timer *timer) +{ + static struct timeval returnval, now; + + gettimeofday(&now, NULL); + if (TIMEVAL_LEQ(timer->tm, now)) { + syslog(LOG_DEBUG, + "<%s> a timer must be expired, but not yet", + __FUNCTION__); + returnval.tv_sec = returnval.tv_usec = 0; + } + else + TIMEVAL_SUB(&timer->tm, &now, &returnval); + + return(&returnval); +} + +/* result = a + b */ +void +TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec + b->tv_usec) < MILLION) { + result->tv_usec = l; + result->tv_sec = a->tv_sec + b->tv_sec; + } + else { + result->tv_usec = l - MILLION; + result->tv_sec = a->tv_sec + b->tv_sec + 1; + } +} + +/* + * result = a - b + * XXX: this function assumes that a >= b. + */ +void +TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec - b->tv_usec) >= 0) { + result->tv_usec = l; + result->tv_sec = a->tv_sec - b->tv_sec; + } + else { + result->tv_usec = MILLION + l; + result->tv_sec = a->tv_sec - b->tv_sec - 1; + } +} diff --git a/rtadvd.tproj/timer.h b/rtadvd.tproj/timer.h new file mode 100644 index 0000000..63705a1 --- /dev/null +++ b/rtadvd.tproj/timer.h @@ -0,0 +1,66 @@ +/* $KAME: timer.h,v 1.3 2000/05/27 11:30:43 jinmei Exp $ */ + +/* + * Copyright (C) 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. 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. + * + * $FreeBSD: src/usr.sbin/rtadvd/timer.h,v 1.1.2.2 2001/07/03 11:02:14 ume Exp $ + */ + +/* a < b */ +#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) && \ + ((a).tv_usec < (b).tv_usec))) + +/* a <= b */ +#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) &&\ + ((a).tv_usec <= (b).tv_usec))) + +struct rtadvd_timer { + struct rtadvd_timer *next; + struct rtadvd_timer *prev; + struct rainfo *rai; + struct timeval tm; + + void (*expire) __P((void *)); /* expiration function */ + void *expire_data; + void (*update) __P((void *, struct timeval *)); /* update function */ + void *update_data; +}; + +void rtadvd_timer_init __P((void)); +struct rtadvd_timer *rtadvd_add_timer __P((void (*) __P((void *)), + void (*) __P((void *, struct timeval *)), void *, void *)); +void rtadvd_set_timer __P((struct timeval *, struct rtadvd_timer *)); +void rtadvd_remove_timer __P((struct rtadvd_timer **)); +struct timeval * rtadvd_check_timer __P((void)); +struct timeval * rtadvd_timer_rest __P((struct rtadvd_timer *)); +void TIMEVAL_ADD __P((struct timeval *, struct timeval *, + struct timeval *)); +void TIMEVAL_SUB __P((struct timeval *, struct timeval *, + struct timeval *)); diff --git a/ftp.tproj/Makefile b/rtsol.tproj/Makefile similarity index 76% rename from ftp.tproj/Makefile rename to rtsol.tproj/Makefile index 980a8c2..f1a8386 100644 --- a/ftp.tproj/Makefile +++ b/rtsol.tproj/Makefile @@ -7,25 +7,25 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = ftp +NAME = rtsol PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -HFILES = extern.h ftp_var.h pathnames.h +CFILES = rtsold.c rtsol.c if.c probe.c dump.c rtsock.c +HFILES = rtsold.h -CFILES = cmds.c cmdtab.c domacro.c ftp.c ftp_var.c main.c\ - ruserpass.c - -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble m.template\ - h.template ftp.1 +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble Makefile.dist\ + rtsol.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles CODE_GEN_STYLE = DYNAMIC MAKEFILE = tool.make -NEXTSTEP_INSTALLDIR = /usr/bin -LIBS = +NEXTSTEP_INSTALLDIR = /sbin +WINDOWS_INSTALLDIR = /sbin +PDO_UNIX_INSTALLDIR = /sbin +LIBS = -lipsec DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) diff --git a/rtsol.tproj/Makefile.dist b/rtsol.tproj/Makefile.dist new file mode 100644 index 0000000..030b906 --- /dev/null +++ b/rtsol.tproj/Makefile.dist @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/5/93 + +PROG= rtsol +MAN8= rtsol.8 +BINOWN= root +BINMODE=4555 + +.include diff --git a/rtsol.tproj/Makefile.postamble b/rtsol.tproj/Makefile.postamble new file mode 100644 index 0000000..fea50f2 --- /dev/null +++ b/rtsol.tproj/Makefile.postamble @@ -0,0 +1,10 @@ +INSTALL_PERMISSIONS = 0555 # If set, 'install' chmod's executable to this +install-daemon: + install -d $(DSTROOT)/usr/sbin + install -c -m 555 "$(DSTROOT)/sbin/rtsol" "$(DSTROOT)/usr/sbin/rtsold" + +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 rtsol.8 "$(DSTROOT)/usr/share/man/man8/rtsol.8" + install -c -m 644 rtsol.8 "$(DSTROOT)/usr/share/man/man8/rtsold.8" + diff --git a/rtsol.tproj/Makefile.preamble b/rtsol.tproj/Makefile.preamble new file mode 100644 index 0000000..9b598d0 --- /dev/null +++ b/rtsol.tproj/Makefile.preamble @@ -0,0 +1,4 @@ +OTHER_GENERATED_OFILES = $(VERS_OFILE) +-include ../Makefile.include +LOCAL_CFLAGS= -DINET6 -DHAVE_GETIFADDRS +AFTER_INSTALL += install-man-page install-daemon diff --git a/rtsol.tproj/PB.project b/rtsol.tproj/PB.project new file mode 100644 index 0000000..313152e --- /dev/null +++ b/rtsol.tproj/PB.project @@ -0,0 +1,31 @@ +{ + APPCLASS = NSApplication; + FILESTABLE = { + FRAMEWORKS = (); + H_FILES = (rtsold.h); + M_FILES = (); + OTHER_LIBS = (); + OTHER_LINKED = (rtosld.c, rtsol.c, if.c, probe.c, dump.c, rtsock.c); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, Makefile.dist, rtsol.8); + SUBPROJECTS = (); + }; + LANGUAGE = English; + LOCALIZABLE_FILES = {}; + NEXTSTEP_BUILDDIR = "/$(USER)/BUILD"; + NEXTSTEP_BUILDTOOL = /bin/gnumake; + NEXTSTEP_INSTALLDIR = /sbin; + NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; + NEXTSTEP_MAINNIB = rtsol; + NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; + PDO_UNIX_INSTALLDIR = /sbin; + PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; + PDO_UNIX_MAINNIB = rtsol; + PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; + PROJECTNAME = rtsol; + PROJECTTYPE = Tool; + PROJECTVERSION = 2.8; + WINDOWS_INSTALLDIR = /sbin; + WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; + WINDOWS_MAINNIB = ping6; + WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; +} diff --git a/rtsol.tproj/dump.c b/rtsol.tproj/dump.c new file mode 100644 index 0000000..7ac8e1f --- /dev/null +++ b/rtsol.tproj/dump.c @@ -0,0 +1,142 @@ +/* $KAME: dump.c,v 1.8 2000/10/05 22:20:39 itojun Exp $ */ + +/* + * Copyright (C) 1999 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. 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. + * + * $FreeBSD: src/usr.sbin/rtsold/dump.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "rtsold.h" + +static FILE *fp; + +extern struct ifinfo *iflist; + +static void dump_interface_status __P((void)); +static char *sec2str __P((time_t)); +char *ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE"}; + +static void +dump_interface_status() +{ + struct ifinfo *ifinfo; + struct timeval now; + + gettimeofday(&now, NULL); + + for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { + fprintf(fp, "Interface %s\n", ifinfo->ifname); + fprintf(fp, " probe interval: "); + if (ifinfo->probeinterval) { + fprintf(fp, "%d\n", ifinfo->probeinterval); + fprintf(fp, " probe timer: %d\n", ifinfo->probetimer); + } + else { + fprintf(fp, "infinity\n"); + fprintf(fp, " no probe timer\n"); + } + fprintf(fp, " interface status: %s\n", + ifinfo->active > 0 ? "active" : "inactive"); + fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]); + fprintf(fp, " carrier detection: %s\n", + ifinfo->mediareqok ? "available" : "unavailable"); + fprintf(fp, " probes: %d, dadcount = %d\n", + ifinfo->probes, ifinfo->dadcount); + if (ifinfo->timer.tv_sec == tm_max.tv_sec && + ifinfo->timer.tv_usec == tm_max.tv_usec) + fprintf(fp, " no timer\n"); + else { + fprintf(fp, " timer: interval=%d:%d, expire=%s\n", + (int)ifinfo->timer.tv_sec, + (int)ifinfo->timer.tv_usec, + (ifinfo->expire.tv_sec < now.tv_sec) ? "expired" + : sec2str(ifinfo->expire.tv_sec - now.tv_sec)); + } + fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt); + } +} + +void +rtsold_dump_file(dumpfile) + char *dumpfile; +{ + if ((fp = fopen(dumpfile, "w")) == NULL) { + warnmsg(LOG_WARNING, __FUNCTION__, "open a dump file(%s): %s", + dumpfile, strerror(errno)); + return; + } + + dump_interface_status(); + + fclose(fp); +} + +static char * +sec2str(total) + time_t total; +{ + static char result[256]; + int days, hours, mins, secs; + int first = 1; + char *p = result; + + days = total / 3600 / 24; + hours = (total / 3600) % 24; + mins = (total / 60) % 60; + secs = total % 60; + + if (days) { + first = 0; + p += sprintf(p, "%dd", days); + } + if (!first || hours) { + first = 0; + p += sprintf(p, "%dh", hours); + } + if (!first || mins) { + first = 0; + p += sprintf(p, "%dm", mins); + } + sprintf(p, "%ds", secs); + + return(result); +} diff --git a/rtsol.tproj/if.c b/rtsol.tproj/if.c new file mode 100644 index 0000000..2413cdb --- /dev/null +++ b/rtsol.tproj/if.c @@ -0,0 +1,468 @@ +/* $KAME: if.c,v 1.15 2001/05/22 06:04:17 jinmei 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. 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. + * + * $FreeBSD: src/usr.sbin/rtsold/if.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__) +#include +#endif /* __FreeBSD__ >= 3 */ +#include +#include +#include +#include +#if defined ( __FreeBSD__) || defined (__APPLE__) +# include +#endif +#ifdef __NetBSD__ +#include +#endif +#if defined(__bsdi__) || defined(__OpenBSD__) +# include +# include +#endif +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_GETIFADDRS +#include +#endif + +#include "rtsold.h" + +extern int rssock; +static int ifsock; + +static int get_llflag __P((const char *name)); +#ifndef HAVE_GETIFADDRS +static unsigned int if_maxindex __P((void)); +#endif +static void get_rtaddrs __P((int addrs, struct sockaddr *sa, + struct sockaddr **rti_info)); + +int +ifinit() +{ + ifsock = rssock; + + return(0); +} + +int +interface_up(char *name) +{ + struct ifreq ifr; + int llflag; + + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + warnmsg(LOG_WARNING, __FUNCTION__, "ioctl(SIOCGIFFLAGS): %s", + strerror(errno)); + return(-1); + } + if (!(ifr.ifr_flags & IFF_UP)) { + ifr.ifr_flags |= IFF_UP; + if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, + "ioctl(SIOCSIFFLAGS): %s", strerror(errno)); + } + return(-1); + } + + warnmsg(LOG_DEBUG, __FUNCTION__, "checking if %s is ready...", name); + + llflag = get_llflag(name); + if (llflag < 0) { + warnmsg(LOG_WARNING, __FUNCTION__, + "get_llflag() failed, anyway I'll try"); + return 0; + } + + if (!(llflag & IN6_IFF_NOTREADY)) { + warnmsg(LOG_DEBUG, __FUNCTION__, + "%s is ready", name); + return(0); + } else { + if (llflag & IN6_IFF_TENTATIVE) { + warnmsg(LOG_DEBUG, __FUNCTION__, "%s is tentative", + name); + return IFS_TENTATIVE; + } + if (llflag & IN6_IFF_DUPLICATED) + warnmsg(LOG_DEBUG, __FUNCTION__, "%s is duplicated", + name); + return -1; + } +} + +int +interface_status(struct ifinfo *ifinfo) +{ + char *ifname = ifinfo->ifname; + struct ifreq ifr; + struct ifmediareq ifmr; + + /* get interface flags */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGIFFLAGS) on %s: %s", + ifname, strerror(errno)); + return(-1); + } + /* + * if one of UP and RUNNING flags is dropped, + * the interface is not active. + */ + if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { + goto inactive; + } + + /* Next, check carrier on the interface, if possible */ + if (!ifinfo->mediareqok) + goto active; + memset(&ifmr, 0, sizeof(ifmr)); + strncpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name)); + + if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { + if (errno != EINVAL) { + warnmsg(LOG_DEBUG, __FUNCTION__, + "ioctl(SIOCGIFMEDIA) on %s: %s", + ifname, strerror(errno)); + return(-1); + } + /* + * EINVAL simply means that the interface does not support + * the SIOCGIFMEDIA ioctl. We regard it alive. + */ + ifinfo->mediareqok = 0; + goto active; + } + + if (ifmr.ifm_status & IFM_AVALID) { + switch(ifmr.ifm_active & IFM_NMASK) { + case IFM_ETHER: + if (ifmr.ifm_status & IFM_ACTIVE) + goto active; + else + goto inactive; + break; + default: + goto inactive; + } + } + + inactive: + return(0); + + active: + return(1); +} + +#define ROUNDUP(a, size) \ + (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) + +#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ + ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\ + sizeof(u_long)) :\ + sizeof(u_long))) +#define ROUNDUP8(a) (1 + (((a) - 1) | 7)) + +int +lladdropt_length(struct sockaddr_dl *sdl) +{ + switch(sdl->sdl_type) { + case IFT_ETHER: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif + return(ROUNDUP8(ETHER_ADDR_LEN + 2)); + default: + return(0); + } +} + +void +lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt) +{ + char *addr; + + ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */ + + switch(sdl->sdl_type) { + case IFT_ETHER: +#ifdef IFT_IEEE80211 + case IFT_IEEE80211: +#endif + ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3; + addr = (char *)(ndopt + 1); + memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN); + break; + default: + warnmsg(LOG_ERR, __FUNCTION__, + "unsupported link type(%d)", sdl->sdl_type); + exit(1); + } + + return; +} + +struct sockaddr_dl * +if_nametosdl(char *name) +{ + int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; + char *buf, *next, *lim; + size_t len; + struct if_msghdr *ifm; + struct sockaddr *sa, *rti_info[RTAX_MAX]; + struct sockaddr_dl *sdl = NULL, *ret_sdl; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return(NULL); + if ((buf = malloc(len)) == NULL) + return(NULL); + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + free(buf); + return(NULL); + } + + lim = buf + len; + for (next = buf; next < lim; next += ifm->ifm_msglen) { + ifm = (struct if_msghdr *)next; + if (ifm->ifm_type == RTM_IFINFO) { + sa = (struct sockaddr *)(ifm + 1); + get_rtaddrs(ifm->ifm_addrs, sa, rti_info); + if ((sa = rti_info[RTAX_IFP]) != NULL) { + if (sa->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)sa; + if (strlen(name) != sdl->sdl_nlen) + continue; /* not same len */ + if (strncmp(&sdl->sdl_data[0], + name, + sdl->sdl_nlen) == 0) { + break; + } + } + } + } + } + if (next == lim) { + /* search failed */ + free(buf); + return(NULL); + } + + if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) + return(NULL); + memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len); + + free(buf); + return(ret_sdl); +} + +int +getinet6sysctl(int code) +{ + int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 }; + int value; + size_t size; + + mib[3] = code; + size = sizeof(value); + if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0) + return -1; + else + return value; +} + +/*------------------------------------------------------------*/ + +/* get ia6_flags for link-local addr on if. returns -1 on error. */ +static int +get_llflag(const char *name) +{ +#ifdef HAVE_GETIFADDRS + struct ifaddrs *ifap, *ifa; + struct in6_ifreq ifr6; + struct sockaddr_in6 *sin6; + int s; + + if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s", + strerror(errno)); + exit(1); + } + if (getifaddrs(&ifap) != 0) { + warnmsg(LOG_ERR, __FUNCTION__, "etifaddrs: %s", + strerror(errno)); + exit(1); + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (strlen(ifa->ifa_name) != strlen(name) + || strncmp(ifa->ifa_name, name, strlen(name)) != 0) + continue; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + continue; + + memset(&ifr6, 0, sizeof(ifr6)); + strcpy(ifr6.ifr_name, name); + memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); + if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, + "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); + exit(1); + } + + freeifaddrs(ifap); + close(s); + return ifr6.ifr_ifru.ifru_flags6; + } + + freeifaddrs(ifap); + close(s); + return -1; +#else + int s; + unsigned int maxif; + struct ifreq *iflist; + struct ifconf ifconf; + struct ifreq *ifr, *ifr_end; + struct sockaddr_in6 *sin6; + struct in6_ifreq ifr6; + + maxif = if_maxindex() + 1; + iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */ + if (iflist == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, "not enough core"); + exit(1); + } + + if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s", + strerror(errno)); + exit(1); + } + memset(&ifconf, 0, sizeof(ifconf)); + ifconf.ifc_req = iflist; + ifconf.ifc_len = maxif * BUFSIZ; /* XXX */ + if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGIFCONF): %s", + strerror(errno)); + exit(1); + } + + /* Look for this interface in the list */ + ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len); + for (ifr = ifconf.ifc_req; + ifr < ifr_end; + ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + + ifr->ifr_addr.sa_len)) { + if (strlen(ifr->ifr_name) != strlen(name) + || strncmp(ifr->ifr_name, name, strlen(name)) != 0) + continue; + if (ifr->ifr_addr.sa_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)&ifr->ifr_addr; + if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + continue; + + memset(&ifr6, 0, sizeof(ifr6)); + strcpy(ifr6.ifr_name, name); + memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len); + if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, + "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno)); + exit(1); + } + + free(iflist); + close(s); + return ifr6.ifr_ifru.ifru_flags6; + } + + free(iflist); + close(s); + return -1; +#endif +} + +#ifndef HAVE_GETIFADDRS +static unsigned int +if_maxindex() +{ + struct if_nameindex *p, *p0; + unsigned int max = 0; + + p0 = if_nameindex(); + for (p = p0; p && p->if_index && p->if_name; p++) { + if (max < p->if_index) + max = p->if_index; + } + if_freenameindex(p0); + return max; +} +#endif + +static void +get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) +{ + int i; + + for (i = 0; i < RTAX_MAX; i++) { + if (addrs & (1 << i)) { + rti_info[i] = sa; + NEXT_SA(sa); + } + else + rti_info[i] = NULL; + } +} diff --git a/rtsol.tproj/probe.c b/rtsol.tproj/probe.c new file mode 100644 index 0000000..61ddb63 --- /dev/null +++ b/rtsol.tproj/probe.c @@ -0,0 +1,191 @@ +/* $KAME: probe.c,v 1.10 2000/08/13 06:14:59 itojun Exp $ */ + +/* + * Copyright (C) 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. 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. + * + * $FreeBSD: src/usr.sbin/rtsold/probe.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#include +#if defined(__FreeBSD__) && __FreeBSD__ >= 3 +#include +#endif /* __FreeBSD__ >= 3 */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "rtsold.h" + +static struct msghdr sndmhdr; +static struct iovec sndiov[2]; +static int probesock; +static void sendprobe __P((struct in6_addr *addr, int ifindex)); + + +int +probe_init() +{ + int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + static u_char *sndcmsgbuf = NULL; + + if (sndcmsgbuf == NULL && + (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, "malloc failed"); + return(-1); + } + + if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); + return(-1); + } + + /* make the socket send-only */ + if (shutdown(probesock, 0)) { + warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno)); + return(-1); + } + + /* initialize msghdr for sending packets */ + sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); + sndmhdr.msg_iov = sndiov; + sndmhdr.msg_iovlen = 1; + sndmhdr.msg_control = (caddr_t)sndcmsgbuf; + sndmhdr.msg_controllen = scmsglen; + + return(0); +} + +/* + * Probe if each router in the default router list is still alive. + */ +void +defrouter_probe(int ifindex) +{ + struct in6_drlist dr; + int s, i; + u_char ntopbuf[INET6_ADDRSTRLEN]; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); + return; + } + bzero(&dr, sizeof(dr)); + strcpy(dr.ifname, "lo0"); /* dummy interface */ + if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s", + strerror(errno)); + goto closeandend; + } + + for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) { + if (ifindex && dr.defrouter[i].if_index == ifindex) { + /* sanity check */ + if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) { + warnmsg(LOG_ERR, __FUNCTION__, + "default router list contains a " + "non-linklocal address(%s)", + inet_ntop(AF_INET6, + &dr.defrouter[i].rtaddr, + ntopbuf, INET6_ADDRSTRLEN)); + continue; /* ignore the address */ + } + sendprobe(&dr.defrouter[i].rtaddr, + dr.defrouter[i].if_index); + } + } + + closeandend: + close(s); + return; +} + +static void +sendprobe(struct in6_addr *addr, int ifindex) +{ + struct sockaddr_in6 sa6_probe; + struct in6_pktinfo *pi; + struct cmsghdr *cm; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];; + + bzero(&sa6_probe, sizeof(sa6_probe)); + sa6_probe.sin6_family = AF_INET6; + sa6_probe.sin6_len = sizeof(sa6_probe); + sa6_probe.sin6_addr = *addr; + + sndmhdr.msg_name = (caddr_t)&sa6_probe; + sndmhdr.msg_iov[0].iov_base = NULL; + sndmhdr.msg_iov[0].iov_len = 0; + + cm = CMSG_FIRSTHDR(&sndmhdr); + /* specify the outgoing interface */ + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pi = (struct in6_pktinfo *)CMSG_DATA(cm); + memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ + pi->ipi6_ifindex = ifindex; + + /* specify the hop limit of the packet for safety */ + { + int hoplimit = 1; + + cm = CMSG_NXTHDR(&sndmhdr, cm); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_HOPLIMIT; + cm->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); + } + + warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s", + inet_ntop(AF_INET6, addr, ntopbuf, INET6_ADDRSTRLEN), + if_indextoname(ifindex, ifnamebuf)); + + if (sendmsg(probesock, &sndmhdr, 0)) + warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s", + if_indextoname(ifindex, ifnamebuf), strerror(errno)); + + return; +} diff --git a/rtsol.tproj/rtsock.c b/rtsol.tproj/rtsock.c new file mode 100644 index 0000000..15348c4 --- /dev/null +++ b/rtsol.tproj/rtsock.c @@ -0,0 +1,179 @@ +/* $KAME: rtsock.c,v 1.3 2000/10/10 08:46:45 itojun Exp $ */ +/* $FreeBSD: src/usr.sbin/rtsold/rtsock.c,v 1.1.2.1 2001/07/03 11:02:16 ume Exp $ */ + +/* + * Copyright (C) 2000 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. 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtsold.h" + +#define ROUNDUP(a, size) \ + (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) + +#define NEXT_SA(ap) (ap) = (struct sockaddr *) \ + ((caddr_t)(ap) + \ + ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) \ + : sizeof(u_long))) + +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ +static int rtsock_input_ifannounce __P((int, struct rt_msghdr *, char *)); +#endif + +static struct { + u_char type; + size_t minlen; + int (*func) __P((int, struct rt_msghdr *, char *)); +} rtsock_dispatch[] = { +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ + { RTM_IFANNOUNCE, sizeof(struct if_announcemsghdr), + rtsock_input_ifannounce }, +#endif + { 0, NULL }, +}; + +int +rtsock_open() +{ + + return socket(PF_ROUTE, SOCK_RAW, 0); +} + +int +rtsock_input(s) + int s; +{ + ssize_t n; + char msg[2048]; + char *lim, *next; + struct rt_msghdr *rtm; + int idx; + size_t len; + int ret = 0; + const size_t lenlim = + offsetof(struct rt_msghdr, rtm_msglen) + sizeof(rtm->rtm_msglen); + + n = read(s, msg, sizeof(msg)); + + lim = msg + n; + for (next = msg; next < lim; next += len) { + rtm = (struct rt_msghdr *)next; + if (lim - next < lenlim) + break; + len = rtm->rtm_msglen; + if (len < lenlim) + break; + + if (dflag > 1) { + warnmsg(LOG_INFO, __FUNCTION__, + "rtmsg type %d, len=%lu", rtm->rtm_type, + (u_long)len); + } + + for (idx = 0; rtsock_dispatch[idx].func; idx++) { + if (rtm->rtm_type != rtsock_dispatch[idx].type) + continue; + if (rtm->rtm_msglen < rtsock_dispatch[idx].minlen) { + warnmsg(LOG_INFO, __FUNCTION__, + "rtmsg type %d too short!", rtm->rtm_type); + continue; + } + + ret = (*rtsock_dispatch[idx].func)(s, rtm, lim); + break; + } + } + + return ret; +} + +#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/ +static int +rtsock_input_ifannounce(s, rtm, lim) + int s; + struct rt_msghdr *rtm; + char *lim; +{ + struct if_announcemsghdr *ifan; + struct ifinfo *ifinfo; + + ifan = (struct if_announcemsghdr *)rtm; + if ((char *)(ifan + 1) > lim) + return -1; + + switch (ifan->ifan_what) { + case IFAN_ARRIVAL: + /* + * XXX for NetBSD 1.5, interface index will monotonically be + * increased as new pcmcia card gets inserted. + * we may be able to do a name-based interface match, + * and call ifreconfig() to enable the interface again. + */ + warnmsg(LOG_INFO, __FUNCTION__, + "interface %s inserted", ifan->ifan_name); + break; + case IFAN_DEPARTURE: + warnmsg(LOG_WARNING, __FUNCTION__, + "interface %s removed", ifan->ifan_name); + ifinfo = find_ifinfo(ifan->ifan_index); + if (ifinfo) { + if (dflag > 1) { + warnmsg(LOG_INFO, __FUNCTION__, + "bring interface %s to DOWN state", + ifan->ifan_name); + } + ifinfo->state = IFS_DOWN; + } + break; + } + + return 0; +} +#endif diff --git a/rtsol.tproj/rtsol.8 b/rtsol.tproj/rtsol.8 new file mode 100644 index 0000000..30c3768 --- /dev/null +++ b/rtsol.tproj/rtsol.8 @@ -0,0 +1,224 @@ +.\" $KAME: rtsold.8,v 1.16 2000/10/15 13:19:05 itojun 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. 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. +.\" +.\" $FreeBSD: src/usr.sbin/rtsold/rtsold.8,v 1.1.2.5 2001/08/16 15:56:30 ru Exp $ +.\" +.Dd May 17, 1998 +.Dt RTSOLD 8 +.Os +.\" +.Sh NAME +.Nm rtsold +.Nd router solicitation daemon +.\" +.Sh SYNOPSIS +.Nm +.Op Fl dDfm1 +.Ar interface ... +.Nm +.Op Fl dDfm1 +.Fl a +.Nm rtsol +.Op Fl dD +.Ar interface ... +.Nm rtsol +.Op Fl dD +.Fl a +.\" +.Sh DESCRIPTION +.Nm +is the daemon program to send ICMPv6 Router Solicitation messages +on the specified interfaces. +If a node (re)attaches to a link, +.Nm +sends some Router Solicitations on the link destined to the link-local scope +all-routers multicast address to discover new routers +and to get non link-local addresses. +.Pp +.Nm +should be used on IPv6 hosts +(non-router nodes) +only. +.Pp +If you invoke the program as +.Nm rtsol , +it will transmit probes from the specified +.Ar interface , +without becoming a daemon. +In other words, +.Nm rtsol +behaves as +.Do +.Nm +.Fl f1 +.Ar interfaces +.Dc . +.Pp +Specifically, +.Nm +sends at most 3 Router Solicitations on an interface +after one of the following events: +.Pp +.Bl -bullet -compact +.It +Just after invocation of +.Nm +daemon. +.It +The interface is up after a temporary interface failure. +.Nm +detects such failures by periodically probing to see if the status +of the interface is active or not. +Note that some network cards and drivers do not allow the extraction +of link state. +In such cases, +.Nm +cannot detect the change of the interface status. +.It +Every 60 seconds if the +.Fl m +option is specified and the +.Nm +daemon cannot get the interface status. +This feature does not conform to the IPv6 neighbor discovery +specification, but is provided for mobile stations. +The default interval for router advertisements, which is on the order of 10 +minutes, is slightly long for mobile stations. +This feature is provided +for such stations so that they can find new routers as soon as possible +when they attach to another link. +.El +.Lp +Once +.Nm +has sent a Router Solicitation, and has received a valid Router Advertisement, +it refrains from sending additional solicitations on that interface, until +the next time one of the above events occurs. +.Lp +When sending a Router Solicitation on an interface, +.Nm +includes a Source Link-layer address option if the interface +has a link-layer address. +.Pp +Upon receipt of signal +.Dv SIGUSR1 , +.Nm +will dump the current internal state into +.Pa /var/run/rtsold.dump . +.\" +.Sh OPTIONS +.Bl -tag -width indent +.It Fl a +Autoprobe outgoing interface. +.Nm +will try to find a non-loopback, non-point-to-point, IPv6-capable interface. +If +.Nm +finds multiple interfaces, +.Nm +will exit with error. +.\" +.It Fl d +Enable debugging. +.It Fl D +Enable more debugging including the printing of internal timer information. +.It Fl f +.Fl f +prevents +.Nm +from becoming a daemon (foreground mode). +Warning messages are generated to standard error +instead of +.Xr syslog 3 . +.It Fl m +Enable mobility support. +If this option is specified, +.Nm +sends probing packets to default routers that have advertised Router +Advertisements +when the node (re)attaches to an interface. +Moreover, if the option is specified, +.Nm +periodically sends Router Solicitation on an interface that does not support +.Dv SIOCGIFMEDIA +ioctl. +.It Fl 1 +Perform only one probe. +Transmit Router Solicitation packets until at least one valid Router +Advertisement packet has arrived on each +.Ar interface , +then exit. +.El +.Sh DIAGNOSTICS +.Ex -std +.\" +.Sh FILES +.Bl -tag -width /var/run/rtsold.dump -compact +.It Pa /var/run/rtsold.pid +the pid of the currently running +.Nm . +.It Pa /var/run/rtsold.dump +dumps internal state on. +.El +.\" +.Sh SEE ALSO +.Xr rtadvd 8 , +.Xr sysctl 8 +.\" +.Sh HISTORY +The +.Nm +command is based on the +.Nm rtsol +command, which first appeared in WIDE/KAME IPv6 protocol stack kit. +.Nm rtsol +is now integrated into +.Xr rtsold 8 . +.\" +.Sh BUGS +In some operating systems, when a PCMCIA network card is removed +and reinserted, the corresponding interface index is changed. +However, +.Nm +assumes such changes will not occur, and always uses the index that +it got at invocation. As a result, +.Nm +may not work if you reinsert a network card. +In such a case, +.Nm +should be killed and restarted. +.Pp +The IPv6 autoconfiguration specification assumes a single-interface host. +You may see kernel error messages if you try to autoconfigure a host with +multiple interfaces. +Also, it seems contradictory for +.Nm +to accept multiple +.Ar interface +arguments. diff --git a/rtsol.tproj/rtsol.c b/rtsol.tproj/rtsol.c new file mode 100644 index 0000000..753eed7 --- /dev/null +++ b/rtsol.tproj/rtsol.c @@ -0,0 +1,343 @@ +/* $KAME: rtsol.c,v 1.11 2000/08/13 06:14:59 itojun 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. 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. + * + * $FreeBSD: src/usr.sbin/rtsold/rtsol.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtsold.h" + +#define ALLROUTER "ff02::2" + +static struct msghdr rcvmhdr; +static struct msghdr sndmhdr; +static struct iovec rcviov[2]; +static struct iovec sndiov[2]; +static struct sockaddr_in6 from; + +int rssock; + +static struct sockaddr_in6 sin6_allrouters = {sizeof(sin6_allrouters), AF_INET6}; + +int +sockopen() +{ + int on; + struct icmp6_filter filt; + static u_char answer[1500]; + int rcvcmsglen, sndcmsglen; + static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL; + + sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "malloc for receive msghdr failed"); + return(-1); + } + if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "malloc for send msghdr failed"); + return(-1); + } + memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6)); + if (inet_pton(AF_INET6, ALLROUTER, + &sin6_allrouters.sin6_addr.s6_addr) != 1) { + warnmsg(LOG_ERR, __FUNCTION__, "inet_pton failed for %s", + ALLROUTER); + return(-1); + } + + if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno)); + return(-1); + } + + /* specify to tell receiving interface */ + on = 1; +#ifdef IPV6_RECVPKTINFO + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVPKTINFO: %s", + strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_PKTINFO: %s", + strerror(errno)); + exit(1); + } +#endif + + on = 1; + /* specify to tell value of hoplimit field of received IP6 hdr */ +#ifdef IPV6_RECVHOPLIMIT + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVHOPLIMIT: %s", + strerror(errno)); + exit(1); + } +#else /* old adv. API */ + if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, + sizeof(on)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "IPV6_HOPLIMIT: %s", + strerror(errno)); + exit(1); + } +#endif + + /* specfiy to accept only router advertisements on the socket */ + ICMP6_FILTER_SETBLOCKALL(&filt); + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); + if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + sizeof(filt)) == -1) { + warnmsg(LOG_ERR, __FUNCTION__, "setsockopt(ICMP6_FILTER): %s", + strerror(errno)); + return(-1); + } + + /* initialize msghdr for receiving packets */ + rcviov[0].iov_base = (caddr_t)answer; + rcviov[0].iov_len = sizeof(answer); + rcvmhdr.msg_name = (caddr_t)&from; + rcvmhdr.msg_namelen = sizeof(from); + rcvmhdr.msg_iov = rcviov; + rcvmhdr.msg_iovlen = 1; + rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; + rcvmhdr.msg_controllen = rcvcmsglen; + + /* initialize msghdr for sending packets */ + sndmhdr.msg_namelen = sizeof(struct sockaddr_in6); + sndmhdr.msg_iov = sndiov; + sndmhdr.msg_iovlen = 1; + sndmhdr.msg_control = (caddr_t)sndcmsgbuf; + sndmhdr.msg_controllen = sndcmsglen; + + return(rssock); +} + +void +sendpacket(struct ifinfo *ifinfo) +{ + int i; + struct cmsghdr *cm; + struct in6_pktinfo *pi; + + sndmhdr.msg_name = (caddr_t)&sin6_allrouters; + sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data; + sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen; + + cm = CMSG_FIRSTHDR(&sndmhdr); + /* specify the outgoing interface */ + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_PKTINFO; + cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pi = (struct in6_pktinfo *)CMSG_DATA(cm); + memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/ + pi->ipi6_ifindex = ifinfo->sdl->sdl_index; + + /* specify the hop limit of the packet */ + { + int hoplimit = 255; + + cm = CMSG_NXTHDR(&sndmhdr, cm); + cm->cmsg_level = IPPROTO_IPV6; + cm->cmsg_type = IPV6_HOPLIMIT; + cm->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int)); + } + + warnmsg(LOG_DEBUG, + __FUNCTION__, "send RS on %s, whose state is %d", + ifinfo->ifname, ifinfo->state); + + i = sendmsg(rssock, &sndmhdr, 0); + + if (i < 0 || i != ifinfo->rs_datalen) { + /* + * ENETDOWN is not so serious, especially when using several + * network cards on a mobile node. We ignore it. + */ + if (errno != ENETDOWN || dflag > 0) + warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s", + ifinfo->ifname, strerror(errno)); + } + + /* update counter */ + ifinfo->probes++; +} + +void +rtsol_input(int s) +{ + int i; + int *hlimp = NULL; + struct icmp6_hdr *icp; + int ifindex = 0; + struct cmsghdr *cm; + struct in6_pktinfo *pi = NULL; + struct ifinfo *ifi = NULL; + u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ]; + + /* get message */ + if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) { + warnmsg(LOG_ERR, __FUNCTION__, "recvmsg: %s", strerror(errno)); + return; + } + + /* extract optional information via Advanced API */ + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr); + cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO && + cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { + pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); + ifindex = pi->ipi6_ifindex; + } + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_HOPLIMIT && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + hlimp = (int *)CMSG_DATA(cm); + } + + if (ifindex == 0) { + warnmsg(LOG_ERR, + __FUNCTION__, "failed to get receiving interface"); + return; + } + if (hlimp == NULL) { + warnmsg(LOG_ERR, + __FUNCTION__, "failed to get receiving hop limit"); + return; + } + + if (i < sizeof(struct nd_router_advert)) { + warnmsg(LOG_ERR, + __FUNCTION__, "packet size(%d) is too short", i); + return; + } + + icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base; + + if (icp->icmp6_type != ND_ROUTER_ADVERT) { + warnmsg(LOG_ERR, __FUNCTION__, + "invalid icmp type(%d) from %s on %s", icp->icmp6_type, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + if (icp->icmp6_code != 0) { + warnmsg(LOG_ERR, __FUNCTION__, + "invalid icmp code(%d) from %s on %s", icp->icmp6_code, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + if (*hlimp != 255) { + warnmsg(LOG_NOTICE, __FUNCTION__, + "invalid RA with hop limit(%d) from %s on %s", + *hlimp, + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) { + warnmsg(LOG_NOTICE, __FUNCTION__, + "invalid RA with non link-local source from %s on %s", + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + /* xxx: more validation? */ + + if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) { + warnmsg(LOG_NOTICE, __FUNCTION__, + "received RA from %s on an unexpeced IF(%s)", + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + if_indextoname(pi->ipi6_ifindex, ifnamebuf)); + return; + } + + warnmsg(LOG_DEBUG, __FUNCTION__, + "received RA from %s on %s, state is %d", + inet_ntop(AF_INET6, &from.sin6_addr, ntopbuf, + INET6_ADDRSTRLEN), + ifi->ifname, ifi->state); + + ifi->racnt++; + + switch(ifi->state) { + case IFS_IDLE: /* should be ignored */ + case IFS_DELAY: /* right? */ + break; + case IFS_PROBE: + ifi->state = IFS_IDLE; + ifi->probes = 0; + rtsol_timer_update(ifi); + break; + } +} diff --git a/rtsol.tproj/rtsold.c b/rtsol.tproj/rtsold.c new file mode 100644 index 0000000..37f0f8b --- /dev/null +++ b/rtsol.tproj/rtsold.c @@ -0,0 +1,792 @@ +/* $KAME: rtsold.c,v 1.31 2001/05/22 06:03:06 jinmei 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. 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. + * + * $FreeBSD: src/usr.sbin/rtsold/rtsold.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rtsold.h" + +struct ifinfo *iflist; +struct timeval tm_max = {0x7fffffff, 0x7fffffff}; +int aflag = 0; +int dflag = 0; +static int log_upto = 999; +static int fflag = 0; + +/* protocol constatns */ +#define MAX_RTR_SOLICITATION_DELAY 1 /* second */ +#define RTR_SOLICITATION_INTERVAL 4 /* seconds */ +#define MAX_RTR_SOLICITATIONS 3 /* times */ + +/* implementation dependent constants */ +#define PROBE_INTERVAL 60 /* secondes XXX: should be configurable */ + +/* utility macros */ +/* a < b */ +#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) && \ + ((a).tv_usec < (b).tv_usec))) + +/* a <= b */ +#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\ + (((a).tv_sec == (b).tv_sec) &&\ + ((a).tv_usec <= (b).tv_usec))) + +/* a == b */ +#define TIMEVAL_EQ(a, b) (((a).tv_sec==(b).tv_sec) && ((a).tv_usec==(b).tv_usec)) + +int main __P((int argc, char *argv[])); + +/* static variables and functions */ +static int mobile_node = 0; +static int do_dump; +static char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */ +static char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */ + +static int ifconfig __P((char *ifname)); +#if 0 +static int ifreconfig __P((char *ifname)); +#endif +static int make_packet __P((struct ifinfo *ifinfo)); +static struct timeval *rtsol_check_timer __P((void)); +static void TIMEVAL_ADD __P((struct timeval *a, struct timeval *b, + struct timeval *result)); +static void TIMEVAL_SUB __P((struct timeval *a, struct timeval *b, + struct timeval *result)); + +static void rtsold_set_dump_file __P((void)); +static void usage __P((char *progname)); +static char **autoifprobe __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int s, rtsock, maxfd, ch; + int once = 0; + struct timeval *timeout; + struct fd_set fdset; + char *argv0; + char *opts; + + /* + * Initialization + */ + argv0 = argv[0]; + + /* get option */ + if (argv0 && argv0[strlen(argv0) - 1] != 'd') { + fflag = 1; + once = 1; + opts = "adD"; + } else + opts = "adDfm1"; + + while ((ch = getopt(argc, argv, opts)) != -1) { + switch (ch) { + case 'a': + aflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'D': + dflag = 2; + break; + case 'f': + fflag = 1; + break; + case 'm': + mobile_node = 1; + break; + case '1': + once = 1; + break; + default: + usage(argv0); + /*NOTREACHED*/ + } + } + argc -= optind; + argv += optind; + + if (aflag) { + int i; + + if (argc != 0) { + usage(argv0); + /*NOTREACHED*/ + } + + argv = autoifprobe(); + if (!argv) { + errx(1, "could not autoprobe interface"); + /*NOTREACHED*/ + } + + for (i = 0; argv[i]; i++) + ; + argc = i; + } + if (argc == 0) { + usage(argv0); + /*NOTREACHED*/ + } + + /* set log level */ + if (dflag == 0) + log_upto = LOG_NOTICE; + if (!fflag) { + char *ident; + ident = strrchr(argv0, '/'); + if (!ident) + ident = argv0; + else + ident++; + openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON); + if (log_upto >= 0) + setlogmask(LOG_UPTO(log_upto)); + } + +#ifndef HAVE_ARC4RANDOM + /* random value initilization */ + srandom((u_long)time(NULL)); +#endif + + /* warn if accept_rtadv is down */ + if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) + warnx("kernel is configured not to accept RAs"); + /* warn if forwarding is up */ + if (getinet6sysctl(IPV6CTL_FORWARDING)) + warnx("kernel is configured as a router, not a host"); + + /* initialization to dump internal status to a file */ + if (signal(SIGUSR1, (void *)rtsold_set_dump_file) < 0) { + errx(1, "failed to set signal for dump status"); + /*NOTREACHED*/ + } + + /* + * Open a socket for sending RS and receiving RA. + * This should be done before calling ifinit(), since the function + * uses the socket. + */ + if ((s = sockopen()) < 0) { + errx(1, "failed to open a socket"); + /*NOTREACHED*/ + } + maxfd = s; + if ((rtsock = rtsock_open()) < 0) { + errx(1, "failed to open a socket"); + /*NOTREACHED*/ + } + if (rtsock > maxfd) + maxfd = rtsock; + + /* configuration per interface */ + if (ifinit()) { + errx(1, "failed to initilizatoin interfaces"); + /*NOTREACHED*/ + } + while (argc--) { + if (ifconfig(*argv)) { + errx(1, "failed to initialize %s", *argv); + /*NOTREACHED*/ + } + argv++; + } + + /* setup for probing default routers */ + if (probe_init()) { + errx(1, "failed to setup for probing routers"); + /*NOTREACHED*/ + } + + if (!fflag) + daemon(0, 0); /* act as a daemon */ + + /* dump the current pid */ + if (!once) { + pid_t pid = getpid(); + FILE *fp; + + if ((fp = fopen(pidfilename, "w")) == NULL) + warnmsg(LOG_ERR, __FUNCTION__, + "failed to open a log file(%s): %s", + pidfilename, strerror(errno)); + else { + fprintf(fp, "%d\n", pid); + fclose(fp); + } + } + + FD_ZERO(&fdset); + FD_SET(s, &fdset); + FD_SET(rtsock, &fdset); + while (1) { /* main loop */ + int e; + struct fd_set select_fd = fdset; + + if (do_dump) { /* SIGUSR1 */ + do_dump = 0; + rtsold_dump_file(dumpfilename); + } + + timeout = rtsol_check_timer(); + + if (once) { + struct ifinfo *ifi; + + /* if we have no timeout, we are done (or failed) */ + if (timeout == NULL) + break; + + /* if all interfaces have got RA packet, we are done */ + for (ifi = iflist; ifi; ifi = ifi->next) { + if (ifi->state != IFS_DOWN && ifi->racnt == 0) + break; + } + if (ifi == NULL) + break; + } + e = select(maxfd + 1, &select_fd, NULL, NULL, timeout); + if (e < 1) { + if (e < 0 && errno != EINTR) { + warnmsg(LOG_ERR, __FUNCTION__, "select: %s", + strerror(errno)); + } + continue; + } + + /* packet reception */ + if (FD_ISSET(rtsock, &select_fd)) + rtsock_input(rtsock); + if (FD_ISSET(s, &select_fd)) + rtsol_input(s); + } + /* NOTREACHED */ + + return 0; +} + +static int +ifconfig(char *ifname) +{ + struct ifinfo *ifinfo; + struct sockaddr_dl *sdl; + int flags; + + if ((sdl = if_nametosdl(ifname)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "failed to get link layer information for %s", ifname); + return(-1); + } + if (find_ifinfo(sdl->sdl_index)) { + warnmsg(LOG_ERR, __FUNCTION__, + "interface %s was already cofigured", ifname); + free(sdl); + return(-1); + } + + if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, "memory allocation failed"); + free(sdl); + return(-1); + } + memset(ifinfo, 0, sizeof(*ifinfo)); + ifinfo->sdl = sdl; + + strncpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname)); + + /* construct a router solicitation message */ + if (make_packet(ifinfo)) + goto bad; + + /* + * check if the interface is available. + * also check if SIOCGIFMEDIA ioctl is OK on the interface. + */ + ifinfo->mediareqok = 1; + ifinfo->active = interface_status(ifinfo); + if (!ifinfo->mediareqok) { + /* + * probe routers periodically even if the link status + * does not change. + */ + ifinfo->probeinterval = PROBE_INTERVAL; + } + + /* activate interface: interface_up returns 0 on success */ + flags = interface_up(ifinfo->ifname); + if (flags == 0) + ifinfo->state = IFS_DELAY; + else if (flags == IFS_TENTATIVE) + ifinfo->state = IFS_TENTATIVE; + else + ifinfo->state = IFS_DOWN; + + rtsol_timer_update(ifinfo); + + /* link into chain */ + if (iflist) + ifinfo->next = iflist; + iflist = ifinfo; + + return(0); + + bad: + free(ifinfo->sdl); + free(ifinfo); + return(-1); +} + +#if 0 +static int +ifreconfig(char *ifname) +{ + struct ifinfo *ifi, *prev; + int rv; + + prev = NULL; + for (ifi = iflist; ifi; ifi = ifi->next) { + if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0) + break; + prev = ifi; + } + prev->next = ifi->next; + + rv = ifconfig(ifname); + + /* reclaim it after ifconfig() in case ifname is pointer inside ifi */ + if (ifi->rs_data) + free(ifi->rs_data); + free(ifi->sdl); + free(ifi); + + return rv; +} +#endif + +struct ifinfo * +find_ifinfo(int ifindex) +{ + struct ifinfo *ifi; + + for (ifi = iflist; ifi; ifi = ifi->next) + if (ifi->sdl->sdl_index == ifindex) + return(ifi); + + return(NULL); +} + +static int +make_packet(struct ifinfo *ifinfo) +{ + char *buf; + struct nd_router_solicit *rs; + size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0; + + if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) { + warnmsg(LOG_INFO, __FUNCTION__, + "link-layer address option has null length" + " on %s. Treat as not included.", ifinfo->ifname); + } + packlen += lladdroptlen; + ifinfo->rs_datalen = packlen; + + /* allocate buffer */ + if ((buf = malloc(packlen)) == NULL) { + warnmsg(LOG_ERR, __FUNCTION__, + "memory allocation failed for %s", ifinfo->ifname); + return(-1); + } + ifinfo->rs_data = buf; + + /* fill in the message */ + rs = (struct nd_router_solicit *)buf; + rs->nd_rs_type = ND_ROUTER_SOLICIT; + rs->nd_rs_code = 0; + rs->nd_rs_cksum = 0; + rs->nd_rs_reserved = 0; + buf += sizeof(*rs); + + /* fill in source link-layer address option */ + if (lladdroptlen) + lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf); + + return(0); +} + +static struct timeval * +rtsol_check_timer() +{ + static struct timeval returnval; + struct timeval now, rtsol_timer; + struct ifinfo *ifinfo; + int flags; + + gettimeofday(&now, NULL); + + rtsol_timer = tm_max; + + for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) { + if (TIMEVAL_LEQ(ifinfo->expire, now)) { + if (dflag > 1) + warnmsg(LOG_DEBUG, __FUNCTION__, + "timer expiration on %s, " + "state = %d", ifinfo->ifname, + ifinfo->state); + + switch (ifinfo->state) { + case IFS_DOWN: + case IFS_TENTATIVE: + /* interface_up returns 0 on success */ + flags = interface_up(ifinfo->ifname); + if (flags == 0) + ifinfo->state = IFS_DELAY; + else if (flags == IFS_TENTATIVE) + ifinfo->state = IFS_TENTATIVE; + else + ifinfo->state = IFS_DOWN; + break; + case IFS_IDLE: + { + int oldstatus = ifinfo->active; + int probe = 0; + + ifinfo->active = + interface_status(ifinfo); + + if (oldstatus != ifinfo->active) { + warnmsg(LOG_DEBUG, __FUNCTION__, + "%s status is changed" + " from %d to %d", + ifinfo->ifname, + oldstatus, ifinfo->active); + probe = 1; + ifinfo->state = IFS_DELAY; + } + else if (ifinfo->probeinterval && + (ifinfo->probetimer -= + ifinfo->timer.tv_sec) <= 0) { + /* probe timer expired */ + ifinfo->probetimer = + ifinfo->probeinterval; + probe = 1; + ifinfo->state = IFS_PROBE; + } + + if (probe && mobile_node) + defrouter_probe(ifinfo->sdl->sdl_index); + break; + } + case IFS_DELAY: + ifinfo->state = IFS_PROBE; + sendpacket(ifinfo); + break; + case IFS_PROBE: + if (ifinfo->probes < MAX_RTR_SOLICITATIONS) + sendpacket(ifinfo); + else { + warnmsg(LOG_INFO, __FUNCTION__, + "No answer " + "after sending %d RSs", + ifinfo->probes); + ifinfo->probes = 0; + ifinfo->state = IFS_IDLE; + } + break; + } + rtsol_timer_update(ifinfo); + } + + if (TIMEVAL_LT(ifinfo->expire, rtsol_timer)) + rtsol_timer = ifinfo->expire; + } + + if (TIMEVAL_EQ(rtsol_timer, tm_max)) { + warnmsg(LOG_DEBUG, __FUNCTION__, "there is no timer"); + return(NULL); + } + else if (TIMEVAL_LT(rtsol_timer, now)) + /* this may occur when the interval is too small */ + returnval.tv_sec = returnval.tv_usec = 0; + else + TIMEVAL_SUB(&rtsol_timer, &now, &returnval); + + if (dflag > 1) + warnmsg(LOG_DEBUG, __FUNCTION__, "New timer is %ld:%08ld", + (long)returnval.tv_sec, (long)returnval.tv_usec); + + return(&returnval); +} + +void +rtsol_timer_update(struct ifinfo *ifinfo) +{ +#define MILLION 1000000 +#define DADRETRY 10 /* XXX: adhoc */ + long interval; + struct timeval now; + + bzero(&ifinfo->timer, sizeof(ifinfo->timer)); + + switch (ifinfo->state) { + case IFS_DOWN: + case IFS_TENTATIVE: + if (++ifinfo->dadcount > DADRETRY) { + ifinfo->dadcount = 0; + ifinfo->timer.tv_sec = PROBE_INTERVAL; + } + else + ifinfo->timer.tv_sec = 1; + break; + case IFS_IDLE: + if (mobile_node) { + /* XXX should be configurable */ + ifinfo->timer.tv_sec = 3; + } + else + ifinfo->timer = tm_max; /* stop timer(valid?) */ + break; + case IFS_DELAY: +#ifndef HAVE_ARC4RANDOM + interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); +#else + interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION); +#endif + ifinfo->timer.tv_sec = interval / MILLION; + ifinfo->timer.tv_usec = interval % MILLION; + break; + case IFS_PROBE: + if (ifinfo->probes < MAX_RTR_SOLICITATIONS) + ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL; + else { + /* + * After sending MAX_RTR_SOLICITATIONS solicitations, + * we're just waiting for possible replies; there + * will be no more solicatation. Thus, we change + * the timer value to MAX_RTR_SOLICITATION_DELAY based + * on RFC 2461, Section 6.3.7. + */ + ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY; + } + break; + default: + warnmsg(LOG_ERR, __FUNCTION__, + "illegal interface state(%d) on %s", + ifinfo->state, ifinfo->ifname); + return; + } + + /* reset the timer */ + if (TIMEVAL_EQ(ifinfo->timer, tm_max)) { + ifinfo->expire = tm_max; + warnmsg(LOG_DEBUG, __FUNCTION__, + "stop timer for %s", ifinfo->ifname); + } + else { + gettimeofday(&now, NULL); + TIMEVAL_ADD(&now, &ifinfo->timer, &ifinfo->expire); + + if (dflag > 1) + warnmsg(LOG_DEBUG, __FUNCTION__, + "set timer for %s to %d:%d", ifinfo->ifname, + (int)ifinfo->timer.tv_sec, + (int)ifinfo->timer.tv_usec); + } + +#undef MILLION +} + +/* timer related utility functions */ +#define MILLION 1000000 + +/* result = a + b */ +static void +TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec + b->tv_usec) < MILLION) { + result->tv_usec = l; + result->tv_sec = a->tv_sec + b->tv_sec; + } + else { + result->tv_usec = l - MILLION; + result->tv_sec = a->tv_sec + b->tv_sec + 1; + } +} + +/* + * result = a - b + * XXX: this function assumes that a >= b. + */ +void +TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result) +{ + long l; + + if ((l = a->tv_usec - b->tv_usec) >= 0) { + result->tv_usec = l; + result->tv_sec = a->tv_sec - b->tv_sec; + } + else { + result->tv_usec = MILLION + l; + result->tv_sec = a->tv_sec - b->tv_sec - 1; + } +} + +static void +rtsold_set_dump_file() +{ + do_dump = 1; +} + +static void +usage(char *progname) +{ + if (progname && progname[strlen(progname) - 1] != 'd') { + fprintf(stderr, "usage: rtsol [-dD] interfaces...\n"); + fprintf(stderr, "usage: rtsol [-dD] -a\n"); + } else { + fprintf(stderr, "usage: rtsold [-adDfm1] interfaces...\n"); + fprintf(stderr, "usage: rtsold [-dDfm1] -a\n"); + } + exit(1); +} + +void +#if __STDC__ +warnmsg(int priority, const char *func, const char *msg, ...) +#else +warnmsg(priority, func, msg, va_alist) + int priority; + const char *func; + const char *msg; + va_dcl +#endif +{ + va_list ap; + char buf[BUFSIZ]; + + va_start(ap, msg); + if (fflag) { + if (priority <= log_upto) { + (void)vfprintf(stderr, msg, ap); + (void)fprintf(stderr, "\n"); + } + } else { + snprintf(buf, sizeof(buf), "<%s> %s", func, msg); + msg = buf; + vsyslog(priority, msg, ap); + } + va_end(ap); +} + +static char ** +autoifprobe() +{ +#ifndef HAVE_GETIFADDRS + errx(1, "-a is not available with the configuration"); +#else + static char ifname[IFNAMSIZ + 1]; + static char *argv[2]; + struct ifaddrs *ifap, *ifa, *target; + + if (getifaddrs(&ifap) != 0) + return NULL; + + target = NULL; + /* find an ethernet */ + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if ((ifa->ifa_flags & IFF_UP) == 0) + continue; + if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0) + continue; + if ((ifa->ifa_flags & IFF_LOOPBACK) != 0) + continue; + if ((ifa->ifa_flags & IFF_MULTICAST) == 0) + continue; + + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + if (target && strcmp(target->ifa_name, ifa->ifa_name) == 0) + continue; + + if (!target) + target = ifa; + else { + /* if we find multiple candidates, failure. */ + if (dflag > 1) + warnx("multiple interfaces found"); + target = NULL; + break; + } + } + + if (target) { + strncpy(ifname, target->ifa_name, sizeof(ifname) - 1); + ifname[sizeof(ifname) - 1] = '\0'; + argv[0] = ifname; + argv[1] = NULL; + + if (dflag > 0) + warnx("probing %s", argv[0]); + } + freeifaddrs(ifap); + if (target) + return argv; + else + return (char **)NULL; +#endif +} diff --git a/rtsol.tproj/rtsold.h b/rtsol.tproj/rtsold.h new file mode 100644 index 0000000..dccbc57 --- /dev/null +++ b/rtsol.tproj/rtsold.h @@ -0,0 +1,95 @@ +/* $KAME: rtsold.h,v 1.11 2000/10/10 06:18:04 itojun 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. 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. + * + * $FreeBSD: src/usr.sbin/rtsold/rtsold.h,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $ + */ + +struct ifinfo { + struct ifinfo *next; /* pointer to the next interface */ + + struct sockaddr_dl *sdl; /* link-layer address */ + char ifname[IF_NAMESIZE]; /* interface name */ + int active; /* interface status */ + int probeinterval; /* interval of probe timer(if necessary) */ + int probetimer; /* rest of probe timer */ + int mediareqok; /* wheter the IF supports SIOCGIFMEDIA */ + int state; + int probes; + int dadcount; + struct timeval timer; + struct timeval expire; + int errors; /* # of errors we've got - detect wedge */ + + int racnt; /* total # of valid RAs it have got */ + + size_t rs_datalen; + u_char *rs_data; +}; + +/* per interface status */ +#define IFS_IDLE 0 +#define IFS_DELAY 1 +#define IFS_PROBE 2 +#define IFS_DOWN 3 +#define IFS_TENTATIVE 4 + +/* rtsold.c */ +extern struct timeval tm_max; +extern int dflag; +struct ifinfo *find_ifinfo __P((int ifindex)); +void rtsol_timer_update __P((struct ifinfo *ifinfo)); +extern void warnmsg __P((int, const char *, const char *, ...)) + __attribute__((__format__(__printf__, 3, 4))); + +/* if.c */ +extern int ifinit __P((void)); +extern int interface_up __P((char *name)); +extern int interface_status __P((struct ifinfo*)); +extern int lladdropt_length __P((struct sockaddr_dl *sdl)); +extern void lladdropt_fill __P((struct sockaddr_dl *sdl, + struct nd_opt_hdr *ndopt)); +extern struct sockaddr_dl *if_nametosdl __P((char *name)); +extern int getinet6sysctl __P((int code)); + +/* rtsol.c */ +extern int sockopen __P((void)); +extern void sendpacket __P((struct ifinfo *ifinfo)); +extern void rtsol_input __P((int s)); + +/* probe.c */ +extern int probe_init __P((void)); +extern void defrouter_probe __P((int ifindex)); + +/* dump.c */ +extern void rtsold_dump_file __P((char *)); + +/* rtsock.c */ +extern int rtsock_open __P((void)); +extern int rtsock_input __P((int)); diff --git a/setkey.tproj/Makefile b/setkey.tproj/Makefile new file mode 100644 index 0000000..fc8fbf0 --- /dev/null +++ b/setkey.tproj/Makefile @@ -0,0 +1,51 @@ +# +# Generated by the Apple Project Builder. +# +# NOTE: Do NOT change this file -- Project Builder maintains it. +# +# Put all of your customizations in files called Makefile.preamble +# and Makefile.postamble (both optional), and Makefile will include them. +# + +NAME = setkey + +PROJECTVERSION = 2.8 +PROJECT_TYPE = Tool + +HFILES = vchar.h ipsec_strerror.h key_debug.h libpfkey.h + +OTHERLINKED = libpfkey.h parse.y token.l + +CFILES = key_debug.c pfkey.c pfkey_dump.c setkey.c + +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble setkey.8 + +OTHERLINKEDOFILES = parse.o token.o + +MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles +CODE_GEN_STYLE = DYNAMIC +MAKEFILE = tool.make +NEXTSTEP_INSTALLDIR = /usr/sbin +WINDOWS_INSTALLDIR = /Library/Executables +PDO_UNIX_INSTALLDIR = /bin +LIBS = -lipsec +DEBUG_LIBS = $(LIBS) +PROF_LIBS = $(LIBS) + + +NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc +WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc +PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc +NEXTSTEP_JAVA_COMPILER = /usr/bin/javac +WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe +PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac + +include $(MAKEFILEDIR)/platform.make + +-include Makefile.preamble + +include $(MAKEFILEDIR)/$(MAKEFILE) + +-include Makefile.postamble + +-include Makefile.dependencies diff --git a/setkey.tproj/Makefile.postamble b/setkey.tproj/Makefile.postamble new file mode 100644 index 0000000..5d9d699 --- /dev/null +++ b/setkey.tproj/Makefile.postamble @@ -0,0 +1,103 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGES: langages in which the project is written (default "English") +# English_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# +install-man-page: + install -d "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 setkey.8 "$(DSTROOT)/usr/share/man/man8/setkey.8" diff --git a/setkey.tproj/Makefile.preamble b/setkey.tproj/Makefile.preamble new file mode 100644 index 0000000..be4a6ee --- /dev/null +++ b/setkey.tproj/Makefile.preamble @@ -0,0 +1,140 @@ +############################################################################### +# Makefile.preamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile for configuring the standard application makefiles +# associated with ProjectBuilder. It is included before the main makefile. +# In Makefile.preamble you set attributes for a project, so they are available +# to the project's makefiles. In contrast, you typically write additional rules or +# override built-in behavior in the Makefile.postamble. +# +# Each directory in a project tree (main project plus subprojects) should +# have its own Makefile.preamble and Makefile.postamble. +############################################################################### +# +# Before the main makefile is included for this project, you may set: +# +# MAKEFILEDIR: Directory in which to find $(MAKEFILE) +# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make) + +# Compiler/linker flags added to the defaults: The OTHER_* variables will be +# inherited by all nested sub-projects, but the LOCAL_ versions of the same +# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's +# Build Attributes inspector if at all possible. To override the default flags +# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The +# variables below are *inputs* to the build process and distinct from the override +# settings done (less often) in the Makefile.postamble. +# +# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler +# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m, +# .cc, .cxx, .C, and .M files. There is no need to respecify the +# flags in OTHER_MFLAGS, etc. +# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files +# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files +# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files +# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when +# precompiling header files +# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool +# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap +# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen +# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc +# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex +LOCAL_CFLAGS=-g -DIPSEC_DEBUG -DINET6 -DYY_NO_INPUT -I. +LOCAL_YFLAGS=-d + +# These variables provide hooks enabling you to add behavior at almost every +# stage of the make: +# +# BEFORE_PREBUILD: targets to build before installing headers for a subproject +# AFTER_PREBUILD: targets to build after installing headers for a subproject +# BEFORE_BUILD_RECURSION: targets to make before building subprojects +# BEFORE_BUILD: targets to make before a build, but after subprojects +# AFTER_BUILD: targets to make after a build +# +# BEFORE_INSTALL: targets to build before installing the product +# AFTER_INSTALL: targets to build after installing the product +# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject +# AFTER_POSTINSTALL: targts to build after postinstalling every subproject +# +# BEFORE_INSTALLHDRS: targets to build before installing headers for a +# subproject +# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject +# BEFORE_INSTALLSRC: targets to build before installing source for a subproject +# AFTER_INSTALLSRC: targets to build after installing source for a subproject +# +# BEFORE_DEPEND: targets to build before building dependencies for a +# subproject +# AFTER_DEPEND: targets to build after building dependencies for a +# subproject +# +# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is +# updated every time the project is built. If NO, the dependency +# file is only built when the depend target is invoked. + +# Framework-related variables: +# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the framework's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables +AFTER_INSTALL += install-man-page + +# Library-related variables: +# PUBLIC_HEADER_DIR: Determines where public exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. For library projects you should +# set this to something like /Developer/Headers/$(NAME). Do not set +# this variable for framework projects unless you do not want the +# header files included in the framework. +# PRIVATE_HEADER_DIR: Determines where private exported header files +# should be installed. Do not include $(DSTROOT) in this value -- +# it is prefixed automatically. +# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines +# whether the libraries produced are statically linked when they +# are used or if they are dynamically loadable. This defaults to +# DYNAMIC. +# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates +# where to put the library's DLL. This variable defaults to +# $(INSTALLDIR)/../Executables +# +# INSTALL_AS_USER: owner of the intalled products (default root) +# INSTALL_AS_GROUP: group of the installed products (default wheel) +# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX) +# +# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be +# passed on the command line to recursive invocations of make. Note that +# the values in OTHER_*FLAGS are inherited by subprojects automatically -- +# you do not have to (and shouldn't) add OTHER_*FLAGS to +# OTHER_RECURSIVE_VARIABLES. + +# Additional headers to export beyond those in the PB.project: +# OTHER_PUBLIC_HEADERS +# OTHER_PROJECT_HEADERS +# OTHER_PRIVATE_HEADERS + +# Additional files for the project's product: <> +# OTHER_RESOURCES: (non-localized) resources for this project +# OTHER_OFILES: relocatables to be linked into this project +# OTHER_LIBS: more libraries to link against +# OTHER_PRODUCT_DEPENDS: other dependencies of this project +# OTHER_SOURCEFILES: other source files maintained by .pre/postamble +# OTHER_GARBAGE: additional files to be removed by `make clean' + +# Set this to YES if you don't want a final libtool call for a library/framework. +# BUILD_OFILES_LIST_ONLY + +# To include a version string, project source must exist in a directory named +# $(NAME).%d[.%d][.%d] and the following line must be uncommented. +# OTHER_GENERATED_OFILES = $(VERS_OFILE) + +# This definition will suppress stripping of debug symbols when an executable +# is installed. By default it is YES. +# STRIP_ON_INSTALL = NO + +# Uncomment to suppress generation of a KeyValueCoding index when installing +# frameworks (This index is used by WOB and IB to determine keys available +# for an object). Set to YES by default. +# PREINDEX_FRAMEWORK = NO + +# Change this definition to install projects somewhere other than the +# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems +# and "" on other systems. +DSTROOT = $(HOME) diff --git a/ftp.tproj/PB.project b/setkey.tproj/PB.project similarity index 53% rename from ftp.tproj/PB.project rename to setkey.tproj/PB.project index 3b40ec2..50f2fe5 100644 --- a/ftp.tproj/PB.project +++ b/setkey.tproj/PB.project @@ -2,33 +2,26 @@ DYNAMIC_CODE_GEN = YES; FILESTABLE = { FRAMEWORKS = (); - H_FILES = (extern.h, ftp_var.h, pathnames.h); - OTHER_LINKED = (cmds.c, cmdtab.c, domacro.c, ftp.c, ftp_var.c, main.c, ruserpass.c); - OTHER_SOURCES = ( - Makefile.preamble, - Makefile, - Makefile.postamble, - m.template, - h.template, - ftp.1 - ); - SUBPROJECTS = (); + H_FILES = (vchar.h, ipsec_strerror.h, key_debug.h, libpfkey.h); + OTHER_LIBS = (ipsec); + OTHER_LINKED = (key_debug.c, parse.y, pfkey.c, pfkey_dump.c, setkey.c, token.l); + OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, setkey.8); }; LANGUAGE = English; - LOCALIZABLE_FILES = {}; MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles"; - NEXTSTEP_BUILDDIR = "/$(USER)/BUILD"; NEXTSTEP_BUILDTOOL = /bin/gnumake; - NEXTSTEP_INSTALLDIR = /usr/bin; + NEXTSTEP_INSTALLDIR = /bin; NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; + PDO_UNIX_INSTALLDIR = /bin; + PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac"; PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = ftp; + PROJECTNAME = setkey; PROJECTTYPE = Tool; PROJECTVERSION = 2.8; WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make; + WINDOWS_INSTALLDIR = /Library/Executables; WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; } diff --git a/setkey.tproj/ipsec_strerror.h b/setkey.tproj/ipsec_strerror.h new file mode 100644 index 0000000..da87324 --- /dev/null +++ b/setkey.tproj/ipsec_strerror.h @@ -0,0 +1,63 @@ +/* $FreeBSD: src/lib/libipsec/ipsec_strerror.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: ipsec_strerror.h,v 1.8 2000/07/30 00:45:12 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +extern int __ipsec_errcode; +extern void __ipsec_set_strerror __P((const char *)); + +#define EIPSEC_NO_ERROR 0 /*success*/ +#define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ +#define EIPSEC_INVAL_ARGUMENT 2 /*invalid argument*/ +#define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/ +#define EIPSEC_INVAL_VERSION 4 /*invalid version*/ +#define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/ +#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/ +#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/ +#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/ +#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/ +#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/ +#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/ +#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/ +#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/ +#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/ +#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/ +#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/ +#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/ +#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/ +#define EIPSEC_NO_PROTO 19 /*no protocol specified*/ +#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/ +#define EIPSEC_NO_BUFS 21 /*no buffers available*/ +#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/ +#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/ +#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/ +#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/ +#define EIPSEC_SYSTEM_ERROR 26 /*system error*/ +#define EIPSEC_MAX 27 /*unknown error*/ diff --git a/setkey.tproj/key_debug.c b/setkey.tproj/key_debug.c new file mode 100644 index 0000000..7ace6be --- /dev/null +++ b/setkey.tproj/key_debug.c @@ -0,0 +1,751 @@ +/* $FreeBSD: src/sys/netkey/key_debug.c,v 1.10.2.2 2001/07/03 11:01:59 ume Exp $ */ +/* $KAME: key_debug.c,v 1.25 2000/07/24 13:23:12 itojun 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. 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. + */ + +#ifdef _KERNEL +#include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipsec.h" +#endif + +#include +#include +#ifdef _KERNEL +#include +#include +#include +#endif +#include + +#include + +#include +#include + +#include +#include + +#ifndef _KERNEL +#include +#include +#include +#endif /* !_KERNEL */ + +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) + +static void kdebug_sadb_prop __P((struct sadb_ext *)); +static void kdebug_sadb_identity __P((struct sadb_ext *)); +static void kdebug_sadb_supported __P((struct sadb_ext *)); +static void kdebug_sadb_lifetime __P((struct sadb_ext *)); +static void kdebug_sadb_sa __P((struct sadb_ext *)); +static void kdebug_sadb_address __P((struct sadb_ext *)); +static void kdebug_sadb_key __P((struct sadb_ext *)); +static void kdebug_sadb_x_sa2 __P((struct sadb_ext *)); + +#ifdef _KERNEL +static void kdebug_secreplay __P((struct secreplay *)); +#endif + +#ifndef _KERNEL +#define panic(param) { printf(param); exit(-1); } +#endif + +/* NOTE: host byte order */ + +/* %%%: about struct sadb_msg */ +void +kdebug_sadb(base) + struct sadb_msg *base; +{ + struct sadb_ext *ext; + int tlen, extlen; + + /* sanity check */ + if (base == NULL) + panic("kdebug_sadb: NULL pointer was passed.\n"); + + printf("sadb_msg{ version=%u type=%u errno=%u satype=%u\n", + base->sadb_msg_version, base->sadb_msg_type, + base->sadb_msg_errno, base->sadb_msg_satype); + printf(" len=%u reserved=%u seq=%u pid=%u\n", + base->sadb_msg_len, base->sadb_msg_reserved, + base->sadb_msg_seq, base->sadb_msg_pid); + + tlen = PFKEY_UNUNIT64(base->sadb_msg_len) - sizeof(struct sadb_msg); + ext = (struct sadb_ext *)((caddr_t)base + sizeof(struct sadb_msg)); + + while (tlen > 0) { + printf("sadb_ext{ len=%u type=%u }\n", + ext->sadb_ext_len, ext->sadb_ext_type); + + if (ext->sadb_ext_len == 0) { + printf("kdebug_sadb: invalid ext_len=0 was passed.\n"); + return; + } + if (ext->sadb_ext_len > tlen) { + printf("kdebug_sadb: ext_len exceeds end of buffer.\n"); + return; + } + + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + kdebug_sadb_sa(ext); + break; + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + kdebug_sadb_lifetime(ext); + break; + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + kdebug_sadb_address(ext); + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + kdebug_sadb_key(ext); + break; + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + kdebug_sadb_identity(ext); + break; + case SADB_EXT_SENSITIVITY: + break; + case SADB_EXT_PROPOSAL: + kdebug_sadb_prop(ext); + break; + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + kdebug_sadb_supported(ext); + break; + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_KMPRIVATE: + break; + case SADB_X_EXT_POLICY: + kdebug_sadb_x_policy(ext); + break; + case SADB_X_EXT_SA2: + kdebug_sadb_x_sa2(ext); + break; + default: + printf("kdebug_sadb: invalid ext_type %u was passed.\n", + ext->sadb_ext_type); + return; + } + + extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + tlen -= extlen; + ext = (struct sadb_ext *)((caddr_t)ext + extlen); + } + + return; +} + +static void +kdebug_sadb_prop(ext) + struct sadb_ext *ext; +{ + struct sadb_prop *prop = (struct sadb_prop *)ext; + struct sadb_comb *comb; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_prop: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(prop->sadb_prop_len) - sizeof(*prop)) + / sizeof(*comb); + comb = (struct sadb_comb *)(prop + 1); + printf("sadb_prop{ replay=%u\n", prop->sadb_prop_replay); + + while (len--) { + printf("sadb_comb{ auth=%u encrypt=%u " + "flags=0x%04x reserved=0x%08x\n", + comb->sadb_comb_auth, comb->sadb_comb_encrypt, + comb->sadb_comb_flags, comb->sadb_comb_reserved); + + printf(" auth_minbits=%u auth_maxbits=%u " + "encrypt_minbits=%u encrypt_maxbits=%u\n", + comb->sadb_comb_auth_minbits, + comb->sadb_comb_auth_maxbits, + comb->sadb_comb_encrypt_minbits, + comb->sadb_comb_encrypt_maxbits); + + printf(" soft_alloc=%u hard_alloc=%u " + "soft_bytes=%lu hard_bytes=%lu\n", + comb->sadb_comb_soft_allocations, + comb->sadb_comb_hard_allocations, + (unsigned long)comb->sadb_comb_soft_bytes, + (unsigned long)comb->sadb_comb_hard_bytes); + + printf(" soft_alloc=%lu hard_alloc=%lu " + "soft_bytes=%lu hard_bytes=%lu }\n", + (unsigned long)comb->sadb_comb_soft_addtime, + (unsigned long)comb->sadb_comb_hard_addtime, + (unsigned long)comb->sadb_comb_soft_usetime, + (unsigned long)comb->sadb_comb_hard_usetime); + comb++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_identity(ext) + struct sadb_ext *ext; +{ + struct sadb_ident *id = (struct sadb_ident *)ext; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_identity: NULL pointer was passed.\n"); + + len = PFKEY_UNUNIT64(id->sadb_ident_len) - sizeof(*id); + printf("sadb_ident_%s{", + id->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC ? "src" : "dst"); + switch (id->sadb_ident_type) { + default: + printf(" type=%d id=%lu", + id->sadb_ident_type, (u_long)id->sadb_ident_id); + if (len) { +#ifdef _KERNEL + ipsec_hexdump((caddr_t)(id + 1), len); /*XXX cast ?*/ +#else + char *p, *ep; + printf("\n str=\""); + p = (char *)(id + 1); + ep = p + len; + for (/*nothing*/; *p && p < ep; p++) { + if (isprint(*p)) + printf("%c", *p & 0xff); + else + printf("\\%03o", *p & 0xff); + } +#endif + printf("\""); + } + break; + } + + printf(" }\n"); + + return; +} + +static void +kdebug_sadb_supported(ext) + struct sadb_ext *ext; +{ + struct sadb_supported *sup = (struct sadb_supported *)ext; + struct sadb_alg *alg; + int len; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_supported: NULL pointer was passed.\n"); + + len = (PFKEY_UNUNIT64(sup->sadb_supported_len) - sizeof(*sup)) + / sizeof(*alg); + alg = (struct sadb_alg *)(sup + 1); + printf("sadb_sup{\n"); + while (len--) { + printf(" { id=%d ivlen=%d min=%d max=%d }\n", + alg->sadb_alg_id, alg->sadb_alg_ivlen, + alg->sadb_alg_minbits, alg->sadb_alg_maxbits); + alg++; + } + printf("}\n"); + + return; +} + +static void +kdebug_sadb_lifetime(ext) + struct sadb_ext *ext; +{ + struct sadb_lifetime *lft = (struct sadb_lifetime *)ext; + + /* sanity check */ + if (ext == NULL) + printf("kdebug_sadb_lifetime: NULL pointer was passed.\n"); + + printf("sadb_lifetime{ alloc=%u, bytes=%u\n", + lft->sadb_lifetime_allocations, + (u_int32_t)lft->sadb_lifetime_bytes); + printf(" addtime=%u, usetime=%u }\n", + (u_int32_t)lft->sadb_lifetime_addtime, + (u_int32_t)lft->sadb_lifetime_usetime); + + return; +} + +static void +kdebug_sadb_sa(ext) + struct sadb_ext *ext; +{ + struct sadb_sa *sa = (struct sadb_sa *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_sa: NULL pointer was passed.\n"); + + printf("sadb_sa{ spi=%u replay=%u state=%u\n", + (u_int32_t)ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, + sa->sadb_sa_state); + printf(" auth=%u encrypt=%u flags=0x%08x }\n", + sa->sadb_sa_auth, sa->sadb_sa_encrypt, sa->sadb_sa_flags); + + return; +} + +static void +kdebug_sadb_address(ext) + struct sadb_ext *ext; +{ + struct sadb_address *addr = (struct sadb_address *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_address: NULL pointer was passed.\n"); + + printf("sadb_address{ proto=%u prefixlen=%u reserved=0x%02x%02x }\n", + addr->sadb_address_proto, addr->sadb_address_prefixlen, + ((u_char *)&addr->sadb_address_reserved)[0], + ((u_char *)&addr->sadb_address_reserved)[1]); + + kdebug_sockaddr((struct sockaddr *)((caddr_t)ext + sizeof(*addr))); + + return; +} + +static void +kdebug_sadb_key(ext) + struct sadb_ext *ext; +{ + struct sadb_key *key = (struct sadb_key *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_key: NULL pointer was passed.\n"); + + printf("sadb_key{ bits=%u reserved=%u\n", + key->sadb_key_bits, key->sadb_key_reserved); + printf(" key="); + + /* sanity check 2 */ + if ((key->sadb_key_bits >> 3) > + (PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key))) { + printf("kdebug_sadb_key: key length mismatch, bit:%d len:%ld.\n", + key->sadb_key_bits >> 3, + (long)PFKEY_UNUNIT64(key->sadb_key_len) - sizeof(struct sadb_key)); + } + + ipsec_hexdump((caddr_t)key + sizeof(struct sadb_key), + key->sadb_key_bits >> 3); + printf(" }\n"); + return; +} + +static void +kdebug_sadb_x_sa2(ext) + struct sadb_ext *ext; +{ + struct sadb_x_sa2 *sa2 = (struct sadb_x_sa2 *)ext; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_sa2: NULL pointer was passed.\n"); + + printf("sadb_x_sa2{ mode=%u reqid=%u\n", + sa2->sadb_x_sa2_mode, sa2->sadb_x_sa2_reqid); + printf(" reserved1=%u reserved2=%u reserved3=%u }\n", + sa2->sadb_x_sa2_reserved1, sa2->sadb_x_sa2_reserved1, + sa2->sadb_x_sa2_reserved1); + + return; +} + +void +kdebug_sadb_x_policy(ext) + struct sadb_ext *ext; +{ + struct sadb_x_policy *xpl = (struct sadb_x_policy *)ext; + struct sockaddr *addr; + + /* sanity check */ + if (ext == NULL) + panic("kdebug_sadb_x_policy: NULL pointer was passed.\n"); + + printf("sadb_x_policy{ type=%u dir=%u id=%x }\n", + xpl->sadb_x_policy_type, xpl->sadb_x_policy_dir, + xpl->sadb_x_policy_id); + + if (xpl->sadb_x_policy_type == IPSEC_POLICY_IPSEC) { + int tlen; + struct sadb_x_ipsecrequest *xisr; + + tlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); + xisr = (struct sadb_x_ipsecrequest *)(xpl + 1); + + while (tlen > 0) { + printf(" { len=%u proto=%u mode=%u level=%u reqid=%u\n", + xisr->sadb_x_ipsecrequest_len, + xisr->sadb_x_ipsecrequest_proto, + xisr->sadb_x_ipsecrequest_mode, + xisr->sadb_x_ipsecrequest_level, + xisr->sadb_x_ipsecrequest_reqid); + + if (xisr->sadb_x_ipsecrequest_len > sizeof(*xisr)) { + addr = (struct sockaddr *)(xisr + 1); + kdebug_sockaddr(addr); + addr = (struct sockaddr *)((caddr_t)addr + + addr->sa_len); + kdebug_sockaddr(addr); + } + + printf(" }\n"); + + /* prevent infinite loop */ + if (xisr->sadb_x_ipsecrequest_len <= 0) { + printf("kdebug_sadb_x_policy: wrong policy struct.\n"); + return; + } + /* prevent overflow */ + if (xisr->sadb_x_ipsecrequest_len > tlen) { + printf("invalid ipsec policy length\n"); + return; + } + + tlen -= xisr->sadb_x_ipsecrequest_len; + + xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr + + xisr->sadb_x_ipsecrequest_len); + } + + if (tlen != 0) + panic("kdebug_sadb_x_policy: wrong policy struct.\n"); + } + + return; +} + +#ifdef _KERNEL +/* %%%: about SPD and SAD */ +void +kdebug_secpolicy(sp) + struct secpolicy *sp; +{ + /* sanity check */ + if (sp == NULL) + panic("kdebug_secpolicy: NULL pointer was passed.\n"); + + printf("secpolicy{ refcnt=%u state=%u policy=%u\n", + sp->refcnt, sp->state, sp->policy); + + kdebug_secpolicyindex(&sp->spidx); + + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + printf(" type=discard }\n"); + break; + case IPSEC_POLICY_NONE: + printf(" type=none }\n"); + break; + case IPSEC_POLICY_IPSEC: + { + struct ipsecrequest *isr; + for (isr = sp->req; isr != NULL; isr = isr->next) { + + printf(" level=%u\n", isr->level); + kdebug_secasindex(&isr->saidx); + + if (isr->sav != NULL) + kdebug_secasv(isr->sav); + } + printf(" }\n"); + } + break; + case IPSEC_POLICY_BYPASS: + printf(" type=bypass }\n"); + break; + case IPSEC_POLICY_ENTRUST: + printf(" type=entrust }\n"); + break; + default: + printf("kdebug_secpolicy: Invalid policy found. %d\n", + sp->policy); + break; + } + + return; +} + +void +kdebug_secpolicyindex(spidx) + struct secpolicyindex *spidx; +{ + /* sanity check */ + if (spidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secpolicyindex{ dir=%u prefs=%u prefd=%u ul_proto=%u\n", + spidx->dir, spidx->prefs, spidx->prefd, spidx->ul_proto); + + ipsec_hexdump((caddr_t)&spidx->src, + ((struct sockaddr *)&spidx->src)->sa_len); + printf("\n"); + ipsec_hexdump((caddr_t)&spidx->dst, + ((struct sockaddr *)&spidx->dst)->sa_len); + printf("}\n"); + + return; +} + +void +kdebug_secasindex(saidx) + struct secasindex *saidx; +{ + /* sanity check */ + if (saidx == NULL) + panic("kdebug_secpolicyindex: NULL pointer was passed.\n"); + + printf("secasindex{ mode=%u proto=%u\n", + saidx->mode, saidx->proto); + + ipsec_hexdump((caddr_t)&saidx->src, + ((struct sockaddr *)&saidx->src)->sa_len); + printf("\n"); + ipsec_hexdump((caddr_t)&saidx->dst, + ((struct sockaddr *)&saidx->dst)->sa_len); + printf("\n"); + + return; +} + +void +kdebug_secasv(sav) + struct secasvar *sav; +{ + /* sanity check */ + if (sav == NULL) + panic("kdebug_secasv: NULL pointer was passed.\n"); + + printf("secas{"); + kdebug_secasindex(&sav->sah->saidx); + + printf(" refcnt=%u state=%u auth=%u enc=%u\n", + sav->refcnt, sav->state, sav->alg_auth, sav->alg_enc); + printf(" spi=%u flags=%u\n", + (u_int32_t)ntohl(sav->spi), sav->flags); + + if (sav->key_auth != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_auth); + if (sav->key_enc != NULL) + kdebug_sadb_key((struct sadb_ext *)sav->key_enc); + if (sav->iv != NULL) { + printf(" iv="); + ipsec_hexdump(sav->iv, sav->ivlen ? sav->ivlen : 8); + printf("\n"); + } + + if (sav->replay != NULL) + kdebug_secreplay(sav->replay); + if (sav->lft_c != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_c); + if (sav->lft_h != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_h); + if (sav->lft_s != NULL) + kdebug_sadb_lifetime((struct sadb_ext *)sav->lft_s); + +#if notyet + /* XXX: misc[123] ? */ +#endif + + return; +} + +static void +kdebug_secreplay(rpl) + struct secreplay *rpl; +{ + int len, l; + + /* sanity check */ + if (rpl == NULL) + panic("kdebug_secreplay: NULL pointer was passed.\n"); + + printf(" secreplay{ count=%u wsize=%u seq=%u lastseq=%u", + rpl->count, rpl->wsize, rpl->seq, rpl->lastseq); + + if (rpl->bitmap == NULL) { + printf(" }\n"); + return; + } + + printf("\n bitmap { "); + + for (len = 0; len < rpl->wsize; len++) { + for (l = 7; l >= 0; l--) + printf("%u", (((rpl->bitmap)[len] >> l) & 1) ? 1 : 0); + } + printf(" }\n"); + + return; +} + +void +kdebug_mbufhdr(m) + struct mbuf *m; +{ + /* sanity check */ + if (m == NULL) + return; + + printf("mbuf(%p){ m_next:%p m_nextpkt:%p m_data:%p " + "m_len:%d m_type:0x%02x m_flags:0x%02x }\n", + m, m->m_next, m->m_nextpkt, m->m_data, + m->m_len, m->m_type, m->m_flags); + + if (m->m_flags & M_PKTHDR) { + printf(" m_pkthdr{ len:%d rcvif:%p }\n", + m->m_pkthdr.len, m->m_pkthdr.rcvif); + } + + if (m->m_flags & M_EXT) { + printf(" m_ext{ ext_buf:%p ext_free:%p " + "ext_size:%u ext_ref:%p }\n", + m->m_ext.ext_buf, m->m_ext.ext_free, + m->m_ext.ext_size, m->m_ext.ext_ref); + } + + return; +} + +void +kdebug_mbuf(m0) + struct mbuf *m0; +{ + struct mbuf *m = m0; + int i, j; + + for (j = 0; m; m = m->m_next) { + kdebug_mbufhdr(m); + printf(" m_data:\n"); + for (i = 0; i < m->m_len; i++) { + if (i && i % 32 == 0) + printf("\n"); + if (i % 4 == 0) + printf(" "); + printf("%02x", mtod(m, u_char *)[i]); + j++; + } + printf("\n"); + } + + return; +} +#endif /* _KERNEL */ + +void +kdebug_sockaddr(addr) + struct sockaddr *addr; +{ + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + + /* sanity check */ + if (addr == NULL) + panic("kdebug_sockaddr: NULL pointer was passed.\n"); + + /* NOTE: We deal with port number as host byte order. */ + printf("sockaddr{ len=%u family=%u", addr->sa_len, addr->sa_family); + + switch (addr->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *)addr; + printf(" port=%u\n", ntohs(sin->sin_port)); + ipsec_hexdump((caddr_t)&sin->sin_addr, sizeof(sin->sin_addr)); + break; +#ifdef INET6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *)addr; + printf(" port=%u\n", ntohs(sin6->sin6_port)); + printf(" flowinfo=0x%08x, scope_id=0x%08x\n", + sin6->sin6_flowinfo, sin6->sin6_scope_id); + ipsec_hexdump((caddr_t)&sin6->sin6_addr, + sizeof(sin6->sin6_addr)); + break; +#endif + } + + printf(" }\n"); + + return; +} + +void +ipsec_bindump(buf, len) + caddr_t buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) + printf("%c", (unsigned char)buf[i]); + + return; +} + + +void +ipsec_hexdump(buf, len) + caddr_t buf; + int len; +{ + int i; + + for (i = 0; i < len; i++) { + if (i != 0 && i % 32 == 0) printf("\n"); + if (i % 4 == 0) printf(" "); + printf("%02x", (unsigned char)buf[i]); + } +#if 0 + if (i % 32 != 0) printf("\n"); +#endif + + return; +} + +#endif /* !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) */ diff --git a/setkey.tproj/key_debug.h b/setkey.tproj/key_debug.h new file mode 100644 index 0000000..7620da5 --- /dev/null +++ b/setkey.tproj/key_debug.h @@ -0,0 +1,95 @@ +/* $FreeBSD: src/sys/netkey/key_debug.h,v 1.5.2.2 2001/07/03 11:01:59 ume Exp $ */ +/* $KAME: key_debug.h,v 1.7 2000/07/04 04:08:16 itojun 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. 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. + */ + +#ifndef _NETKEY_KEY_DEBUG_H_ +#define _NETKEY_KEY_DEBUG_H_ + +#if !defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG)) + +/* debug flags */ +#define KEYDEBUG_STAMP 0x00000001 /* path */ +#define KEYDEBUG_DATA 0x00000002 /* data */ +#define KEYDEBUG_DUMP 0x00000004 /* dump */ + +#define KEYDEBUG_KEY 0x00000010 /* key processing */ +#define KEYDEBUG_ALG 0x00000020 /* ciph & auth algorithm */ +#define KEYDEBUG_IPSEC 0x00000040 /* ipsec processing */ + +#define KEYDEBUG_KEY_STAMP (KEYDEBUG_KEY | KEYDEBUG_STAMP) +#define KEYDEBUG_KEY_DATA (KEYDEBUG_KEY | KEYDEBUG_DATA) +#define KEYDEBUG_KEY_DUMP (KEYDEBUG_KEY | KEYDEBUG_DUMP) +#define KEYDEBUG_ALG_STAMP (KEYDEBUG_ALG | KEYDEBUG_STAMP) +#define KEYDEBUG_ALG_DATA (KEYDEBUG_ALG | KEYDEBUG_DATA) +#define KEYDEBUG_ALG_DUMP (KEYDEBUG_ALG | KEYDEBUG_DUMP) +#define KEYDEBUG_IPSEC_STAMP (KEYDEBUG_IPSEC | KEYDEBUG_STAMP) +#define KEYDEBUG_IPSEC_DATA (KEYDEBUG_IPSEC | KEYDEBUG_DATA) +#define KEYDEBUG_IPSEC_DUMP (KEYDEBUG_IPSEC | KEYDEBUG_DUMP) + +#define KEYDEBUG(lev,arg) if ((key_debug_level & (lev)) == (lev)) { arg; } + +#ifdef _KERNEL +extern u_int32_t key_debug_level; +#endif /*_KERNEL*/ + +struct sadb_msg; +struct sadb_ext; +extern void kdebug_sadb __P((struct sadb_msg *)); +extern void kdebug_sadb_x_policy __P((struct sadb_ext *)); + +#ifdef _KERNEL +struct secpolicy; +struct secpolicyindex; +struct secasindex; +struct secasvar; +struct secreplay; +struct mbuf; +extern void kdebug_secpolicy __P((struct secpolicy *)); +extern void kdebug_secpolicyindex __P((struct secpolicyindex *)); +extern void kdebug_secasindex __P((struct secasindex *)); +extern void kdebug_secasv __P((struct secasvar *)); +extern void kdebug_mbufhdr __P((struct mbuf *)); +extern void kdebug_mbuf __P((struct mbuf *)); +#endif /*_KERNEL*/ + +struct sockaddr; +extern void kdebug_sockaddr __P((struct sockaddr *)); + +extern void ipsec_hexdump __P((caddr_t, int)); +extern void ipsec_bindump __P((caddr_t, int)); + +#else + +#define KEYDEBUG(lev,arg) + +#endif /*!defined(_KERNEL) || (defined(_KERNEL) && defined(IPSEC_DEBUG))*/ + +#endif /* _NETKEY_KEY_DEBUG_H_ */ diff --git a/setkey.tproj/libpfkey.h b/setkey.tproj/libpfkey.h new file mode 100644 index 0000000..28adea7 --- /dev/null +++ b/setkey.tproj/libpfkey.h @@ -0,0 +1,90 @@ +/* $FreeBSD: src/lib/libipsec/libpfkey.h,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: libpfkey.h,v 1.6 2001/03/05 18:22:17 thorpej 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. 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. + */ + +struct sadb_msg; +extern void pfkey_sadump __P((struct sadb_msg *)); +extern void pfkey_spdump __P((struct sadb_msg *)); + +struct sockaddr; +struct sadb_alg; +int ipsec_check_keylen __P((u_int, u_int, u_int)); +int ipsec_check_keylen2 __P((u_int, u_int, u_int)); +int ipsec_get_keylen __P((u_int, u_int, struct sadb_alg *)); +u_int pfkey_set_softrate __P((u_int, u_int)); +u_int pfkey_get_softrate __P((u_int)); +int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t)); +int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, + caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t, + u_int64_t, u_int64_t, u_int32_t)); +int pfkey_send_delete __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_delete_all __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *)); +int pfkey_send_get __P((int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +int pfkey_send_register __P((int, u_int)); +int pfkey_recv_register __P((int)); +int pfkey_set_supported __P((struct sadb_msg *, int)); +int pfkey_send_flush __P((int, u_int)); +int pfkey_send_dump __P((int, u_int)); +int pfkey_send_promisc_toggle __P((int, int)); +int pfkey_send_spdadd __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdadd2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdupdate2 __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + caddr_t, int, u_int32_t)); +int pfkey_send_spddelete __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spddelete2 __P((int, u_int32_t)); +int pfkey_send_spdget __P((int, u_int32_t)); +int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t)); +int pfkey_send_spdflush __P((int)); +int pfkey_send_spddump __P((int)); + +int pfkey_open __P((void)); +void pfkey_close __P((int)); +struct sadb_msg *pfkey_recv __P((int)); +int pfkey_send __P((int, struct sadb_msg *, int)); +int pfkey_align __P((struct sadb_msg *, caddr_t *)); +int pfkey_check __P((caddr_t *)); diff --git a/setkey.tproj/parse.y b/setkey.tproj/parse.y new file mode 100644 index 0000000..92f998e --- /dev/null +++ b/setkey.tproj/parse.y @@ -0,0 +1,933 @@ +/* $FreeBSD: src/usr.sbin/setkey/parse.y,v 1.1.2.2 2001/07/03 11:02:17 ume Exp $ */ +/* $KAME: kame/kame/kame/setkey/parse.y,v 1.36 2001/06/07 15:53:12 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +%{ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "libpfkey.h" +#include "vchar.h" + +#define ATOX(c) \ + (isdigit(c) ? (c - '0') : (isupper(c) ? (c - 'A' + 10) : (c - 'a' + 10) )) + +u_int p_type; +u_int32_t p_spi; +int p_no_spi; +struct sockaddr *p_src, *p_dst; +u_int p_prefs, p_prefd, p_upper; +u_int p_satype, p_ext, p_alg_enc, p_alg_auth, p_replay, p_mode; +u_int32_t p_reqid; +u_int p_key_enc_len, p_key_auth_len; +caddr_t p_key_enc, p_key_auth; +time_t p_lt_hard, p_lt_soft; + +u_int p_policy_len; +char *p_policy; + +/* temporary buffer */ +static struct sockaddr *pp_addr; +static u_int pp_prefix; +static u_int pp_port; +static caddr_t pp_key; + +extern u_char m_buf[BUFSIZ]; +extern int m_len; +extern char cmdarg[8192]; +extern int f_debug; + +static struct addrinfo *parse_addr __P((char *, char *, int)); +static int setvarbuf __P((int *, struct sadb_ext *, int, caddr_t, int)); +void parse_init __P((void)); +void free_buffer __P((void)); + +extern int setkeymsg __P((void)); +extern int sendkeymsg __P((void)); + +extern int yylex __P((void)); +extern void yyfatal __P((const char *)); +extern void yyerror __P((const char *)); +%} + +%union { + unsigned long num; + vchar_t val; +} + +%token EOT +%token ADD GET DELETE FLUSH DUMP +%token ADDRESS PREFIX PORT PORTANY +%token UP_PROTO PR_ESP PR_AH PR_IPCOMP +%token F_PROTOCOL F_AUTH F_ENC F_REPLAY F_COMP F_RAWCPI +%token F_MODE MODE F_REQID +%token F_EXT EXTENSION NOCYCLICSEQ +%token ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP +%token F_LIFETIME_HARD F_LIFETIME_SOFT +%token DECSTRING QUOTEDSTRING HEXSTRING STRING ANY + /* SPD management */ +%token SPDADD SPDDELETE SPDDUMP SPDFLUSH +%token F_POLICY PL_REQUESTS + +%type PORT PREFIX EXTENSION MODE +%type UP_PROTO PR_ESP PR_AH PR_IPCOMP +%type ALG_AUTH ALG_ENC ALG_ENC_DESDERIV ALG_ENC_DES32IV ALG_COMP +%type DECSTRING +%type ADDRESS PL_REQUESTS +%type key_string policy_requests +%type QUOTEDSTRING HEXSTRING STRING + +%% +commands + : /*NOTHING*/ + | commands command + { + if (f_debug) { + printf("cmdarg:\n%s\n", cmdarg); + } else { + setkeymsg(); + sendkeymsg(); + } + free_buffer(); + parse_init(); + } + ; + +command + : add_command + | get_command + | delete_command + | deleteall_command + | flush_command + | dump_command + | spdadd_command + | spddelete_command + | spddump_command + | spdflush_command + ; + /* commands concerned with management, there is in tail of this file. */ + + /* add command */ +add_command + : ADD { p_type = SADB_ADD; } + sa_selector_spec extension_spec algorithm_spec EOT + ; + + /* delete */ +delete_command + : DELETE { p_type = SADB_DELETE; } + sa_selector_spec extension_spec + { + if (p_mode != IPSEC_MODE_ANY) + yyerror("WARNING: mode is obsoleted."); + } + EOT + ; + + /* deleteall command */ +deleteall_command + : DELETEALL { p_type = SADB_DELETE; } + ipaddress { p_src = pp_addr; } + ipaddress { p_dst = pp_addr; } + protocol_spec + { p_no_spi = 1; } + EOT + ; + + /* get command */ +get_command + : GET { p_type = SADB_GET; } + sa_selector_spec extension_spec + { + if (p_mode != IPSEC_MODE_ANY) + yyerror("WARNING: mode is obsoleted."); + } + EOT + ; + + /* flush */ +flush_command + : FLUSH { p_type = SADB_FLUSH; } + protocol_spec EOT + ; + + /* dump */ +dump_command + : DUMP { p_type = SADB_DUMP; } + protocol_spec EOT + ; + + /* sa_selector_spec */ +sa_selector_spec + : ipaddress { p_src = pp_addr; } + ipaddress { p_dst = pp_addr; } + protocol_spec spi + ; + +protocol_spec + : /*NOTHING*/ { p_satype = SADB_SATYPE_UNSPEC; } + | PR_ESP + { + p_satype = SADB_SATYPE_ESP; + if ($1 == 1) + p_ext |= SADB_X_EXT_OLD; + else + p_ext &= ~SADB_X_EXT_OLD; + } + | PR_AH + { + p_satype = SADB_SATYPE_AH; + if ($1 == 1) + p_ext |= SADB_X_EXT_OLD; + else + p_ext &= ~SADB_X_EXT_OLD; + } + | PR_IPCOMP + { + p_satype = SADB_X_SATYPE_IPCOMP; + } + ; + +spi + : DECSTRING { p_spi = $1; } + | HEXSTRING + { + caddr_t bp; + caddr_t yp = $1.buf; + char buf0[4], buf[4]; + int i, j; + + /* sanity check */ + if ($1.len > 4) { + yyerror("SPI too big."); + free($1.buf); + return -1; + } + + bp = buf0; + while (*yp) { + *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); + yp += 2, bp++; + } + + /* initialize */ + for (i = 0; i < 4; i++) buf[i] = 0; + + for (j = $1.len - 1, i = 3; j >= 0; j--, i--) + buf[i] = buf0[j]; + + /* XXX: endian */ + p_spi = ntohl(*(u_int32_t *)buf); + + free($1.buf); + } + ; + +algorithm_spec + : esp_spec + | ah_spec + | ipcomp_spec + ; + +esp_spec + : F_ENC enc_alg enc_key F_AUTH auth_alg auth_key + | F_ENC enc_alg enc_key + ; + +ah_spec + : F_AUTH auth_alg auth_key + ; + +ipcomp_spec + : F_COMP ALG_COMP { p_alg_enc = $2; } + | F_COMP ALG_COMP { p_alg_enc = $2; } + F_RAWCPI { p_ext |= SADB_X_EXT_RAWCPI; } + ; + +enc_alg + : ALG_ENC { p_alg_enc = $1; } + | ALG_ENC_DESDERIV + { + p_alg_enc = $1; + if (p_ext & SADB_X_EXT_OLD) { + yyerror("algorithm mismatched."); + return -1; + } + p_ext |= SADB_X_EXT_DERIV; + } + | ALG_ENC_DES32IV + { + p_alg_enc = $1; + if (!(p_ext & SADB_X_EXT_OLD)) { + yyerror("algorithm mismatched."); + return -1; + } + p_ext |= SADB_X_EXT_IV4B; + } + ; + +enc_key + : /*NOTHING*/ + { + if (p_alg_enc != SADB_EALG_NULL) { + yyerror("no key found."); + return -1; + } + } + | key_string + { + p_key_enc_len = $1.len; + p_key_enc = pp_key; + + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_ENCRYPT, + p_alg_enc, + PFKEY_UNUNIT64(p_key_enc_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + ; + +auth_alg + : ALG_AUTH { p_alg_auth = $1; } + ; + +auth_key + : /*NOTHING*/ + { + if (p_alg_auth != SADB_X_AALG_NULL) { + yyerror("no key found."); + return -1; + } + } + | key_string + { + p_key_auth_len = $1.len; + p_key_auth = pp_key; + + if (ipsec_check_keylen(SADB_EXT_SUPPORTED_AUTH, + p_alg_auth, + PFKEY_UNUNIT64(p_key_auth_len)) < 0) { + yyerror(ipsec_strerror()); + return -1; + } + } + ; + +key_string + : QUOTEDSTRING + { + pp_key = $1.buf; + /* free pp_key later */ + } + | HEXSTRING + { + caddr_t bp; + caddr_t yp = $1.buf; + + if ((pp_key = malloc($1.len)) == 0) { + free($1.buf); + yyerror("not enough core"); + return -1; + } + memset(pp_key, 0, $1.len); + + bp = pp_key; + while (*yp) { + *bp = (ATOX(yp[0]) << 4) | ATOX(yp[1]); + yp += 2, bp++; + } + + free($1.buf); + } + ; + +extension_spec + : /*NOTHING*/ + | extension_spec extension + ; + +extension + : F_EXT EXTENSION { p_ext |= $2; } + | F_EXT NOCYCLICSEQ { p_ext &= ~SADB_X_EXT_CYCSEQ; } + | F_MODE MODE { p_mode = $2; } + | F_MODE ANY { p_mode = IPSEC_MODE_ANY; } + | F_REQID DECSTRING { p_reqid = $2; } + | F_REPLAY DECSTRING + { + if (p_ext & SADB_X_EXT_OLD) { + yyerror("replay prevention " + "only use on new spec."); + return -1; + } + p_replay = $2; + } + | F_LIFETIME_HARD DECSTRING { p_lt_hard = $2; } + | F_LIFETIME_SOFT DECSTRING { p_lt_soft = $2; } + ; + + /* definition about command for SPD management */ + /* spdadd */ +spdadd_command + : SPDADD + { + p_type = SADB_X_SPDADD; + p_satype = SADB_SATYPE_UNSPEC; + } + sp_selector_spec policy_spec EOT + ; + +spddelete_command: + SPDDELETE + { + p_type = SADB_X_SPDDELETE; + p_satype = SADB_SATYPE_UNSPEC; + } + sp_selector_spec policy_spec EOT + ; + +spddump_command: + SPDDUMP + { + p_type = SADB_X_SPDDUMP; + p_satype = SADB_SATYPE_UNSPEC; + } + EOT + ; + +spdflush_command: + SPDFLUSH + { + p_type = SADB_X_SPDFLUSH; + p_satype = SADB_SATYPE_UNSPEC; + } + EOT + ; + + /* sp_selector_spec */ +sp_selector_spec + : ipaddress { p_src = pp_addr; } + prefix { p_prefs = pp_prefix; } + port + { + switch (p_src->sa_family) { + case AF_INET: + ((struct sockaddr_in *)p_src)->sin_port = + htons(pp_port); + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)p_src)->sin6_port = + htons(pp_port); + break; +#endif + default: + exit(1); /*XXX*/ + } + } + ipaddress { p_dst = pp_addr; } + prefix { p_prefd = pp_prefix; } + port + { + switch (p_dst->sa_family) { + case AF_INET: + ((struct sockaddr_in *)p_dst)->sin_port = + htons(pp_port); + break; +#ifdef INET6 + case AF_INET6: + ((struct sockaddr_in6 *)p_dst)->sin6_port = + htons(pp_port); + break; +#endif + default: + exit(1); /*XXX*/ + } + } + upper_spec + { + /* XXX is it something userland should check? */ +#if 0 + switch (p_upper) { + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + if (_INPORTBYSA(p_src) != IPSEC_PORT_ANY + || _INPORTBYSA(p_dst) != IPSEC_PORT_ANY) { + yyerror("port number must be \"any\"."); + return -1; + } + if ((pp_addr->sa_family == AF_INET6 + && p_upper == IPPROTO_ICMP) + || (pp_addr->sa_family == AF_INET + && p_upper == IPPROTO_ICMPV6)) { + yyerror("upper layer protocol " + "mismatched.\n"); + return -1; + } + break; + default: + break; + } +#endif + } + ; + +ipaddress + : ADDRESS + { + struct addrinfo *res; + + res = parse_addr($1.buf, NULL, AI_NUMERICHOST); + if (res == NULL) { + free($1.buf); + return -1; + } + pp_addr = (struct sockaddr *)malloc(res->ai_addrlen); + if (!pp_addr) { + yyerror("not enough core"); + goto end; + } + + memcpy(pp_addr, res->ai_addr, res->ai_addrlen); + end: + freeaddrinfo(res); + free($1.buf); + } + ; + +prefix + : /*NOTHING*/ { pp_prefix = ~0; } + | PREFIX { pp_prefix = $1; } + ; + +port + : /*NOTHING*/ { pp_port = IPSEC_PORT_ANY; } + | PORT { pp_port = $1; } + | PORTANY { pp_port = IPSEC_PORT_ANY; } + ; + +upper_spec + : DECSTRING { p_upper = $1; } + | UP_PROTO { p_upper = $1; } + | ANY { p_upper = IPSEC_ULPROTO_ANY; } + | STRING + { + struct protoent *ent; + + ent = getprotobyname($1.buf); + if (ent) + p_upper = ent->p_proto; + else { + if (strcmp("icmp6", $1.buf) == 0) { + p_upper = IPPROTO_ICMPV6; + } else if(strcmp("ip4", $1.buf) == 0) { + p_upper = IPPROTO_IPV4; + } else { + yyerror("invalid upper layer protocol"); + free($1.buf); + return -1; + } + } + free($1.buf); + } + ; + +policy_spec + : F_POLICY policy_requests + { + p_policy = ipsec_set_policy($2.buf, $2.len); + if (p_policy == NULL) { + free($2.buf); + p_policy = NULL; + yyerror(ipsec_strerror()); + return -1; + } + + p_policy_len = ipsec_get_policylen(p_policy); + + free($2.buf); + } + ; + +policy_requests + : PL_REQUESTS { $$ = $1; } + ; + +%% + +int +setkeymsg() +{ + struct sadb_msg m_msg; + + m_msg.sadb_msg_version = PF_KEY_V2; + m_msg.sadb_msg_type = p_type; + m_msg.sadb_msg_errno = 0; + m_msg.sadb_msg_satype = p_satype; + m_msg.sadb_msg_reserved = 0; + m_msg.sadb_msg_seq = 0; + m_msg.sadb_msg_pid = getpid(); + + m_len = sizeof(struct sadb_msg); + memcpy(m_buf, &m_msg, m_len); + + switch (p_type) { + case SADB_FLUSH: + case SADB_DUMP: + break; + + case SADB_ADD: + /* set encryption algorithm, if present. */ + if (p_satype != SADB_X_SATYPE_IPCOMP && p_alg_enc != SADB_EALG_NONE) { + struct sadb_key m_key; + + m_key.sadb_key_len = + PFKEY_UNIT64(sizeof(m_key) + + PFKEY_ALIGN8(p_key_enc_len)); + m_key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; + m_key.sadb_key_bits = p_key_enc_len * 8; + m_key.sadb_key_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_key, sizeof(m_key), + (caddr_t)p_key_enc, p_key_enc_len); + } + + /* set authentication algorithm, if present. */ + if (p_alg_auth != SADB_AALG_NONE) { + struct sadb_key m_key; + + m_key.sadb_key_len = + PFKEY_UNIT64(sizeof(m_key) + + PFKEY_ALIGN8(p_key_auth_len)); + m_key.sadb_key_exttype = SADB_EXT_KEY_AUTH; + m_key.sadb_key_bits = p_key_auth_len * 8; + m_key.sadb_key_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_key, sizeof(m_key), + (caddr_t)p_key_auth, p_key_auth_len); + } + + /* set lifetime for HARD */ + if (p_lt_hard != 0) { + struct sadb_lifetime m_lt; + u_int len = sizeof(struct sadb_lifetime); + + m_lt.sadb_lifetime_len = PFKEY_UNIT64(len); + m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; + m_lt.sadb_lifetime_allocations = 0; + m_lt.sadb_lifetime_bytes = 0; + m_lt.sadb_lifetime_addtime = p_lt_hard; + m_lt.sadb_lifetime_usetime = 0; + + memcpy(m_buf + m_len, &m_lt, len); + m_len += len; + } + + /* set lifetime for SOFT */ + if (p_lt_soft != 0) { + struct sadb_lifetime m_lt; + u_int len = sizeof(struct sadb_lifetime); + + m_lt.sadb_lifetime_len = PFKEY_UNIT64(len); + m_lt.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; + m_lt.sadb_lifetime_allocations = 0; + m_lt.sadb_lifetime_bytes = 0; + m_lt.sadb_lifetime_addtime = p_lt_soft; + m_lt.sadb_lifetime_usetime = 0; + + memcpy(m_buf + m_len, &m_lt, len); + m_len += len; + } + /* FALLTHROUGH */ + + case SADB_DELETE: + case SADB_GET: + { + struct sadb_sa m_sa; + struct sadb_x_sa2 m_sa2; + struct sadb_address m_addr; + u_int len; + + if (p_no_spi == 0) { + len = sizeof(struct sadb_sa); + m_sa.sadb_sa_len = PFKEY_UNIT64(len); + m_sa.sadb_sa_exttype = SADB_EXT_SA; + m_sa.sadb_sa_spi = htonl(p_spi); + m_sa.sadb_sa_replay = p_replay; + m_sa.sadb_sa_state = 0; + m_sa.sadb_sa_auth = p_alg_auth; + m_sa.sadb_sa_encrypt = p_alg_enc; + m_sa.sadb_sa_flags = p_ext; + + memcpy(m_buf + m_len, &m_sa, len); + m_len += len; + + len = sizeof(struct sadb_x_sa2); + m_sa2.sadb_x_sa2_len = PFKEY_UNIT64(len); + m_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2; + m_sa2.sadb_x_sa2_mode = p_mode; + m_sa2.sadb_x_sa2_reqid = p_reqid; + + memcpy(m_buf + m_len, &m_sa2, len); + m_len += len; + } + + /* set src */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_src->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + switch (p_src->sa_family) { + case AF_INET: + m_addr.sadb_address_prefixlen = + sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + m_addr.sadb_address_prefixlen = + sizeof(struct in6_addr) << 3; + break; +#endif + default: + yyerror("unsupported address family"); + exit(1); /*XXX*/ + } + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_src, p_src->sa_len); + + /* set dst */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_dst->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + m_addr.sadb_address_proto = IPSEC_ULPROTO_ANY; + switch (p_dst->sa_family) { + case AF_INET: + m_addr.sadb_address_prefixlen = + sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + m_addr.sadb_address_prefixlen = + sizeof(struct in6_addr) << 3; + break; +#endif + default: + yyerror("unsupported address family"); + exit(1); /*XXX*/ + } + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_dst, p_dst->sa_len); + } + break; + + /* for SPD management */ + case SADB_X_SPDFLUSH: + case SADB_X_SPDDUMP: + break; + + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + { + struct sadb_address m_addr; + u_int8_t plen; + + memcpy(m_buf + m_len, p_policy, p_policy_len); + m_len += p_policy_len; + free(p_policy); + p_policy = NULL; + + /* set src */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_src->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + m_addr.sadb_address_proto = p_upper; + switch (p_src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + yyerror("unsupported address family"); + exit(1); /*XXX*/ + } + m_addr.sadb_address_prefixlen = + (p_prefs != ~0 ? p_prefs : plen); + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_src, p_src->sa_len); + + /* set dst */ + m_addr.sadb_address_len = + PFKEY_UNIT64(sizeof(m_addr) + + PFKEY_ALIGN8(p_dst->sa_len)); + m_addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST; + m_addr.sadb_address_proto = p_upper; + switch (p_dst->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; +#ifdef INET6 + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; +#endif + default: + yyerror("unsupported address family"); + exit(1); /*XXX*/ + } + m_addr.sadb_address_prefixlen = + (p_prefd != ~0 ? p_prefd : plen); + m_addr.sadb_address_reserved = 0; + + setvarbuf(&m_len, + (struct sadb_ext *)&m_addr, sizeof(m_addr), + (caddr_t)p_dst, p_dst->sa_len); + } + break; + } + + ((struct sadb_msg *)m_buf)->sadb_msg_len = PFKEY_UNIT64(m_len); + + return 0; +} + +static struct addrinfo * +parse_addr(host, port, flag) + char *host; + char *port; + int flag; +{ + struct addrinfo hints, *res = NULL; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = flag; + error = getaddrinfo(host, port, &hints, &res); + if (error != 0) { + yyerror(gai_strerror(error)); + return NULL; + } + if (res->ai_next != NULL) { + yyerror(gai_strerror(error)); + } + return res; +} + +static int +setvarbuf(off, ebuf, elen, vbuf, vlen) + caddr_t vbuf; + struct sadb_ext *ebuf; + int *off, elen, vlen; +{ + memset(m_buf + *off, 0, PFKEY_UNUNIT64(ebuf->sadb_ext_len)); + memcpy(m_buf + *off, (caddr_t)ebuf, elen); + memcpy(m_buf + *off + elen, vbuf, vlen); + (*off) += PFKEY_ALIGN8(elen + vlen); + + return 0; +} + +void +parse_init() +{ + p_type = 0; + p_spi = 0; + p_no_spi = 0; + + p_src = 0, p_dst = 0; + pp_prefix = p_prefs = p_prefd = ~0; + pp_port = IPSEC_PORT_ANY; + p_upper = 0; + + p_satype = 0; + p_ext = SADB_X_EXT_CYCSEQ; + p_alg_enc = SADB_EALG_NONE; + p_alg_auth = SADB_AALG_NONE; + p_mode = IPSEC_MODE_ANY; + p_reqid = 0; + p_replay = 0; + p_key_enc_len = p_key_auth_len = 0; + p_key_enc = p_key_auth = 0; + p_lt_hard = p_lt_soft = 0; + + p_policy_len = 0; + p_policy = NULL; + + memset(cmdarg, 0, sizeof(cmdarg)); + + return; +} + +void +free_buffer() +{ + if (p_src) free(p_src); + if (p_dst) free(p_dst); + if (p_key_enc) free(p_key_enc); + if (p_key_auth) free(p_key_auth); + + return; +} + diff --git a/setkey.tproj/pfkey.c b/setkey.tproj/pfkey.c new file mode 100644 index 0000000..813b304 --- /dev/null +++ b/setkey.tproj/pfkey.c @@ -0,0 +1,2108 @@ +/* $FreeBSD: src/lib/libipsec/pfkey.c,v 1.1.2.2 2001/07/03 11:01:14 ume Exp $ */ +/* $KAME: pfkey.c,v 1.39 2001/03/05 18:22:17 thorpej Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +#define CALLOC(size, cast) (cast)calloc(1, (size)) + +static int findsupportedmap __P((int)); +static int setsupportedmap __P((struct sadb_supported *)); +static struct sadb_alg *findsupportedalg __P((u_int, u_int)); +static int pfkey_send_x1 __P((int, u_int, u_int, u_int, struct sockaddr *, + struct sockaddr *, u_int32_t, u_int32_t, u_int, caddr_t, + u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static int pfkey_send_x2 __P((int, u_int, u_int, u_int, + struct sockaddr *, struct sockaddr *, u_int32_t)); +static int pfkey_send_x3 __P((int, u_int, u_int)); +static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int, + struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t, + char *, int, u_int32_t)); +static int pfkey_send_x5 __P((int, u_int, u_int32_t)); + +static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int, + u_int, u_int32_t, pid_t)); +static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int, + u_int, u_int, u_int32_t)); +static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int, + struct sockaddr *, u_int, u_int)); +static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int)); +static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t)); +static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t)); + +/* + * make and search supported algorithm structure. + */ +static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL, }; + +static int supported_map[] = { + SADB_SATYPE_AH, + SADB_SATYPE_ESP, + SADB_X_SATYPE_IPCOMP, +}; + +static int +findsupportedmap(satype) + int satype; +{ + int i; + + for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++) + if (supported_map[i] == satype) + return i; + return -1; +} + +static struct sadb_alg * +findsupportedalg(satype, alg_id) + u_int satype, alg_id; +{ + int algno; + int tlen; + caddr_t p; + + /* validity check */ + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return NULL; + } + if (ipsec_supported[algno] == NULL) { + __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST; + return NULL; + } + + tlen = ipsec_supported[algno]->sadb_supported_len + - sizeof(struct sadb_supported); + p = (caddr_t)(ipsec_supported[algno] + 1); + while (tlen > 0) { + if (tlen < sizeof(struct sadb_alg)) { + /* invalid format */ + break; + } + if (((struct sadb_alg *)p)->sadb_alg_id == alg_id) + return (struct sadb_alg *)p; + + tlen -= sizeof(struct sadb_alg); + p += sizeof(struct sadb_alg); + } + + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return NULL; +} + +static int +setsupportedmap(sup) + struct sadb_supported *sup; +{ + struct sadb_supported **ipsup; + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)]; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)]; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + if (*ipsup) + free(*ipsup); + + *ipsup = malloc(sup->sadb_supported_len); + if (!*ipsup) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + memcpy(*ipsup, sup, sup->sadb_supported_len); + + return 0; +} + +/* + * check key length against algorithm specified. + * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the + * augument, and only calls to ipsec_check_keylen2(); + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen(supported, alg_id, keylen) + u_int supported; + u_int alg_id; + u_int keylen; +{ + int satype; + + /* validity check */ + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + return ipsec_check_keylen2(satype, alg_id, keylen); +} + +/* + * check key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_check_keylen2(satype, alg_id, keylen) + u_int satype; + u_int alg_id; + u_int keylen; +{ + struct sadb_alg *alg; + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) { + __ipsec_errcode = EIPSEC_INVAL_KEYLEN; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * get max/min key length against algorithm specified. + * satype is one of satype defined at pfkeyv2.h. + * keylen is the unit of bit. + * OUT: + * -1: invalid. + * 0: valid. + */ +int +ipsec_get_keylen(supported, alg_id, alg0) + u_int supported, alg_id; + struct sadb_alg *alg0; +{ + struct sadb_alg *alg; + u_int satype; + + /* validity check */ + if (!alg0) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + switch (supported) { + case SADB_EXT_SUPPORTED_AUTH: + satype = SADB_SATYPE_AH; + break; + case SADB_EXT_SUPPORTED_ENCRYPT: + satype = SADB_SATYPE_ESP; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + alg = findsupportedalg(satype, alg_id); + if (!alg) + return -1; + + memcpy(alg0, alg, sizeof(*alg0)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set the rate for SOFT lifetime against HARD one. + * If rate is more than 100 or equal to zero, then set to 100. + */ +static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; + +u_int +pfkey_set_softrate(type, rate) + u_int type, rate; +{ + __ipsec_errcode = EIPSEC_NO_ERROR; + + if (rate > 100 || rate == 0) + rate = 100; + + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + soft_lifetime_allocations_rate = rate; + return 0; + case SADB_X_LIFETIME_BYTES: + soft_lifetime_bytes_rate = rate; + return 0; + case SADB_X_LIFETIME_ADDTIME: + soft_lifetime_addtime_rate = rate; + return 0; + case SADB_X_LIFETIME_USETIME: + soft_lifetime_usetime_rate = rate; + return 0; + } + + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return 1; +} + +/* + * get current rate for SOFT lifetime against HARD one. + * ATTENTION: ~0 is returned if invalid type was passed. + */ +u_int +pfkey_get_softrate(type) + u_int type; +{ + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + return soft_lifetime_allocations_rate; + case SADB_X_LIFETIME_BYTES: + return soft_lifetime_bytes_rate; + case SADB_X_LIFETIME_ADDTIME: + return soft_lifetime_addtime_rate; + case SADB_X_LIFETIME_USETIME: + return soft_lifetime_usetime_rate; + } + + return ~0; +} + +/* + * sending SADB_GETSPI message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t min, max, reqid, seq; +{ + struct sadb_msg *newmsg; + caddr_t ep; + int len; + int need_spirange = 0; + caddr_t p; + int plen; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (min > max || (min > 0 && min <= 255)) { + __ipsec_errcode = EIPSEC_INVAL_SPI; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if (min > 255 && max < ~0) { + need_spirange++; + len += sizeof(struct sadb_spirange); + } + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_GETSPI, + len, satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for source */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* set sadb_address for destination */ + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + /* proccessing spi range */ + if (need_spirange) { + struct sadb_spirange spirange; + + if (p + sizeof(spirange) > ep) { + free(newmsg); + return -1; + } + + memset(&spirange, 0, sizeof(spirange)); + spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange)); + spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE; + spirange.sadb_spirange_min = min; + spirange.sadb_spirange_max = max; + + memcpy(p, &spirange, sizeof(spirange)); + + p += sizeof(spirange); + } + if (p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_UPDATE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_ADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_delete(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE without spi to the kernel. This is + * the "delete all" request (an extension also present in + * Solaris). + * + * OUT: + * positive: success and return length sent + * -1 : error occured, and set errno + */ +int +pfkey_send_delete_all(so, satype, mode, src, dst) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_DELETE, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_GET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_get(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_REGISTER message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_register(so, satype) + int so; + u_int satype; +{ + int len, algno; + + if (satype == PF_UNSPEC) { + for (algno = 0; + algno < sizeof(supported_map)/sizeof(supported_map[0]); + algno++) { + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + } else { + algno = findsupportedmap(satype); + if (algno == -1) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if (ipsec_supported[algno]) { + free(ipsec_supported[algno]); + ipsec_supported[algno] = NULL; + } + } + + if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) + return -1; + + return len; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_recv_register(so) + int so; +{ + pid_t pid = getpid(); + struct sadb_msg *newmsg; + int error = -1; + + /* receive message */ + do { + if ((newmsg = pfkey_recv(so)) == NULL) + return -1; + } while (newmsg->sadb_msg_type != SADB_REGISTER + || newmsg->sadb_msg_pid != pid); + + /* check and fix */ + newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); + + error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len); + free(newmsg); + + if (error == 0) + __ipsec_errcode = EIPSEC_NO_ERROR; + + return error; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * NOTE: sadb_msg_len must be host order. + * IN: + * tlen: msg length, it's to makeing sure. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_set_supported(msg, tlen) + struct sadb_msg *msg; + int tlen; +{ + struct sadb_supported *sup; + caddr_t p; + caddr_t ep; + + /* validity */ + if (msg->sadb_msg_len != tlen) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + p = (caddr_t)msg; + ep = p + tlen; + + p += sizeof(struct sadb_msg); + + while (p < ep) { + sup = (struct sadb_supported *)p; + if (ep < p + sizeof(*sup) || + PFKEY_EXTLEN(sup) < sizeof(*sup) || + ep < p + sup->sadb_supported_len) { + /* invalid format */ + break; + } + + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* fixed length */ + sup->sadb_supported_len = PFKEY_EXTLEN(sup); + + /* set supported map */ + if (setsupportedmap(sup) != 0) + return -1; + + p += sup->sadb_supported_len; + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + + return 0; +} + +/* + * sending SADB_FLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_flush(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_dump(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_PROMISC message to the kernel. + * NOTE that this function handles promisc mode toggle only. + * IN: + * flag: set promisc off if zero, set promisc on if non-zero. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + * 0 : error occured, and set errno. + * others: a pointer to new allocated buffer in which supported + * algorithms is. + */ +int +pfkey_send_promisc_toggle(so, flag) + int so; + int flag; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDADD, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDUPDATE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdupdate2(so, src, prefs, dst, prefd, proto, ltime, vtime, + policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int64_t ltime, vtime; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE, + src, prefs, dst, prefd, proto, + ltime, vtime, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete2(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDGET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdget(so, spid) + int so; + u_int32_t spid; +{ + int len; + + if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDSETIDX message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdsetidx(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + caddr_t policy; + int policylen; + u_int32_t seq; +{ + int len; + + if (policylen != sizeof(struct sadb_x_policy)) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX, + src, prefs, dst, prefd, proto, + 0, 0, + policy, policylen, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDFLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdflush(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDDUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddump(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* sending SADB_ADD or SADB_UPDATE message to the kernel */ +static int +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + u_int wsize; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + switch (satype) { + case SADB_SATYPE_ESP: + if (e_type == SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_SATYPE_AH: + if (e_type != SADB_EALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type == SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_X_SATYPE_IPCOMP: + if (e_type == SADB_X_CALG_NONE) { + __ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type != SADB_AALG_NONE) { + __ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_x_sa2) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime); + + if (e_type != SADB_EALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); + if (a_type != SADB_AALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + satype, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, wsize, a_type, e_type, flags); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbxsa2(p, ep, mode, reqid); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + + if (e_type != SADB_EALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT, + keymat, e_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + if (a_type != SADB_AALG_NONE) { + p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH, + keymat + e_keylen, a_keylen); + if (!p) { + free(newmsg); + return -1; + } + } + + /* set sadb_lifetime for destination */ + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT, + l_alloc, l_bytes, l_addtime, l_usetime); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_DELETE or SADB_GET message to the kernel */ +static int +pfkey_send_x2(so, type, satype, mode, src, dst, spi) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, plen, + IPSEC_ULPROTO_ANY); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, plen, + IPSEC_ULPROTO_ANY); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message + * to the kernel + */ +static int +pfkey_send_x3(so, type, satype) + int so; + u_int type, satype; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + caddr_t ep; + + /* validity check */ + switch (type) { + case SADB_X_PROMISC: + if (satype != 0 && satype != 1) { + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + default: + switch (satype) { + case SADB_SATYPE_UNSPEC: + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, satype, 0, + getpid()); + if (!p || p != ep) { + free(newmsg); + return -1; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDADD message to the kernel */ +static int +pfkey_send_x4(so, type, src, prefs, dst, prefd, proto, + ltime, vtime, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int type, prefs, prefd, proto; + u_int64_t ltime, vtime; + char *policy; + int policylen; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + int plen; + caddr_t ep; + + /* validity check */ + if (src == NULL || dst == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (src->sa_family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + if (prefs > plen || prefd > plen) { + __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_lifetime) + + policylen; + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, seq, getpid()); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto); + if (!p) { + free(newmsg); + return -1; + } + p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD, + 0, 0, ltime, vtime); + if (!p || p + policylen != ep) { + free(newmsg); + return -1; + } + memcpy(p, policy, policylen); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */ +static int +pfkey_send_x5(so, type, spid) + int so; + u_int type; + u_int32_t spid; +{ + struct sadb_msg *newmsg; + struct sadb_x_policy xpl; + int len; + caddr_t p; + caddr_t ep; + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(xpl); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + ep = ((caddr_t)newmsg) + len; + + p = pfkey_setsadbmsg((caddr_t)newmsg, ep, type, len, + SADB_SATYPE_UNSPEC, 0, getpid()); + if (!p) { + free(newmsg); + return -1; + } + + if (p + sizeof(xpl) != ep) { + free(newmsg); + return -1; + } + memset(&xpl, 0, sizeof(xpl)); + xpl.sadb_x_policy_len = PFKEY_UNUNIT64(sizeof(xpl)); + xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY; + xpl.sadb_x_policy_id = spid; + memcpy(p, &xpl, sizeof(xpl)); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * open a socket. + * OUT: + * -1: fail. + * others : success and return value of socket. + */ +int +pfkey_open() +{ + int so; + const int bufsiz = 128 * 1024; /*is 128K enough?*/ + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + /* + * This is a temporary workaround for KAME PR 154. + * Don't really care even if it fails. + */ + (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); + (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return so; +} + +/* + * close a socket. + * OUT: + * 0: success. + * -1: fail. + */ +void +pfkey_close(so) + int so; +{ + (void)close(so); + + __ipsec_errcode = EIPSEC_NO_ERROR; + return; +} + +/* + * receive sadb_msg data, and return pointer to new buffer allocated. + * Must free this buffer later. + * OUT: + * NULL : error occured. + * others : a pointer to sadb_msg structure. + * + * XXX should be rewritten to pass length explicitly + */ +struct sadb_msg * +pfkey_recv(so) + int so; +{ + struct sadb_msg buf, *newmsg; + int len, reallen; + + while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + if (len < sizeof(buf)) { + recv(so, (caddr_t)&buf, sizeof(buf), 0); + __ipsec_errcode = EIPSEC_MAX; + return NULL; + } + + /* read real message */ + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { + __ipsec_set_strerror(strerror(errno)); + return NULL; + } + + while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { + if (errno == EINTR) + continue; + __ipsec_set_strerror(strerror(errno)); + free(newmsg); + return NULL; + } + + if (len != reallen) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + /* don't trust what the kernel says, validate! */ + if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) { + __ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return newmsg; +} + +/* + * send message to a socket. + * OUT: + * others: success and return length sent. + * -1 : fail. + */ +int +pfkey_send(so, msg, len) + int so; + struct sadb_msg *msg; + int len; +{ + if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { + __ipsec_set_strerror(strerror(errno)); + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * %%% Utilities + * NOTE: These functions are derived from netkey/key.c in KAME. + */ +/* + * set the pointer to each header in this message buffer. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * caddr_t mhp[SADB_EXT_MAX + 1]; + * OUT: -1: invalid. + * 0: valid. + * + * XXX should be rewritten to obtain length explicitly + */ +int +pfkey_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; +{ + struct sadb_ext *ext; + int i; + caddr_t p; + caddr_t ep; /* XXX should be passed from upper layer */ + + /* validity check */ + if (msg == NULL || mhp == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + /* initialize */ + for (i = 0; i < SADB_EXT_MAX + 1; i++) + mhp[i] = NULL; + + mhp[0] = (caddr_t)msg; + + /* initialize */ + p = (caddr_t) msg; + ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len); + + /* skip base header */ + p += sizeof(struct sadb_msg); + + while (p < ep) { + ext = (struct sadb_ext *)p; + if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) || + ep < p + PFKEY_EXTLEN(ext)) { + /* invalid format */ + break; + } + + /* duplicate check */ + /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/ + if (mhp[ext->sadb_ext_type] != NULL) { + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + /* set pointer */ + switch (ext->sadb_ext_type) { + case SADB_EXT_SA: + case SADB_EXT_LIFETIME_CURRENT: + case SADB_EXT_LIFETIME_HARD: + case SADB_EXT_LIFETIME_SOFT: + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_EXT_KEY_AUTH: + /* XXX should to be check weak keys. */ + case SADB_EXT_KEY_ENCRYPT: + /* XXX should to be check weak keys. */ + case SADB_EXT_IDENTITY_SRC: + case SADB_EXT_IDENTITY_DST: + case SADB_EXT_SENSITIVITY: + case SADB_EXT_PROPOSAL: + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + case SADB_EXT_SPIRANGE: + case SADB_X_EXT_POLICY: + case SADB_X_EXT_SA2: + mhp[ext->sadb_ext_type] = (caddr_t)ext; + break; + default: + __ipsec_errcode = EIPSEC_INVAL_EXTTYPE; + return -1; + } + + p += PFKEY_EXTLEN(ext); + } + + if (p != ep) { + __ipsec_errcode = EIPSEC_INVAL_SADBMSG; + return -1; + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * check basic usage for sadb_msg, + * NOTE: This routine is derived from netkey/key.c in KAME. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * + * caddr_t mhp[SADB_EXT_MAX + 1]; + * + * OUT: -1: invalid. + * 0: valid. + */ +int +pfkey_check(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + + /* validity check */ + if (mhp == NULL || mhp[0] == NULL) { + __ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + msg = (struct sadb_msg *)mhp[0]; + + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + __ipsec_errcode = EIPSEC_INVAL_VERSION; + return -1; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + __ipsec_errcode = EIPSEC_INVAL_MSGTYPE; + return -1; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_ESP: + case SADB_SATYPE_AH: + case SADB_X_SATYPE_IPCOMP: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + __ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return -1; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + __ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* check field of upper layer protocol and address family */ + if (mhp[SADB_EXT_ADDRESS_SRC] != NULL + && mhp[SADB_EXT_ADDRESS_DST] != NULL) { + struct sadb_address *src0, *dst0; + + src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); + dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); + + if (src0->sadb_address_proto != dst0->sadb_address_proto) { + __ipsec_errcode = EIPSEC_PROTO_MISMATCH; + return -1; + } + + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { + __ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: + __ipsec_errcode = EIPSEC_INVAL_FAMILY; + return -1; + } + + /* + * prefixlen == 0 is valid because there must be the case + * all addresses are matched. + */ + } + + __ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbmsg(buf, lim, type, tlen, satype, seq, pid) + caddr_t buf; + caddr_t lim; + u_int type, satype; + u_int tlen; + u_int32_t seq; + pid_t pid; +{ + struct sadb_msg *p; + u_int len; + + p = (struct sadb_msg *)buf; + len = sizeof(struct sadb_msg); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_reserved = 0; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + + return(buf + len); +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbsa(buf, lim, spi, wsize, auth, enc, flags) + caddr_t buf; + caddr_t lim; + u_int32_t spi, flags; + u_int wsize, auth, enc; +{ + struct sadb_sa *p; + u_int len; + + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = spi; + p->sadb_sa_replay = wsize; + p->sadb_sa_state = SADB_SASTATE_LARVAL; + p->sadb_sa_auth = auth; + p->sadb_sa_encrypt = enc; + p->sadb_sa_flags = flags; + + return(buf + len); +} + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + * prefixlen is in bits. + */ +static caddr_t +pfkey_setsadbaddr(buf, lim, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + caddr_t lim; + u_int exttype; + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + struct sadb_address *p; + u_int len; + + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype & 0xffff; + p->sadb_address_proto = ul_proto & 0xff; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + memcpy(p + 1, saddr, saddr->sa_len); + + return(buf + len); +} + +/* + * set sadb_key structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadbkey(buf, lim, type, key, keylen) + caddr_t buf; + caddr_t lim; + caddr_t key; + u_int type, keylen; +{ + struct sadb_key *p; + u_int len; + + p = (struct sadb_key *)buf; + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_key_len = PFKEY_UNIT64(len); + p->sadb_key_exttype = type; + p->sadb_key_bits = keylen << 3; + p->sadb_key_reserved = 0; + + memcpy(p + 1, key, keylen); + + return buf + len; +} + +/* + * set sadb_lifetime structure after clearing buffer with zero. + * OUT: the pointer of buf + len. + */ +static caddr_t +pfkey_setsadblifetime(buf, lim, type, l_alloc, l_bytes, l_addtime, l_usetime) + caddr_t buf; + caddr_t lim; + u_int type; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; +{ + struct sadb_lifetime *p; + u_int len; + + p = (struct sadb_lifetime *)buf; + len = sizeof(struct sadb_lifetime); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_lifetime_len = PFKEY_UNIT64(len); + p->sadb_lifetime_exttype = type; + + switch (type) { + case SADB_EXT_LIFETIME_SOFT: + p->sadb_lifetime_allocations + = (l_alloc * soft_lifetime_allocations_rate) /100; + p->sadb_lifetime_bytes + = (l_bytes * soft_lifetime_bytes_rate) /100; + p->sadb_lifetime_addtime + = (l_addtime * soft_lifetime_addtime_rate) /100; + p->sadb_lifetime_usetime + = (l_usetime * soft_lifetime_usetime_rate) /100; + break; + case SADB_EXT_LIFETIME_HARD: + p->sadb_lifetime_allocations = l_alloc; + p->sadb_lifetime_bytes = l_bytes; + p->sadb_lifetime_addtime = l_addtime; + p->sadb_lifetime_usetime = l_usetime; + break; + } + + return buf + len; +} + +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbxsa2(buf, lim, mode0, reqid) + caddr_t buf; + caddr_t lim; + u_int32_t mode0; + u_int32_t reqid; +{ + struct sadb_x_sa2 *p; + u_int8_t mode = mode0 & 0xff; + u_int len; + + p = (struct sadb_x_sa2 *)buf; + len = sizeof(struct sadb_x_sa2); + + if (buf + len > lim) + return NULL; + + memset(p, 0, len); + p->sadb_x_sa2_len = PFKEY_UNIT64(len); + p->sadb_x_sa2_exttype = SADB_X_EXT_SA2; + p->sadb_x_sa2_mode = mode; + p->sadb_x_sa2_reqid = reqid; + + return(buf + len); +} diff --git a/setkey.tproj/pfkey_dump.c b/setkey.tproj/pfkey_dump.c new file mode 100644 index 0000000..485ed46 --- /dev/null +++ b/setkey.tproj/pfkey_dump.c @@ -0,0 +1,596 @@ +/* $FreeBSD: src/lib/libipsec/pfkey_dump.c,v 1.1.2.2 2001/07/03 11:01:15 ume Exp $ */ +/* $KAME: pfkey_dump.c,v 1.27 2001/03/12 09:03:38 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ipsec_strerror.h" +#include "libpfkey.h" + +/* cope with old kame headers - ugly */ +#ifndef SADB_X_AALG_MD5 +#define SADB_X_AALG_MD5 SADB_AALG_MD5 +#endif +#ifndef SADB_X_AALG_SHA +#define SADB_X_AALG_SHA SADB_AALG_SHA +#endif +#ifndef SADB_X_AALG_NULL +#define SADB_X_AALG_NULL SADB_AALG_NULL +#endif + +#ifndef SADB_X_EALG_BLOWFISHCBC +#define SADB_X_EALG_BLOWFISHCBC SADB_EALG_BLOWFISHCBC +#endif +#ifndef SADB_X_EALG_CAST128CBC +#define SADB_X_EALG_CAST128CBC SADB_EALG_CAST128CBC +#endif +#ifndef SADB_X_EALG_RC5CBC +#ifdef SADB_EALG_RC5CBC +#define SADB_X_EALG_RC5CBC SADB_EALG_RC5CBC +#endif +#endif + +#define GETMSGSTR(str, num) \ +do { \ + if (sizeof((str)[0]) == 0 \ + || num >= sizeof(str)/sizeof((str)[0])) \ + printf("%d ", (num)); \ + else if (strlen((str)[(num)]) == 0) \ + printf("%d ", (num)); \ + else \ + printf("%s ", (str)[(num)]); \ +} while (0) + +#define GETMSGV2S(v2s, num) \ +do { \ + struct val2str *p; \ + for (p = (v2s); p && p->str; p++) { \ + if (p->val == (num)) \ + break; \ + } \ + if (p && p->str) \ + printf("%s ", p->str); \ + else \ + printf("%d ", (num)); \ +} while (0) + +static char *str_ipaddr __P((struct sockaddr *)); +static char *str_prefport __P((u_int, u_int, u_int)); +static char *str_time __P((time_t)); +static void str_lifetime_byte __P((struct sadb_lifetime *, char *)); + +struct val2str { + int val; + const char *str; +}; + +/* + * Must to be re-written about following strings. + */ +static char *str_satype[] = { + "unspec", + "unknown", + "ah", + "esp", + "unknown", + "rsvp", + "ospfv2", + "ripv2", + "mip", + "ipcomp", +}; + +static char *str_mode[] = { + "any", + "transport", + "tunnel", +}; + +static char *str_upper[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + "", "tcp", "", "egp", "", +/*10*/ "", "", "", "", "", + "", "", "udp", "", "", +/*20*/ "", "", "idp", "", "", + "", "", "", "", "tp", +/*30*/ "", "", "", "", "", + "", "", "", "", "", +/*40*/ "", "ip6", "", "rt6", "frag6", + "", "rsvp", "gre", "", "", +/*50*/ "esp", "ah", "", "", "", + "", "", "", "icmp6", "none", +/*60*/ "dst6", +}; + +static char *str_state[] = { + "larval", + "mature", + "dying", + "dead", +}; + +static struct val2str str_alg_auth[] = { + { SADB_AALG_NONE, "none", }, + { SADB_AALG_MD5HMAC, "hmac-md5", }, + { SADB_AALG_SHA1HMAC, "hmac-sha1", }, + { SADB_X_AALG_MD5, "md5", }, + { SADB_X_AALG_SHA, "sha", }, + { SADB_X_AALG_NULL, "null", }, +#ifdef SADB_X_AALG_SHA2_256 + { SADB_X_AALG_SHA2_256, "hmac-sha2-256", }, +#endif +#ifdef SADB_X_AALG_SHA2_384 + { SADB_X_AALG_SHA2_384, "hmac-sha2-384", }, +#endif +#ifdef SADB_X_AALG_SHA2_512 + { SADB_X_AALG_SHA2_512, "hmac-sha2-512", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_enc[] = { + { SADB_EALG_NONE, "none", }, + { SADB_EALG_DESCBC, "des-cbc", }, + { SADB_EALG_3DESCBC, "3des-cbc", }, + { SADB_EALG_NULL, "null", }, +#ifdef SADB_X_EALG_RC5CBC + { SADB_X_EALG_RC5CBC, "rc5-cbc", }, +#endif + { SADB_X_EALG_CAST128CBC, "cast128-cbc", }, + { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", }, +#ifdef SADB_X_EALG_RIJNDAELCBC + { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", }, +#endif +#ifdef SADB_X_EALG_TWOFISHCBC + { SADB_X_EALG_TWOFISHCBC, "twofish-cbc", }, +#endif + { -1, NULL, }, +}; + +static struct val2str str_alg_comp[] = { + { SADB_X_CALG_NONE, "none", }, + { SADB_X_CALG_OUI, "oui", }, + { SADB_X_CALG_DEFLATE, "deflate", }, + { SADB_X_CALG_LZS, "lzs", }, + { -1, NULL, }, +}; + +/* + * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). + */ +void +pfkey_sadump(m) + struct sadb_msg *m; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_sa *m_sa; + struct sadb_x_sa2 *m_sa2; + struct sadb_lifetime *m_lftc, *m_lfth, *m_lfts; + struct sadb_address *m_saddr, *m_daddr, *m_paddr; + struct sadb_key *m_auth, *m_enc; + struct sadb_ident *m_sid, *m_did; + struct sadb_sens *m_sens; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_sa = (struct sadb_sa *)mhp[SADB_EXT_SA]; + m_sa2 = (struct sadb_x_sa2 *)mhp[SADB_X_EXT_SA2]; + m_lftc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; + m_lfth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + m_lfts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + m_paddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_PROXY]; + m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; + m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; + m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; + m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; + m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY]; + + /* source address */ + if (m_saddr == NULL) { + printf("no ADDRESS_SRC extension.\n"); + return; + } + printf("%s ", str_ipaddr((struct sockaddr *)(m_saddr + 1))); + + /* destination address */ + if (m_daddr == NULL) { + printf("no ADDRESS_DST extension.\n"); + return; + } + printf("%s ", str_ipaddr((struct sockaddr *)(m_daddr + 1))); + + /* SA type */ + if (m_sa == NULL) { + printf("no SA extension.\n"); + return; + } + if (m_sa2 == NULL) { + printf("no SA2 extension.\n"); + return; + } + printf("\n\t"); + + GETMSGSTR(str_satype, m->sadb_msg_satype); + + printf("mode="); + GETMSGSTR(str_mode, m_sa2->sadb_x_sa2_mode); + + printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)ntohl(m_sa->sadb_sa_spi), + (u_int32_t)m_sa2->sadb_x_sa2_reqid, + (u_int32_t)m_sa2->sadb_x_sa2_reqid); + + /* encryption key */ + if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { + printf("\tC: "); + GETMSGV2S(str_alg_comp, m_sa->sadb_sa_encrypt); + } else if (m->sadb_msg_satype == SADB_SATYPE_ESP) { + if (m_enc != NULL) { + printf("\tE: "); + GETMSGV2S(str_alg_enc, m_sa->sadb_sa_encrypt); + ipsec_hexdump((caddr_t)m_enc + sizeof(*m_enc), + m_enc->sadb_key_bits / 8); + printf("\n"); + } + } + + /* authentication key */ + if (m_auth != NULL) { + printf("\tA: "); + GETMSGV2S(str_alg_auth, m_sa->sadb_sa_auth); + ipsec_hexdump((caddr_t)m_auth + sizeof(*m_auth), + m_auth->sadb_key_bits / 8); + printf("\n"); + } + + /* replay windoe size & flags */ + printf("\treplay=%u flags=0x%08x ", + m_sa->sadb_sa_replay, + m_sa->sadb_sa_flags); + + /* state */ + printf("state="); + GETMSGSTR(str_state, m_sa->sadb_sa_state); + + printf("seq=%lu pid=%lu\n", + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* lifetime */ + if (m_lftc != NULL) { + time_t tmp_time = time(0); + + printf("\tcreated: %s", + str_time(m_lftc->sadb_lifetime_addtime)); + printf("\tcurrent: %s\n", str_time(tmp_time)); + printf("\tdiff: %lu(s)", + (u_long)(m_lftc->sadb_lifetime_addtime == 0 ? + 0 : (tmp_time - m_lftc->sadb_lifetime_addtime))); + + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_addtime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_addtime)); + + printf("\tlast: %s", + str_time(m_lftc->sadb_lifetime_usetime)); + printf("\thard: %lu(s)", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_usetime)); + printf("\tsoft: %lu(s)\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_usetime)); + + str_lifetime_byte(m_lftc, "current"); + str_lifetime_byte(m_lfth, "hard"); + str_lifetime_byte(m_lfts, "soft"); + printf("\n"); + + printf("\tallocated: %lu", + (unsigned long)m_lftc->sadb_lifetime_allocations); + printf("\thard: %lu", + (u_long)(m_lfth == NULL ? + 0 : m_lfth->sadb_lifetime_allocations)); + printf("\tsoft: %lu\n", + (u_long)(m_lfts == NULL ? + 0 : m_lfts->sadb_lifetime_allocations)); + } + + /* XXX DEBUG */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +void +pfkey_spdump(m) + struct sadb_msg *m; +{ + char pbuf[NI_MAXSERV]; + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_address *m_saddr, *m_daddr; + struct sadb_x_policy *m_xpl; + struct sadb_lifetime *m_lft = NULL; + struct sockaddr *sa; + u_int16_t port; + + /* check pfkey message. */ + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + + m_saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]; + m_daddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]; + m_xpl = (struct sadb_x_policy *)mhp[SADB_X_EXT_POLICY]; + m_lft = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + + /* source address */ + if (m_saddr == NULL) { + printf("no ADDRESS_SRC extension.\n"); + return; + } + sa = (struct sockaddr *)(m_saddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_saddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } + + /* destination address */ + if (m_daddr == NULL) { + printf("no ADDRESS_DST extension.\n"); + return; + } + sa = (struct sockaddr *)(m_daddr + 1); + switch (sa->sa_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo(sa, sa->sa_len, NULL, 0, pbuf, sizeof(pbuf), + NI_NUMERICSERV) != 0) + port = 0; /*XXX*/ + else + port = atoi(pbuf); + printf("%s%s ", str_ipaddr(sa), + str_prefport(sa->sa_family, + m_daddr->sadb_address_prefixlen, port)); + break; + default: + printf("unknown-af "); + break; + } + + /* upper layer protocol */ + if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { + printf("upper layer protocol mismatched.\n"); + return; + } + if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY) + printf("any"); + else + GETMSGSTR(str_upper, m_saddr->sadb_address_proto); + + /* policy */ + { + char *d_xpl; + + if (m_xpl == NULL) { + printf("no X_POLICY extension.\n"); + return; + } + d_xpl = ipsec_dump_policy((char *)m_xpl, "\n\t"); + + /* dump SPD */ + printf("\n\t%s\n", d_xpl); + free(d_xpl); + } + + /* lifetime */ + if (m_lft) { + printf("\tlifetime:%lu validtime:%lu\n", + (u_long)m_lft->sadb_lifetime_addtime, + (u_long)m_lft->sadb_lifetime_usetime); + } + + printf("\tspid=%ld seq=%ld pid=%ld\n", + (u_long)m_xpl->sadb_x_policy_id, + (u_long)m->sadb_msg_seq, + (u_long)m->sadb_msg_pid); + + /* XXX TEST */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved); + + return; +} + +/* + * set "ipaddress" to buffer. + */ +static char * +str_ipaddr(sa) + struct sockaddr *sa; +{ + static char buf[NI_MAXHOST]; +#ifdef NI_WITHSCOPEID + const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflag = NI_NUMERICHOST; +#endif + + if (sa == NULL) + return ""; + + if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, niflag) == 0) + return buf; + return NULL; +} + +/* + * set "/prefix[port number]" to buffer. + */ +static char * +str_prefport(family, pref, port) + u_int family, pref, port; +{ + static char buf[128]; + char prefbuf[10]; + char portbuf[10]; + int plen; + + switch (family) { + case AF_INET: + plen = sizeof(struct in_addr) << 3; + break; + case AF_INET6: + plen = sizeof(struct in6_addr) << 3; + break; + default: + return "?"; + } + + if (pref == plen) + prefbuf[0] = '\0'; + else + snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); + + if (port == IPSEC_PORT_ANY) + snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); + else + snprintf(portbuf, sizeof(portbuf), "[%u]", port); + + snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); + + return buf; +} + +/* + * set "Mon Day Time Year" to buffer + */ +static char * +str_time(t) + time_t t; +{ + static char buf[128]; + + if (t == 0) { + int i = 0; + for (;i < 20;) buf[i++] = ' '; + } else { + char *t0; + t0 = ctime(&t); + memcpy(buf, t0 + 4, 20); + } + + buf[20] = '\0'; + + return(buf); +} + +static void +str_lifetime_byte(x, str) + struct sadb_lifetime *x; + char *str; +{ + double y; + char *unit; + int w; + + if (x == NULL) { + printf("\t%s: 0(bytes)", str); + return; + } + +#if 0 + if ((x->sadb_lifetime_bytes) / 1024 / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024 / 1024; + unit = "M"; + w = 1; + } else if ((x->sadb_lifetime_bytes) / 1024) { + y = (x->sadb_lifetime_bytes) * 1.0 / 1024; + unit = "K"; + w = 1; + } else { + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; + } +#else + y = (x->sadb_lifetime_bytes) * 1.0; + unit = ""; + w = 0; +#endif + printf("\t%s: %.*f(%sbytes)", str, w, y, unit); +} diff --git a/setkey.tproj/setkey.8 b/setkey.tproj/setkey.8 new file mode 100644 index 0000000..ec39ac6 --- /dev/null +++ b/setkey.tproj/setkey.8 @@ -0,0 +1,629 @@ +.\" $KAME: setkey.8,v 1.49 2001/05/18 05:49:51 sakane Exp $ +.\" $FreeBSD: src/usr.sbin/setkey/setkey.8,v 1.4.2.12 2001/08/16 15:56:32 ru Exp $ +.\" +.\" Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. +.\" +.Dd November 20, 2000 +.Dt SETKEY 8 +.Os +.\" +.Sh NAME +.Nm setkey +.Nd "manually manipulate the IPsec SA/SP database" +.\" +.Sh SYNOPSIS +.Nm +.Op Fl dv +.Fl c +.Nm +.Op Fl dv +.Fl f Ar filename +.Nm +.Op Fl adPlv +.Fl D +.Nm +.Op Fl dPv +.Fl F +.Nm +.Op Fl h +.Fl x +.\" +.Sh DESCRIPTION +.Nm +adds, updates, dumps, or flushes +Security Association Database (SAD) entries +as well as Security Policy Database (SPD) entries in the kernel. +.Pp +.Nm +takes a series of operations from the standard input +(if invoked with +.Fl c ) +or the file named +.Ar filename +(if invoked with +.Fl f Ar filename ) . +.Bl -tag -width Ds +.It Fl D +Dump the SAD entries. +If with +.Fl P , +the SPD entries are dumped. +.It Fl F +Flush the SAD entries. +If with +.Fl P , +the SPD entries are flushed. +.It Fl a +.Nm +usually does not display dead SAD entries with +.Fl D . +If with +.Fl a , +the dead SAD entries will be displayed as well. +A dead SAD entry means that +it has been expired but remains +because it is referenced by SPD entries. +.It Fl d +Enable to print debugging messages for command parser, +without talking to kernel. +It is not used usually. +.It Fl x +Loop forever and dump all the messages transmitted to +.Dv PF_KEY +socket. +.Fl xx +makes each timestamps unformatted. +.It Fl h +Add hexadecimal dump on +.Fl x +mode. +.It Fl l +Loop forever with short output on +.Fl D . +.It Fl v +Be verbose. +The program will dump messages exchanged on +.Dv PF_KEY +socket, including messages sent from other processes to the kernel. +.El +.Pp +Operations have the following grammar. +Note that lines starting with +hashmarks ('#') are treated as comment lines. +.Bl -tag -width Ds +.It Xo +.Li add +.Ar src Ar dst Ar protocol Ar spi +.Op Ar extensions +.Ar algorithm... +.Li ; +.Xc +Add an SAD entry. +.\" +.It Xo +.Li get +.Ar src Ar dst Ar protocol Ar spi +.Li ; +.Xc +Show an SAD entry. +.\" +.It Xo +.Li delete +.Ar src Ar dst Ar protocol Ar spi +.Li ; +.Xc +Remove an SAD entry. +.\" +.It Xo +.Li deleteall +.Ar src Ar dst Ar protocol +.Li ; +.Xc +Remove all SAD entries that match the specification. +.\" +.It Xo +.Li flush +.Op Ar protocol +.Li ; +.Xc +Clear all SAD entries matched by the options. +.\" +.It Xo +.Li dump +.Op Ar protocol +.Li ; +.Xc +Dumps all SAD entries matched by the options. +.\" +.It Xo +.Li spdadd +.Ar src_range Ar dst_range Ar upperspec Ar policy +.Li ; +.Xc +Add an SPD entry. +.\" +.It Xo +.Li spddelete +.Ar src_range Ar dst_range Ar upperspec Fl P Ar direction +.Li ; +.Xc +Delete an SPD entry. +.\" +.It Xo +.Li spdflush +.Li ; +.Xc +Clear all SPD entries. +.\" +.It Xo +.Li spddump +.Li ; +.Xc +Dumps all SPD entries. +.El +.\" +.Pp +Meta-arguments are as follows: +.Pp +.Bl -tag -compact -width Ds +.It Ar src +.It Ar dst +Source/destination of the secure communication is specified as +IPv4/v6 address. +.Nm +does not consult hostname-to-address for arguments +.Ar src +and +.Ar dst . +They must be in numeric form. +.\" +.Pp +.It Ar protocol +.Ar protocol +is one of following: +.Bl -tag -width Fl -compact +.It Li esp +ESP based on rfc2405 +.It Li esp-old +ESP based on rfc1827 +.It Li ah +AH based on rfc2402 +.It Li ah-old +AH based on rfc1826 +.It Li ipcomp +IPCOMP +.El +.\" +.Pp +.It Ar spi +Security Parameter Index (SPI) for the SAD and the SPD. +It must be decimal number or hexadecimal number +You cannot use the set of SPI values in the range 0 through 255. +(with +.Li 0x +attached). +.\" +.Pp +.It Ar extensions +takes some of the following: +.Bl -tag -width Fl -compact +.\" +.It Fl m Ar mode +Specify a security protocol mode for use. +.Ar mode +is one of following: +.Li transport , tunnel +or +.Li any . +The default value is +.Li any . +.\" +.It Fl r Ar size +Specify window size of bytes for replay prevention. +.Ar size +must be decimal number in 32-bit word. +If +.Ar size +is zero or not specified, replay check don't take place. +.\" +.It Fl u Ar id +Specify the identifier of the policy entry in SPD. +See +.Ar policy . +.\" +.It Fl f Ar pad_option +defines the content of the ESP padding. +.Ar pad_option +is one of following: +.Bl -tag -width random-pad -compact +.It Li zero-pad +All of the padding are zero. +.It Li random-pad +A series of randomized values are set. +.It Li seq-pad +A series of sequential increasing numbers started from 1 are set. +.El +.\" +.It Fl f Li nocyclic-seq +Don't allow cyclic sequence number. +.\" +.It Fl lh Ar time +.It Fl ls Ar time +Specify hard/soft life time duration of the SA. +.El +.\" +.Pp +.It Ar algorithm +.Bl -tag -width Fl -compact +.It Fl E Ar ealgo Ar key +Specify a encryption algorithm. +.It Fl A Ar aalgo Ar key +Specify a authentication algorithm. +If +.Fl A +is used with +.Ar protocol Li esp , +it will be treated as ESP payload authentication algorithm. +.It Fl C Ar calgo Op Fl R +Specify compression algorithm. +If +.Fl R +is not specified with +.Li ipcomp +line, the kernel will use well-known IPComp CPI +(compression parameter index) +on IPComp CPI field on packets, and +.Ar spi +field will be ignored. +.Ar spi +field is only for kernel internal use in this case. +.\"Therefore, compression protocol number will appear on IPComp CPI field. +If +.Fl R +is used, +the value on +.Ar spi +field will appear on IPComp CPI field on outgoing packets. +.Ar spi +field needs to be smaller than +.Li 0x10000 +in this case. +.El +.Pp +.Ar protocol Li esp +accepts +.Fl E +and +.Fl A . +.Ar protocol Li esp-old +accepts +.Fl E +only. +.Ar protocol Li ah +and +.Li ah-old +accept +.Fl A +only. +.Ar protocol Li ipcomp +accepts +.Fl C +only. +.Pp +.Ar key +must be double-quoted character string or series of hexadecimal digits. +.Pp +Possible values for +.Ar ealgo , +.Ar aalgo +and +.Ar calgo +are specified in separate section. +.\" +.Pp +.It Ar src_range +.It Ar dst_range +These are selections of the secure communication specified as +IPv4/v6 address or IPv4/v6 address range, and it may accompany +TCP/UDP port specification. +This takes the following form: +.Bd -literal -offset +.Ar address +.Ar address/prefixlen +.Ar address[port] +.Ar address/prefixlen[port] +.Ed +.Pp +.Ar prefixlen +and +.Ar port +must be decimal number. +The square bracket around +.Ar port +is really necessary. +They are not manpage metacharacters. +.Pp +.Nm +does not consult hostname-to-address for arguments +.Ar src +and +.Ar dst . +They must be in numeric form. +.\" +.Pp +.It Ar upperspec +Upper-layer protocol to be used. +You can use one of words in +.Pa /etc/protocols +as +.Ar upperspec . +Or +.Li icmp6 , +.Li ip4 , +and +.Li any +can be specified. +.Li any +stands for +.Dq any protocol . +Also you can use the protocol number. +.Pp +NOTE: +.Ar upperspec +does not work against forwarding case at this moment, +as it requires extra reassembly at forwarding node +(not implemented at this moment). +We have many protocols in +.Pa /etc/protocols , +but protocols except of TCP, UDP and ICMP may not be suitable to use with IPSec. +You have to consider and be careful to use them. +.Li icmp +.Li tcp +.Li udp +all protocols +.\" +.Pp +.It Ar policy +.Ar policy +is the one of following: +.Bd -literal -offset +.Xo +.Fl P +.Ar direction +.Li discard +.Xc +.Xo +.Fl P +.Ar direction +.Li none +.Xc +.Xo +.Fl P +.Ar direction +.Li ipsec +.Ar protocol/mode/src-dst/level +.Xc +.Ed +.Pp +You must specify the direction of its policy as +.Ar direction . +Either +.Li out +or +.Li in +are used. +.Li discard +means the packet matching indexes will be discarded. +.Li none +means that IPsec operation will not take place onto the packet. +.Li ipsec +means that IPsec operation will take place onto the packet. +Either +.Li ah , +.Li esp +or +.Li ipcomp +is to be set as +.Ar protocol . +.Ar mode +is either +.Li transport +or +.Li tunnel . +If +.Ar mode +is +.Li tunnel , +you must specify the end-points addresses of the SA as +.Ar src +and +.Ar dst +with +.Sq - +between these addresses which is used to specify the SA to use. +If +.Ar mode +is +.Li transport , +both +.Ar src +and +.Ar dst +can be omited. +.Ar level +is to be one of the following: +.Li default , use , require +or +.Li unique . +If the SA is not available in every level, the kernel will request +getting SA to the key exchange daemon. +.Li default +means the kernel consults to the system wide default against protocol you +specified, e.g.\& +.Li esp_trans_deflev +sysctl variable, when the kernel processes the packet. +.Li use +means that the kernel use a SA if it's available, +otherwise the kernel keeps normal operation. +.Li require +means SA is required whenever the kernel sends a packet matched +with the policy. +.Li unique +is the same to require. +In addition, it allows the policy to bind with the unique out-bound SA. +If you use the SA by manual keying, +you can put the decimal number as the policy identifier after +.Li unique +separated by colon +.Sq \: +like the following; +.Li unique:number . +.Li number +must be between 1 and 32767. +It corresponds to +.Ar extensions Fl u . +.Pp +Note that +.Dq Li discard +and +.Dq Li none +are not in the syntax described in +.Xr ipsec_set_policy 3 . +There are little differences in the syntax. +See +.Xr ipsec_set_policy 3 +for detail. +.Pp +.El +.Pp +.\" +.Sh ALGORITHMS +The following list shows the supported algorithms. +.Sy protocol +and +.Sy algorithm +are almost orthogonal. +Followings are the list of authentication algorithms that can be used as +.Ar aalgo +in +.Fl A Ar aalgo +of +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm keylen (bits) comment +hmac-md5 128 ah: rfc2403 + 128 ah-old: rfc2085 +hmac-sha1 160 ah: rfc2404 + 160 ah-old: 128bit ICV (no document) +keyed-md5 128 ah: 96bit ICV (no document) + 128 ah-old: rfc1828 +keyed-sha1 160 ah: 96bit ICV (no document) + 160 ah-old: 128bit ICV (no document) +null 0 to 2048 for debugging +hmac-sha2-256 256 ah: 96bit ICV (no document) + 256 ah-old: 128bit ICV (no document) +hmac-sha2-384 384 ah: 96bit ICV (no document) + 384 ah-old: 128bit ICV (no document) +hmac-sha2-512 512 ah: 96bit ICV (no document) + 512 ah-old: 128bit ICV (no document) +.Ed +.Pp +Followings are the list of encryption algorithms that can be used as +.Ar ealgo +in +.Fl E Ar ealgo +of +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm keylen (bits) comment +des-cbc 64 esp-old: rfc1829, esp: rfc2405 +3des-cbc 192 rfc2451 +simple 0 to 2048 rfc2410 +blowfish-cbc 40 to 448 rfc2451 +cast128-cbc 40 to 128 rfc2451 +des-deriv 64 ipsec-ciph-des-derived-01 (expired) +3des-deriv 192 no document +rijndael-cbc 128/192/256 draft-ietf-ipsec-ciph-aes-cbc-00 +.Ed +.Pp +Followings are the list of compression algorithms that can be used as +.Ar calgo +in +.Fl C Ar calgo +of +.Ar protocol +parameter: +.Pp +.Bd -literal -offset indent +algorithm comment +deflate rfc2394 +lzs rfc2395 +.Ed +.\" +.Sh EXAMPLES +.Bd -literal -offset +add 3ffe:501:4819::1 3ffe:501:481d::1 esp 123457 + -E des-cbc "ESP SA!!" ; + +add 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 + -A hmac-sha1 "AH SA configuration!" ; + +add 10.0.11.41 10.0.11.33 esp 0x10001 + -E des-cbc "ESP with" + -A hmac-md5 "authentication!!" ; + +get 3ffe:501:4819::1 3ffe:501:481d::1 ah 123456 ; + +flush ; + +dump esp ; + +spdadd 10.0.11.41/32[21] 10.0.11.33/32[any] any + -P out ipsec esp/tunnel/192.168.0.1-192.168.1.2/require ; + +.Ed +.\" +.Sh RETURN VALUES +The command exits with 0 on success, and non-zero on errors. +.\" +.Sh SEE ALSO +.Xr ipsec_set_policy 3 , +.Xr racoon 8 , +.Xr sysctl 8 +.\" +.Sh HISTORY +The +.Nm +command first appeared in WIDE Hydrangea IPv6 protocol stack kit. +The command was completely re-designed in June 1998. +.\" +.\" .Sh BUGS diff --git a/setkey.tproj/setkey.c b/setkey.tproj/setkey.c new file mode 100644 index 0000000..19ccfe3 --- /dev/null +++ b/setkey.tproj/setkey.c @@ -0,0 +1,648 @@ +/* $FreeBSD: src/usr.sbin/setkey/setkey.c,v 1.1.2.2 2001/07/03 11:02:17 ume Exp $ */ +/* $KAME: setkey.c,v 1.18 2001/05/08 04:36:39 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libpfkey.h" + +void Usage __P((void)); +int main __P((int, char **)); +int get_supported __P((void)); +void sendkeyshort __P((u_int)); +void promisc __P((void)); +int sendkeymsg __P((void)); +int postproc __P((struct sadb_msg *, int)); +const char *numstr __P((int)); +void shortdump_hdr __P((void)); +void shortdump __P((struct sadb_msg *)); +static void printdate __P((void)); +static int32_t gmt2local __P((time_t)); + +#define MODE_SCRIPT 1 +#define MODE_CMDDUMP 2 +#define MODE_CMDFLUSH 3 +#define MODE_PROMISC 4 + +int so; + +int f_forever = 0; +int f_all = 0; +int f_debug = 0; +int f_verbose = 0; +int f_mode = 0; +int f_cmddump = 0; +int f_policy = 0; +int f_hexdump = 0; +int f_tflag = 0; +char *pname; + +u_char m_buf[BUFSIZ]; +u_int m_len; + +static time_t thiszone; + +extern int lineno; + +extern int parse __P((FILE **)); + +void +Usage() +{ + printf("Usage:\t%s [-dv] -c\n", pname); + printf("\t%s [-dv] -f (file)\n", pname); + printf("\t%s [-Padlv] -D\n", pname); + printf("\t%s [-Pdv] -F\n", pname); + printf("\t%s [-h] -x\n", pname); + pfkey_close(so); + exit(1); +} + +int +main(ac, av) + int ac; + char **av; +{ + FILE *fp = stdin; + int c; + + pname = *av; + + if (ac == 1) Usage(); + + thiszone = gmt2local(0); + + while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) { + switch (c) { + case 'c': + f_mode = MODE_SCRIPT; + fp = stdin; + break; + case 'f': + f_mode = MODE_SCRIPT; + if ((fp = fopen(optarg, "r")) == NULL) { + err(-1, "fopen"); + /*NOTREACHED*/ + } + break; + case 'D': + f_mode = MODE_CMDDUMP; + break; + case 'F': + f_mode = MODE_CMDFLUSH; + break; + case 'a': + f_all = 1; + break; + case 'l': + f_forever = 1; + break; + case 'h': + f_hexdump = 1; + break; + case 'x': + f_mode = MODE_PROMISC; + f_tflag++; + break; + case 'P': + f_policy = 1; + break; + case 'd': + f_debug = 1; + break; + case 'v': + f_verbose = 1; + break; + default: + Usage(); + /*NOTREACHED*/ + } + } + + switch (f_mode) { + case MODE_CMDDUMP: + sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP); + break; + case MODE_CMDFLUSH: + sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); + pfkey_close(so); + break; + case MODE_SCRIPT: + if (get_supported() < 0) { + errx(-1, "%s", ipsec_strerror()); + /*NOTREACHED*/ + } + if (parse(&fp)) + exit (1); + break; + case MODE_PROMISC: + promisc(); + /*NOTREACHED*/ + default: + Usage(); + /*NOTREACHED*/ + } + + exit(0); +} + +int +get_supported() +{ + int so; + + if ((so = pfkey_open()) < 0) { + perror("pfkey_open"); + return -1; + } + + /* debug mode ? */ + if (f_debug) + return 0; + + if (pfkey_send_register(so, SADB_SATYPE_UNSPEC) < 0) + return -1; + + if (pfkey_recv_register(so) < 0) + return -1; + + return 0; +} + +void +sendkeyshort(type) + u_int type; +{ + struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; + + m_len = sizeof(struct sadb_msg); + + m_msg->sadb_msg_version = PF_KEY_V2; + m_msg->sadb_msg_type = type; + m_msg->sadb_msg_errno = 0; + m_msg->sadb_msg_satype = SADB_SATYPE_UNSPEC; + m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); + m_msg->sadb_msg_reserved = 0; + m_msg->sadb_msg_seq = 0; + m_msg->sadb_msg_pid = getpid(); + + sendkeymsg(); + + return; +} + +void +promisc() +{ + struct sadb_msg *m_msg = (struct sadb_msg *)m_buf; + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + int so, len; + + m_len = sizeof(struct sadb_msg); + + m_msg->sadb_msg_version = PF_KEY_V2; + m_msg->sadb_msg_type = SADB_X_PROMISC; + m_msg->sadb_msg_errno = 0; + m_msg->sadb_msg_satype = 1; + m_msg->sadb_msg_len = PFKEY_UNIT64(m_len); + m_msg->sadb_msg_reserved = 0; + m_msg->sadb_msg_seq = 0; + m_msg->sadb_msg_pid = getpid(); + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + err(1, "socket(PF_KEY)"); + /*NOTREACHED*/ + } + + if ((len = send(so, m_buf, m_len, 0)) < 0) { + err(1, "send"); + /*NOTREACHED*/ + } + + while (1) { + struct sadb_msg *base; + + if ((len = recv(so, rbuf, sizeof(*base), MSG_PEEK)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + + if (len != sizeof(*base)) + continue; + + base = (struct sadb_msg *)rbuf; + if ((len = recv(so, rbuf, PFKEY_UNUNIT64(base->sadb_msg_len), + 0)) < 0) { + err(1, "recv"); + /*NOTREACHED*/ + } + printdate(); + if (f_hexdump) { + int i; + for (i = 0; i < len; i++) { + if (i % 16 == 0) + printf("%08x: ", i); + printf("%02x ", rbuf[i] & 0xff); + if (i % 16 == 15) + printf("\n"); + } + if (len % 16) + printf("\n"); + } + /* adjust base pointer for promisc mode */ + if (base->sadb_msg_type == SADB_X_PROMISC) { + if (sizeof(*base) < len) + base++; + else + base = NULL; + } + if (base) { + kdebug_sadb(base); + printf("\n"); + fflush(stdout); + } + } +} + +int +sendkeymsg() +{ + int so; + + u_char rbuf[1024 * 32]; /* XXX: Enough ? Should I do MSG_PEEK ? */ + int len; + struct sadb_msg *msg; + + if ((so = pfkey_open()) < 0) { + perror("pfkey_open"); + return -1; + } + + { + struct timeval tv; + tv.tv_sec = 1; + tv.tv_usec = 0; + if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { + perror("setsockopt"); + goto end; + } + } + + if (f_forever) + shortdump_hdr(); +again: + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)m_buf); + printf("\n"); + } + + if ((len = send(so, m_buf, m_len, 0)) < 0) { + perror("send"); + goto end; + } + + msg = (struct sadb_msg *)rbuf; + do { + if ((len = recv(so, rbuf, sizeof(rbuf), 0)) < 0) { + perror("recv"); + goto end; + } + + if (PFKEY_UNUNIT64(msg->sadb_msg_len) != len) { + warnx("invalid keymsg length"); + break; + } + + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)rbuf); + printf("\n"); + } + if (postproc(msg, len) < 0) + break; + } while (msg->sadb_msg_errno || msg->sadb_msg_seq); + + if (f_forever) { + fflush(stdout); + sleep(1); + goto again; + } + +end: + pfkey_close(so); + return(0); +} + +int +postproc(msg, len) + struct sadb_msg *msg; + int len; +{ + + if (msg->sadb_msg_errno != 0) { + char inf[80]; + char *errmsg = NULL; + + if (f_mode == MODE_SCRIPT) + snprintf(inf, sizeof(inf), "The result of line %d: ", lineno); + else + inf[0] = '\0'; + + switch (msg->sadb_msg_errno) { + case ENOENT: + switch (msg->sadb_msg_type) { + case SADB_DELETE: + case SADB_GET: + case SADB_X_SPDDELETE: + errmsg = "No entry"; + break; + case SADB_DUMP: + errmsg = "No SAD entries"; + break; + case SADB_X_SPDDUMP: + errmsg = "No SPD entries"; + break; + } + break; + default: + errmsg = strerror(msg->sadb_msg_errno); + } + printf("%s%s.\n", inf, errmsg); + return(-1); + } + + switch (msg->sadb_msg_type) { + case SADB_GET: + pfkey_sadump(msg); + break; + + case SADB_DUMP: + /* filter out DEAD SAs */ + if (!f_all) { + caddr_t mhp[SADB_EXT_MAX + 1]; + struct sadb_sa *sa; + pfkey_align(msg, mhp); + pfkey_check(mhp); + if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { + if (sa->sadb_sa_state == SADB_SASTATE_DEAD) + break; + } + } + if (f_forever) + shortdump(msg); + else + pfkey_sadump(msg); + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)msg); + printf("\n"); + } + break; + + case SADB_X_SPDDUMP: + pfkey_spdump(msg); + if (msg->sadb_msg_seq == 0) break; + msg = (struct sadb_msg *)((caddr_t)msg + + PFKEY_UNUNIT64(msg->sadb_msg_len)); + if (f_verbose) { + kdebug_sadb((struct sadb_msg *)msg); + printf("\n"); + } + break; + } + + return(0); +} + +/*------------------------------------------------------------*/ +static char *satype[] = { + NULL, NULL, "ah", "esp" +}; +static char *sastate[] = { + "L", "M", "D", "d" +}; +static char *ipproto[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + NULL, "tcp", NULL, "egp", NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, "udp", NULL, NULL, +/*20*/ NULL, NULL, "idp", NULL, NULL, + NULL, NULL, NULL, NULL, "tp", +/*30*/ NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, +/*40*/ NULL, "ip6", NULL, "rt6", "frag6", + NULL, "rsvp", "gre", NULL, NULL, +/*50*/ "esp", "ah", NULL, NULL, NULL, + NULL, NULL, NULL, "icmp6", "none", +/*60*/ "dst6", +}; + +#define STR_OR_ID(x, tab) \ + (((x) < sizeof(tab)/sizeof(tab[0]) && tab[(x)]) ? tab[(x)] : numstr(x)) + +const char * +numstr(x) + int x; +{ + static char buf[20]; + snprintf(buf, sizeof(buf), "#%d", x); + return buf; +} + +void +shortdump_hdr() +{ + printf("%-4s %-3s %-1s %-8s %-7s %s -> %s\n", + "time", "p", "s", "spi", "ltime", "src", "dst"); +} + +void +shortdump(msg) + struct sadb_msg *msg; +{ + caddr_t mhp[SADB_EXT_MAX + 1]; + char buf[1024], pbuf[10]; + struct sadb_sa *sa; + struct sadb_address *saddr; + struct sadb_lifetime *lts, *lth, *ltc; + struct sockaddr *s; + u_int t; + time_t cur = time(0); + + pfkey_align(msg, mhp); + pfkey_check(mhp); + + printf("%02lu%02lu", (u_long)(cur % 3600) / 60, (u_long)(cur % 60)); + + printf(" %-3s", STR_OR_ID(msg->sadb_msg_satype, satype)); + + if ((sa = (struct sadb_sa *)mhp[SADB_EXT_SA]) != NULL) { + printf(" %-1s", STR_OR_ID(sa->sadb_sa_state, sastate)); + printf(" %08x", (u_int32_t)ntohl(sa->sadb_sa_spi)); + } else + printf("%-1s %-8s", "?", "?"); + + lts = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_SOFT]; + lth = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_HARD]; + ltc = (struct sadb_lifetime *)mhp[SADB_EXT_LIFETIME_CURRENT]; + if (lts && lth && ltc) { + if (ltc->sadb_lifetime_addtime == 0) + t = (u_long)0; + else + t = (u_long)(cur - ltc->sadb_lifetime_addtime); + if (t >= 1000) + strcpy(buf, " big/"); + else + snprintf(buf, sizeof(buf), " %3lu/", (u_long)t); + printf("%s", buf); + + t = (u_long)lth->sadb_lifetime_addtime; + if (t >= 1000) + strcpy(buf, "big"); + else + snprintf(buf, sizeof(buf), "%-3lu", (u_long)t); + printf("%s", buf); + } else + printf(" ??\?/???"); /* backslash to avoid trigraph ??/ */ + + printf(" "); + + if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC]) != NULL) { + if (saddr->sadb_address_proto) + printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); + s = (struct sockaddr *)(saddr + 1); + getnameinfo(s, s->sa_len, buf, sizeof(buf), + pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); + if (strcmp(pbuf, "0") != 0) + printf("%s[%s]", buf, pbuf); + else + printf("%s", buf); + } else + printf("?"); + + printf(" -> "); + + if ((saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST]) != NULL) { + if (saddr->sadb_address_proto) + printf("%s ", STR_OR_ID(saddr->sadb_address_proto, ipproto)); + + s = (struct sockaddr *)(saddr + 1); + getnameinfo(s, s->sa_len, buf, sizeof(buf), + pbuf, sizeof(pbuf), NI_NUMERICHOST|NI_NUMERICSERV); + if (strcmp(pbuf, "0") != 0) + printf("%s[%s]", buf, pbuf); + else + printf("%s", buf); + } else + printf("?"); + + printf("\n"); +} + +/* From: tcpdump(1):gmt2local.c and util.c */ +/* + * Print the timestamp + */ +static void +printdate() +{ + struct timeval tp; + int s; + + if (gettimeofday(&tp, NULL) == -1) { + perror("gettimeofday"); + return; + } + + if (f_tflag == 1) { + /* Default */ + s = (tp.tv_sec + thiszone ) % 86400; + (void)printf("%02d:%02d:%02d.%06u ", + s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tp.tv_usec); + } else if (f_tflag > 1) { + /* Unix timeval style */ + (void)printf("%u.%06u ", + (u_int32_t)tp.tv_sec, (u_int32_t)tp.tv_usec); + } + + printf("\n"); +} + +/* + * Returns the difference between gmt and local time in seconds. + * Use gmtime() and localtime() to keep things simple. + */ +int32_t +gmt2local(time_t t) +{ + register int dt, dir; + register struct tm *gmt, *loc; + struct tm sgmt; + + if (t == 0) + t = time(NULL); + gmt = &sgmt; + *gmt = *gmtime(&t); + loc = localtime(&t); + dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + + (loc->tm_min - gmt->tm_min) * 60; + + /* + * If the year or julian day is different, we span 00:00 GMT + * and must add or subtract a day. Check the year first to + * avoid problems when the julian day wraps. + */ + dir = loc->tm_year - gmt->tm_year; + if (dir == 0) + dir = loc->tm_yday - gmt->tm_yday; + dt += dir * 24 * 60 * 60; + + return (dt); +} diff --git a/setkey.tproj/token.l b/setkey.tproj/token.l new file mode 100644 index 0000000..23be078 --- /dev/null +++ b/setkey.tproj/token.l @@ -0,0 +1,323 @@ +/* $FreeBSD: src/usr.sbin/setkey/token.l,v 1.2.2.3 2001/07/03 11:02:17 ume Exp $ */ +/* $KAME: token.l,v 1.21 2001/05/18 05:35:01 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +%option noyywrap +%{ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "vchar.h" +#ifdef __NetBSD__ +#include "parse.h" +#else +#include "y.tab.h" +#endif + +#define DECHO \ + if (f_debug) {printf("<%d>", yy_start); ECHO ; printf("\n"); } + +#define CMDARG \ +{ \ + char *__buf__ = strdup(yytext), *__p__; \ + for (__p__ = __buf__; *__p__ != NULL; __p__++) \ + if (*__p__ == '\n' || *__p__ == '\t') \ + *__p__ = ' '; \ + strcat(cmdarg, __buf__); \ + free(__buf__); \ +} + +#define PREPROC DECHO CMDARG + +int lineno = 1; +char cmdarg[8192]; /* XXX: BUFSIZ is the better ? */ + +extern u_char m_buf[BUFSIZ]; +extern u_int m_len; +extern int f_debug; + +int yylex __P((void)); +void yyfatal __P((const char *s)); +void yyerror __P((const char *s)); +extern void parse_init __P((void)); +int parse __P((FILE **)); +int yyparse __P((void)); + +%} + +/* common section */ +nl \n +ws [ \t]+ +digit [0-9] +letter [0-9A-Za-z] +hexdigit [0-9A-Fa-f] +/*octet (([01]?{digit}?{digit})|((2([0-4]{digit}))|(25[0-5])))*/ +special [()+\|\?\*,] +dot \. +comma \, +hyphen \- +colon \: +slash \/ +bcl \{ +ecl \} +blcl \[ +elcl \] +percent \% +semi \; +usec {dot}{digit}{1,6} +comment \#.* +ccomment "/*" +bracketstring \<[^>]*\> +quotedstring \"[^"]*\" +decstring {digit}+ +hexpair {hexdigit}{hexdigit} +hexstring 0[xX]{hexdigit}+ +octetstring {octet}({dot}{octet})+ +ipaddress [a-fA-F0-9:]([a-fA-F0-9:\.]*|[a-fA-F0-9:\.]*%[a-zA-Z0-9]*) +ipaddrmask {slash}{digit}{1,3} +ipaddrport {blcl}{decstring}{elcl} +keyword {letter}{letter}+ +name {letter}(({letter}|{digit}|{hyphen})*({letter}|{digit}))* +hostname {name}(({dot}{name})+{dot}?)? + +%s S_PL + +%% + +add { PREPROC; return(ADD); } +delete { PREPROC; return(DELETE); } +deleteall { PREPROC; return(DELETEALL); } +get { PREPROC; return(GET); } +flush { PREPROC; return(FLUSH); } +dump { PREPROC; return(DUMP); } + + /* for management SPD */ +spdadd { PREPROC; return(SPDADD); } +spddelete { PREPROC; return(SPDDELETE); } +spddump { PREPROC; return(SPDDUMP); } +spdflush { PREPROC; return(SPDFLUSH); } +{hyphen}P { BEGIN S_PL; PREPROC; return(F_POLICY); } +[a-zA-Z0-9:\.\-_/ \n\t][a-zA-Z0-9:\.\-_/ \n\t]* { + yymore(); + + /* count up for nl */ + { + char *p; + for (p = yytext; *p != NULL; p++) + if (*p == '\n') + lineno++; + } + + yylval.val.len = strlen(yytext); + yylval.val.buf = strdup(yytext); + + return(PL_REQUESTS); +} +{semi} { PREPROC; BEGIN INITIAL; return(EOT); } + + /* security protocols */ +ah { PREPROC; yylval.num = 0; return(PR_AH); } +esp { PREPROC; yylval.num = 0; return(PR_ESP); } +ah-old { PREPROC; yylval.num = 1; return(PR_AH); } +esp-old { PREPROC; yylval.num = 1; return(PR_ESP); } +ipcomp { PREPROC; yylval.num = 0; return(PR_IPCOMP); } + + /* authentication alogorithm */ +{hyphen}A { PREPROC; return(F_AUTH); } +hmac-md5 { PREPROC; yylval.num = SADB_AALG_MD5HMAC; return(ALG_AUTH); } +hmac-sha1 { PREPROC; yylval.num = SADB_AALG_SHA1HMAC; return(ALG_AUTH); } +keyed-md5 { PREPROC; yylval.num = SADB_X_AALG_MD5; return(ALG_AUTH); } +keyed-sha1 { PREPROC; yylval.num = SADB_X_AALG_SHA; return(ALG_AUTH); } +hmac-sha2-256 { PREPROC; yylval.num = SADB_X_AALG_SHA2_256; return(ALG_AUTH); } +hmac-sha2-384 { PREPROC; yylval.num = SADB_X_AALG_SHA2_384; return(ALG_AUTH); } +hmac-sha2-512 { PREPROC; yylval.num = SADB_X_AALG_SHA2_512; return(ALG_AUTH); } +null { PREPROC; yylval.num = SADB_X_AALG_NULL; return(ALG_AUTH); } + + /* encryption alogorithm */ +{hyphen}E { PREPROC; return(F_ENC); } +des-cbc { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC); } +3des-cbc { PREPROC; yylval.num = SADB_EALG_3DESCBC; return(ALG_ENC); } +simple { PREPROC; yylval.num = SADB_EALG_NULL; return(ALG_ENC); } +blowfish-cbc { PREPROC; yylval.num = SADB_X_EALG_BLOWFISHCBC; return(ALG_ENC); } +cast128-cbc { PREPROC; yylval.num = SADB_X_EALG_CAST128CBC; return(ALG_ENC); } +des-deriv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DESDERIV); } +des-32iv { PREPROC; yylval.num = SADB_EALG_DESCBC; return(ALG_ENC_DES32IV); } +rijndael-cbc { PREPROC; yylval.num = SADB_X_EALG_RIJNDAELCBC; return(ALG_ENC); } + + /* compression algorithms */ +{hyphen}C { PREPROC; return(F_COMP); } +oui { PREPROC; yylval.num = SADB_X_CALG_OUI; return(ALG_COMP); } +deflate { PREPROC; yylval.num = SADB_X_CALG_DEFLATE; return(ALG_COMP); } +lzs { PREPROC; yylval.num = SADB_X_CALG_LZS; return(ALG_COMP); } +{hyphen}R { PREPROC; return(F_RAWCPI); } + + /* extension */ +{hyphen}m { PREPROC; return(F_MODE); } +transport { PREPROC; yylval.num = IPSEC_MODE_TRANSPORT; return(MODE); } +tunnel { PREPROC; yylval.num = IPSEC_MODE_TUNNEL; return(MODE); } +{hyphen}u { PREPROC; return(F_REQID); } +{hyphen}f { PREPROC; return(F_EXT); } +random-pad { PREPROC; yylval.num = SADB_X_EXT_PRAND; return(EXTENSION); } +seq-pad { PREPROC; yylval.num = SADB_X_EXT_PSEQ; return(EXTENSION); } +zero-pad { PREPROC; yylval.num = SADB_X_EXT_PZERO; return(EXTENSION); } +nocyclic-seq { PREPROC; return(NOCYCLICSEQ); } +{hyphen}r { PREPROC; return(F_REPLAY); } +{hyphen}lh { PREPROC; return(F_LIFETIME_HARD); } +{hyphen}ls { PREPROC; return(F_LIFETIME_SOFT); } + + /* ... */ +any { PREPROC; return(ANY); } +{ws} { PREPROC; } +{nl} { lineno++; } +{comment} +{semi} { PREPROC; return(EOT); } + + /* parameter */ +{decstring} { + char *bp; + + PREPROC; + yylval.num = strtoul(yytext, &bp, 10); + return(DECSTRING); + } + +{ipaddress} { + PREPROC; + + yylval.val.len = yyleng; + yylval.val.buf = strdup(yytext); + + return(ADDRESS); + } + +{ipaddrmask} { + PREPROC; + yytext++; + yylval.num = atoi(yytext); + return(PREFIX); + } + +{ipaddrport} { + char *p = yytext; + PREPROC; + while (*++p != ']') ; + *p = NULL; + yytext++; + yylval.num = atoi(yytext); + return(PORT); + } + +{blcl}any{elcl} { + PREPROC; + return(PORTANY); + } + +{hexstring} { + int len = yyleng - 2; /* (str - "0x") */ + PREPROC; + yylval.val.len = (len & 1) + (len / 2); + /* fixed string if length is odd. */ + if (len & 1) { + yytext[1] = '0'; + yylval.val.buf = strdup(yytext + 1); + } else + yylval.val.buf = strdup(yytext + 2); + + return(HEXSTRING); + } + +{quotedstring} { + char *p = yytext; + PREPROC; + while (*++p != '"') ; + *p = NULL; + yytext++; + yylval.val.len = yyleng - 2; + yylval.val.buf = strdup(yytext); + + return(QUOTEDSTRING); + } + +[a-z0-9.\-]* { + yylval.val.len = yyleng; + yylval.val.buf = strdup(yytext); + return(STRING); + } + +. { + yyfatal("Syntax error"); + /*NOTREACHED*/ + } + +%% + +void +yyfatal(s) + const char *s; +{ + yyerror(s); + exit(1); +} + +void +yyerror(s) + const char *s; +{ + printf("line %d: %s at [%s]\n", lineno, s, yytext); +} + +int +parse(fp) + FILE **fp; +{ + yyin = *fp; + + parse_init(); + + if (yyparse()) { + printf("parse failed, line %d.\n", lineno); + return(-1); + } + + return(0); +} diff --git a/setkey.tproj/vchar.h b/setkey.tproj/vchar.h new file mode 100644 index 0000000..a3f852d --- /dev/null +++ b/setkey.tproj/vchar.h @@ -0,0 +1,36 @@ +/* $FreeBSD: src/usr.sbin/setkey/vchar.h,v 1.1.2.1 2000/07/15 07:37:04 kris Exp $ */ +/* $KAME: vchar.h,v 1.2 2000/06/07 00:29:14 itojun Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 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. 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. + */ + +typedef struct { + u_int len; + caddr_t buf; +} vchar_t; diff --git a/sliplogin.tproj/Makefile.preamble b/sliplogin.tproj/Makefile.preamble deleted file mode 100644 index 2c9003c..0000000 --- a/sliplogin.tproj/Makefile.preamble +++ /dev/null @@ -1,113 +0,0 @@ -############################################################################### -# NeXT Makefile.preamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. -# -############################################################################### -## Configure the flags passed to $(CC) here. These flags will also be -## inherited by all nested sub-projects and bundles. Put your -I, -D, -U, and -## -L flags here. To change the default flags that get passed to ${CC} -## (e.g. change -O to -O2), see Makefile.postamble. - -# Flags passed to compiler (in addition to -g, -O, etc) -OTHER_CFLAGS = -# Flags passed to ld (in addition to -ObjC, etc.) -OTHER_LDFLAGS = - -BUNDLELDFLAGS = # use iff project is a bundle -PALETTELDFLAGS = # use iff project is a palette - -## Specify which headers in this project should be published to the outside -## world in a flat header directory given in PUBLIC_HEADER_DIR (which will be -## prepended by DSTROOT, below. Any subset of these public headers can be -## precompiled automatically after installation, with extra user-defined flags. -PUBLIC_HEADER_DIR = -PUBLIC_HEADERS = -PUBLIC_PRECOMPILED_HEADERS = -PUBLIC_PRECOMPILED_HEADERS_CFLAGS = - -## Configure what is linked in at each level here. Libraries are only used in -## the final 'app' linking step. Final 'app' linking is only done via the -## 'app', 'debug', and 'profile' targets when they are invoked for -## the top-level app. - -# Additional relocatables to be linked in at this level -OTHER_OFILES = -# Additional libs to link apps against ('app' target) -#OTHER_LIBS = -# Additional libs to link apps against ('debug' target) -OTHER_DEBUG_LIBS = -# Additional libs to link apps against ('profile' target) -OTHER_PROF_LIBS = - -# More 'app' libraries when $(JAPANESE) = "YES" -OTHER_JAPANESE_LIBS = -# More 'debug' libraries when $(JAPANESE) = "YES" -OTHER_JAPANESE_DEBUG_LIBS = -# More 'profile' libs when $(JAPANESE) = "YES" -OTHER_JAPANESE_PROF_LIBS = - -# If this is a bundle, and you *know* the enclosing application will not -# be linking with a library which you require in your bundle code, then -# mention it here so that it gets linked into the bundle. Note that this -# is wasteful but sometimes necessary. -BUNDLE_LIBS = - -## Configure how things get built here. Additional dependencies, sourcefiles, -## derived files, and build order should be specified here. - -# Other dependencies of this project -OTHER_PRODUCT_DEPENDS = -# Built *before* building subprojects/bundles -OTHER_INITIAL_TARGETS = -# Other source files maintained by .pre/postamble -OTHER_SOURCEFILES = -# Additional files to be removed by `make clean' -OTHER_GARBAGE = -# Precompiled headers to be built before any compilation occurs (e.g., draw.p) -PRECOMPS = - -# Targets to be built before installation -OTHER_INSTALL_DEPENDS = - -# A virtual root directory (other than /) to be prepended to the $(INSTALLDIR) -# passed from ProjectBuilder. -DSTROOT = - -# Set the following to "YES" if you want the old behavior of recursively -# cleaning all nested subprojects during 'make clean'. -CLEAN_ALL_SUBPROJECTS = - -## Add more obscure source files here to cause them to be automatically -## processed by the appropriate tool. Note that these files should also be -## added to "Supporting Files" in ProjectBuilder. The desired .o files that -## result from these files should also be added to OTHER_OFILES above so they -## will be linked in. - -# .msg files that should have msgwrap run on them -MSGFILES = -# .defs files that should have mig run on them -DEFSFILES = -# .mig files (no .defs files) that should have mig run on them -MIGFILES = - -## Add additional Help directories here (add them to the project as "Other -## Resources" in Project Builder) so that they will be compressed into .store -## files and copied into the app wrapper. If the help directories themselves -## need to also be in the app wrapper, then a cp command will need to be added -## in an after_install target. -OTHER_HELP_DIRS = - -# Don't add more rules here unless you want the first one to be the default -# target for make! Put all your targets in Makefile.postamble. - -# To include a version string, project source must exist in a directory named -# $(NAME).%d[.%d][.%d] and the following line must be uncommented. -OTHER_GENERATED_OFILES = $(VERS_OFILE) --include ../Makefile.include diff --git a/sliplogin.tproj/pathnames.h b/sliplogin.tproj/pathnames.h deleted file mode 100644 index 3060035..0000000 --- a/sliplogin.tproj/pathnames.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 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. - * - * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 - */ - -#ifndef COMPAT -#include -#else -#define _PATH_DEVNULL "/dev/null" -#endif - -#define _PATH_ACCESS "/etc/sliphome/slip.hosts" -#define _PATH_LOGIN "/etc/sliphome/slip.login" -#define _PATH_LOGOUT "/etc/sliphome/slip.logout" -#define _PATH_DEBUG "/tmp/sliplogin.XXXXXX" - diff --git a/sliplogin.tproj/slip.hosts b/sliplogin.tproj/slip.hosts deleted file mode 100644 index f6ebf40..0000000 --- a/sliplogin.tproj/slip.hosts +++ /dev/null @@ -1,11 +0,0 @@ -# @(#)slip.hosts 8.1 (Berkeley) 6/6/93 -# -# login local-addr remote-addr mask opt1 opt2 -# (normal,compress,noicmp) -# -Schez vangogh chez 0xffffff00 compress -Sjun vangogh 128.32.130.36 0xffffff00 normal -Sleconte vangogh leconte 0xffffff00 compress -Sleeb vangogh leeb 0xffffff00 compress -Smjk vangogh pissaro-sl 0xffffff00 compress -Soxford vangogh oxford 0xffffff00 compress diff --git a/sliplogin.tproj/slip.login b/sliplogin.tproj/slip.login deleted file mode 100644 index 3c70095..0000000 --- a/sliplogin.tproj/slip.login +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# -# @(#)slip.login 8.1 (Berkeley) 6/6/93 - -# -# generic login file for a slip line. sliplogin invokes this with -# the parameters: -# 1 2 3 4 5 6 7-n -# slipunit ttyspeed loginname local-addr remote-addr mask opt-args -# -/sbin/ifconfig sl$1 inet $4 $5 netmask $6 -exit diff --git a/sliplogin.tproj/sliplogin.8 b/sliplogin.tproj/sliplogin.8 deleted file mode 100644 index 1c71988..0000000 --- a/sliplogin.tproj/sliplogin.8 +++ /dev/null @@ -1,220 +0,0 @@ -.\" Copyright (c) 1990, 1991, 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. -.\" -.\" @(#)sliplogin.8 8.2 (Berkeley) 1/5/94 -.\" -.Dd January 5, 1994 -.Dt SLIPLOGIN 8 -.Os -.Sh NAME -.Nm sliplogin -.Nd attach a serial line network interface -.Sh SYNOPSIS -.Nm sliplogin -.Op Ar loginname -.Sh DESCRIPTION -.Nm Sliplogin -is used to turn the terminal line on standard input into -a Serial Line IP -.Pq Tn SLIP -link to a remote host. To do this, the program -searches the file -.Pa /etc/sliphome/slip.hosts -for an entry matching -.Ar loginname -(which defaults to the current login name if omitted). -If a matching entry is found, the line is configured appropriately -for slip (8-bit transparent i/o) and converted to -.Tn SLIP -line -discipline. Then a shell script is invoked to initialize the slip -interface with the appropriate local and remote -.Tn IP -address, -netmask, etc. -.Pp -The usual initialization script is -.Pa /etc/sliphome/slip.login -but, if particular hosts need special initialization, the file -.Pa /etc/sliphome/slip.login. Ns Ar loginname -will be executed instead if it exists. -The script is invoked with the parameters -.Bl -tag -width slipunit -.It Em slipunit -The unit number of the slip interface assigned to this line. E.g., -.Sy 0 -for -.Sy sl0 . -.It Em speed -The speed of the line. -.It Em args -The arguments from the -.Pa /etc/sliphome/slip.hosts -entry, in order starting with -.Ar loginname . -.El -.Pp -Only the super-user may attach a network interface. The interface is -automatically detached when the other end hangs up or the -.Nm sliplogin -process dies. If the kernel slip -module has been configured for it, all routes through that interface will -also disappear at the same time. If there is other processing a site -would like done on hangup, the file -.Pa /etc/sliphome/slip.logout -or -.Pa /etc/sliphome/slip.logout. Ns Ar loginname -is executed if it exists. It is given the same arguments as the login script. -.Ss Format of /etc/sliphome/slip.hosts -Comments (lines starting with a `#') and blank lines are ignored. -Other lines must start with a -.Ar loginname -but the remaining arguments can be whatever is appropriate for the -.Pa slip.login -file that will be executed for that name. -Arguments are separated by white space and follow normal -.Xr sh 1 -quoting conventions (however, -.Ar loginname -cannot be quoted). -Usually, lines have the form -.Bd -literal -offset indent -loginname local-address remote-address netmask opt-args -.Ed -.Pp -where -.Em local-address -and -.Em remote-address -are the IP host names or addresses of the local and remote ends of the -slip line and -.Em netmask -is the appropriate IP netmask. These arguments are passed -directly to -.Xr ifconfig 8 . -.Em Opt-args -are optional arguments used to configure the line. -.Sh EXAMPLE -The normal use of -.Nm sliplogin -is to create a -.Pa /etc/passwd -entry for each legal, remote slip site with -.Nm sliplogin -as the shell for that entry. E.g., -.Bd -literal -Sfoo:ikhuy6:2010:1:slip line to foo:/tmp:/usr/sbin/sliplogin -.Ed -.Pp -(Our convention is to name the account used by remote host -.Ar hostname -as -.Em Shostname . ) -Then an entry is added to -.Pa slip.hosts -that looks like: -.Pp -.Bd -literal -offset indent -compact -Sfoo `hostname` foo netmask -.Ed -.Pp -where -.Em `hostname` -will be evaluated by -.Xr sh -to the local host name and -.Em netmask -is the local host IP netmask. -.Pp -Note that -.Nm sliplogin -must be setuid to root and, while not a security hole, moral defectives -can use it to place terminal lines in an unusable state and/or deny -access to legitimate users of a remote slip line. To prevent this, -a site can create a group, say -.Em slip , -that only the slip login accounts are put in then make sure that -.Pa /usr/sbin/sliplogin -is in group -.Em slip -and mode 4550 (setuid root, only group -.Em slip -can execute binary). -.Sh DIAGNOSTICS -.Nm Sliplogin -logs various information to the system log daemon, -.Xr syslogd 8 , -with a facility code of -.Em daemon . -The messages are listed here, grouped by severity level. -.Pp -.Sy Error Severity -.Bl -tag -width Ds -compact -.It Sy ioctl (TCGETS): Em reason -A -.Dv TCGETS -.Fn ioctl -to get the line parameters failed. -.Pp -.It Sy ioctl (TCSETS): Em reason -A -.Dv TCSETS -.Fn ioctl -to set the line parameters failed. -.Pp -.It Sy /etc/sliphome/slip.hosts: Em reason -The -.Pa /etc/sliphome/slip.hosts -file could not be opened. -.Pp -.It Sy access denied for Em user -No entry for -.Em user -was found in -.Pa /etc/sliphome/slip.hosts . -.El -.Pp -.Sy Notice Severity -.Bl -tag -width Ds -compact -.It Sy "attaching slip unit" Em unit Sy for Ar loginname -.Tn SLIP -unit -.Em unit -was successfully attached. -.El -.Sh SEE ALSO -.Xr slattach 8 , -.Xr syslogd 8 -.Sh HISTORY -The -.Nm -command -.Bt diff --git a/sliplogin.tproj/sliplogin.c b/sliplogin.tproj/sliplogin.c deleted file mode 100644 index d1cdcab..0000000 --- a/sliplogin.tproj/sliplogin.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/*- - * Copyright (c) 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. - */ - -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1990, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)sliplogin.c 8.2 (Berkeley) 2/1/94"; -#endif /* not lint */ - -/* - * sliplogin.c - * [MUST BE RUN SUID, SLOPEN DOES A SUSER()!] - * - * This program initializes its own tty port to be an async TCP/IP interface. - * It sets the line discipline to slip, invokes a shell script to initialize - * the network interface, then pauses forever waiting for hangup. - * - * It is a remote descendant of several similar programs with incestuous ties: - * - Kirk Smith's slipconf, modified by Richard Johnsson @ DEC WRL. - * - slattach, probably by Rick Adams but touched by countless hordes. - * - the original sliplogin for 4.2bsd, Doug Kingston the mover behind it. - * - * There are two forms of usage: - * - * "sliplogin" - * Invoked simply as "sliplogin", the program looks up the username - * in the file /etc/slip.hosts. - * If an entry is found, the line on fd0 is configured for SLIP operation - * as specified in the file. - * - * "sliplogin IPhostlogin -#include -#include -#include -#include -#include - -#if BSD >= 199006 -#define POSIX -#endif -#ifdef POSIX -#include -#include -#include -#else -#include -#endif -#include - -#include -#include -#include -#include -#include "pathnames.h" - -int unit; -int speed; -int uid; -char loginargs[BUFSIZ]; -char loginfile[MAXPATHLEN]; -char loginname[BUFSIZ]; - -void -findid(name) - char *name; -{ - FILE *fp; - static char slopt[5][16]; - static char laddr[16]; - static char raddr[16]; - static char mask[16]; - char user[16]; - int i, j, n; - - (void)strcpy(loginname, name); - if ((fp = fopen(_PATH_ACCESS, "r")) == NULL) { - (void)fprintf(stderr, "sliplogin: %s: %s\n", - _PATH_ACCESS, strerror(errno)); - syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS); - exit(1); - } - while (fgets(loginargs, sizeof(loginargs) - 1, fp)) { - if (ferror(fp)) - break; - n = sscanf(loginargs, "%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s%*[ \t]%15s\n", - user, laddr, raddr, mask, slopt[0], slopt[1], - slopt[2], slopt[3], slopt[4]); - if (user[0] == '#' || isspace(user[0])) - continue; - if (strcmp(user, name) != 0) - continue; - - /* - * we've found the guy we're looking for -- see if - * there's a login file we can use. First check for - * one specific to this host. If none found, try for - * a generic one. - */ - (void)sprintf(loginfile, "%s.%s", _PATH_LOGIN, name); - if (access(loginfile, R_OK|X_OK) != 0) { - (void)strcpy(loginfile, _PATH_LOGIN); - if (access(loginfile, R_OK|X_OK)) { - fputs("access denied - no login file\n", - stderr); - syslog(LOG_ERR, - "access denied for %s - no %s\n", - name, _PATH_LOGIN); - exit(5); - } - } - - (void) fclose(fp); - return; - } - (void)fprintf(stderr, "SLIP access denied for %s\n", name); - syslog(LOG_ERR, "SLIP access denied for %s\n", name); - exit(4); - /* NOTREACHED */ -} - -char * -sigstr(s) - int s; -{ - static char buf[32]; - - switch (s) { - case SIGHUP: return("HUP"); - case SIGINT: return("INT"); - case SIGQUIT: return("QUIT"); - case SIGILL: return("ILL"); - case SIGTRAP: return("TRAP"); - case SIGIOT: return("IOT"); - case SIGEMT: return("EMT"); - case SIGFPE: return("FPE"); - case SIGKILL: return("KILL"); - case SIGBUS: return("BUS"); - case SIGSEGV: return("SEGV"); - case SIGSYS: return("SYS"); - case SIGPIPE: return("PIPE"); - case SIGALRM: return("ALRM"); - case SIGTERM: return("TERM"); - case SIGURG: return("URG"); - case SIGSTOP: return("STOP"); - case SIGTSTP: return("TSTP"); - case SIGCONT: return("CONT"); - case SIGCHLD: return("CHLD"); - case SIGTTIN: return("TTIN"); - case SIGTTOU: return("TTOU"); - case SIGIO: return("IO"); - case SIGXCPU: return("XCPU"); - case SIGXFSZ: return("XFSZ"); - case SIGVTALRM: return("VTALRM"); - case SIGPROF: return("PROF"); - case SIGWINCH: return("WINCH"); -#ifdef SIGLOST - case SIGLOST: return("LOST"); -#endif - case SIGUSR1: return("USR1"); - case SIGUSR2: return("USR2"); - } - (void)sprintf(buf, "sig %d", s); - return(buf); -} - -void -hup_handler(s) - int s; -{ - char logoutfile[MAXPATHLEN]; - - (void)sprintf(logoutfile, "%s.%s", _PATH_LOGOUT, loginname); - if (access(logoutfile, R_OK|X_OK) != 0) - (void)strcpy(logoutfile, _PATH_LOGOUT); - if (access(logoutfile, R_OK|X_OK) == 0) { - char logincmd[2*MAXPATHLEN+32]; - - (void) sprintf(logincmd, "%s %d %d %s", logoutfile, unit, speed, - loginargs); - (void) system(logincmd); - } - (void) close(0); - syslog(LOG_INFO, "closed %s slip unit %d (%s)\n", loginname, unit, - sigstr(s)); - exit(1); - /* NOTREACHED */ -} - -main(argc, argv) - int argc; - char *argv[]; -{ - int fd, s, ldisc, odisc; - char *name; -#ifdef POSIX - struct termios tios, otios; -#else - struct sgttyb tty, otty; -#endif - char logincmd[2*BUFSIZ+32]; - extern uid_t getuid(); - - if ((name = strrchr(argv[0], '/')) == NULL) - name = argv[0]; - s = getdtablesize(); - for (fd = 3 ; fd < s ; fd++) - (void) close(fd); - openlog(name, LOG_PID, LOG_DAEMON); - uid = getuid(); - if (argc > 1) { - findid(argv[1]); - - /* - * Disassociate from current controlling terminal, if any, - * and ensure that the slip line is our controlling terminal. - */ -#ifdef POSIX - if (fork() > 0) - exit(0); - if (setsid() != 0) - perror("setsid"); -#else - if ((fd = open("/dev/tty", O_RDONLY, 0)) >= 0) { - extern char *ttyname(); - - (void) ioctl(fd, TIOCNOTTY, (caddr_t)0); - (void) close(fd); - /* open slip tty again to acquire as controlling tty? */ - fd = open(ttyname(0), O_RDWR, 0); - if (fd >= 0) - (void) close(fd); - } - (void) setpgrp(0, getpid()); -#endif - if (argc > 2) { - if ((fd = open(argv[2], O_RDWR)) == -1) { - perror(argv[2]); - exit(2); - } - (void) dup2(fd, 0); - if (fd > 2) - close(fd); - } -#ifdef TIOCSCTTY - if (ioctl(0, TIOCSCTTY, (caddr_t)0) != 0) - perror("ioctl (TIOCSCTTY)"); -#endif - } else { - extern char *getlogin(); - - if ((name = getlogin()) == NULL) { - (void) fprintf(stderr, "access denied - no username\n"); - syslog(LOG_ERR, "access denied - getlogin returned 0\n"); - exit(1); - } - findid(name); - } - (void) fchmod(0, 0600); - (void) fprintf(stderr, "starting slip login for %s\n", loginname); -#ifdef POSIX - /* set up the line parameters */ - if (tcgetattr(0, &tios) < 0) { - syslog(LOG_ERR, "tcgetattr: %m"); - exit(1); - } - otios = tios; - cfmakeraw(&tios); - tios.c_iflag &= ~IMAXBEL; - if (tcsetattr(0, TCSAFLUSH, &tios) < 0) { - syslog(LOG_ERR, "tcsetattr: %m"); - exit(1); - } - speed = cfgetispeed(&tios); -#else - /* set up the line parameters */ - if (ioctl(0, TIOCGETP, (caddr_t)&tty) < 0) { - syslog(LOG_ERR, "ioctl (TIOCGETP): %m"); - exit(1); - } - otty = tty; - speed = tty.sg_ispeed; - tty.sg_flags = RAW | ANYP; - if (ioctl(0, TIOCSETP, (caddr_t)&tty) < 0) { - syslog(LOG_ERR, "ioctl (TIOCSETP): %m"); - exit(1); - } -#endif - /* find out what ldisc we started with */ - if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) { - syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m"); - exit(1); - } - ldisc = SLIPDISC; - if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) { - syslog(LOG_ERR, "ioctl(TIOCSETD): %m"); - exit(1); - } - /* find out what unit number we were assigned */ - if (ioctl(0, SLIOCGUNIT, (caddr_t)&unit) < 0) { - syslog(LOG_ERR, "ioctl (SLIOCGUNIT): %m"); - exit(1); - } - (void) signal(SIGHUP, hup_handler); - (void) signal(SIGTERM, hup_handler); - - syslog(LOG_INFO, "attaching slip unit %d for %s\n", unit, loginname); - (void)sprintf(logincmd, "%s %d %d %s", loginfile, unit, speed, - loginargs); - /* - * aim stdout and errout at /dev/null so logincmd output won't - * babble into the slip tty line. - */ - (void) close(1); - if ((fd = open(_PATH_DEVNULL, O_WRONLY)) != 1) { - if (fd < 0) { - syslog(LOG_ERR, "open /dev/null: %m"); - exit(1); - } - (void) dup2(fd, 1); - (void) close(fd); - } - (void) dup2(1, 2); - - /* - * Run login and logout scripts as root (real and effective); - * current route(8) is setuid root, and checks the real uid - * to see whether changes are allowed (or just "route get"). - */ - (void) setuid(0); - if (s = system(logincmd)) { - syslog(LOG_ERR, "%s login failed: exit status %d from %s", - loginname, s, loginfile); - (void) ioctl(0, TIOCSETD, (caddr_t)&odisc); - exit(6); - } - - /* twiddle thumbs until we get a signal */ - while (1) - sigpause(0); - - /* NOTREACHED */ -} diff --git a/startslip.tproj/Makefile.preamble b/startslip.tproj/Makefile.preamble deleted file mode 100644 index dc05194..0000000 --- a/startslip.tproj/Makefile.preamble +++ /dev/null @@ -1,2 +0,0 @@ -OTHER_GENERATED_OFILES = $(VERS_OFILE) --include ../Makefile.include diff --git a/startslip.tproj/startslip.1 b/startslip.tproj/startslip.1 deleted file mode 100644 index f12feab..0000000 --- a/startslip.tproj/startslip.1 +++ /dev/null @@ -1,105 +0,0 @@ -.\" Copyright (c) 1990, 1991, 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. -.\" -.\" @(#)startslip.1 8.1 (Berkeley) 6/5/93 -.\" -.Dd June 5, 1993 -.Dt STARTSLIP 1 -.Os BSD 4.4 -.Sh NAME -.Nm startslip -.Nd dial up and login to a slip server -.Sh SYNOPSIS -.Nm startslip -.Op Fl d -.Op Fl s Ar string -.Op Fl A Ar annexname -.Op Fl F Ar flowcontrol -.Ar device user passwd -.Sh DESCRIPTION -.Nm Startslip -opens the specified -.Ar device . -.Pp -Once carrier is asserted -.Nm startslip -attempts to login as the specified -.Ar user -with the given -.Ar password . -If successful, it puts the device into the slip line discipline. -If carrier drops and a -.Dv SIGHUP -is sent to -.Nm startslip , -it closes the device and attempts to repeat the dialup and login sequence. -.Pp -Available options: -.Bl -tag -width Ar -.It Fl d -.Nm Startslip -prints out debugging information about what it is trying to do. -.It Fl s Ar string -The optional -.Ar string -is written to -.Ar device . -For a dialup modem, -the string is used to specify a dial sequence. -.It Fl A Ar annexname -.Nm Startslip -assumes it is connecting to a Xylogics Annex box and engages in an -appropriate dialog using the -.Ar user -and -.Ar passwd -arguments. -The -.Ar annexname -argument is a string that is used to match against the Annex prompt -to determine when a connection has been established. -.It Fl F Ar flowcontrol -Determines the type of flow control used on -.Ar device . -Choices for -.Ar flowcontrol -are -``none'' for no flow control (the default), -``hw'' for hardware RTS/CTS flow control and -``sw'' for software XON/XOFF flow control. -.El -.Sh SEE ALSO -.Xr sliplogin 8 -.Sh HISTORY -The -.Nm startslip -appeared in -.Bx 4.4 . diff --git a/startslip.tproj/startslip.c b/startslip.tproj/startslip.c deleted file mode 100644 index f424137..0000000 --- a/startslip.tproj/startslip.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1990, 1991, 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. - */ - - -#include -#if BSD >= 199006 -#define POSIX -#endif -#ifdef POSIX -#include -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_BAUD B9600 -int speed = DEFAULT_BAUD; -#define FC_NONE 0 /* flow control: none */ -#define FC_SW 1 /* flow control: software (XON/XOFF) */ -#define FC_HW 2 /* flow control: hardware (RTS/CTS) */ -int flowcontrol = FC_NONE; -char *annex; -int hup; -int logged_in; -int wait_time = 60; /* then back off */ -#define MAXTRIES 6 /* w/60 sec and doubling, takes an hour */ -#define PIDFILE "/var/run/startslip.pid" - -#ifdef DEBUG -int debug = 1; -#undef LOG_ERR -#undef LOG_INFO -#define syslog fprintf -#define LOG_ERR stderr -#define LOG_INFO stderr -#else -int debug = 0; -#endif -#define printd if (debug) printf - -main(argc, argv) - int argc; - char **argv; -{ - extern char *optarg; - extern int optind; - char *cp, **ap; - int ch, disc; - int fd = -1; - void sighup(); - FILE *wfd = NULL, *pfd; - char *dialerstring = 0, buf[BUFSIZ]; - int first = 1, tries = 0; - int pausefirst = 0; - int pid; -#ifdef POSIX - struct termios t; -#else - struct sgttyb sgtty; -#endif - - while ((ch = getopt(argc, argv, "db:s:p:A:F:")) != EOF) - switch (ch) { - case 'd': - debug = 1; - break; -#ifdef POSIX - case 'b': - speed = atoi(optarg); - break; -#endif - case 'p': - pausefirst = atoi(optarg); - break; - case 's': - dialerstring = optarg; - break; - case 'A': - annex = optarg; - break; - case 'F': -#ifdef POSIX - if (strcmp(optarg, "none") == 0) - flowcontrol = FC_NONE; - else if (strcmp(optarg, "sw") == 0) - flowcontrol = FC_SW; - else if (strcmp(optarg, "hw") == 0) - flowcontrol = FC_HW; - else { - (void)fprintf(stderr, - "flow control: none, sw, hw\n"); - exit(1); - } - break; -#else - (void)fprintf(stderr, "flow control not supported\n"); - exit(1); -#endif - case '?': - default: - usage(); - } - argc -= optind; - argv += optind; - - if (argc != 3) - usage(); - - openlog("startslip", LOG_PID, LOG_DAEMON); - -#if BSD <= 43 - if (debug == 0 && (fd = open("/dev/tty", 0)) >= 0) { - ioctl(fd, TIOCNOTTY, 0); - close(fd); - fd = -1; - } -#endif - - if (debug) - setbuf(stdout, NULL); - - if (pfd = fopen(PIDFILE, "r")) { - pid = 0; - fscanf(pfd, "%d", &pid); - if (pid > 0) - kill(pid, SIGUSR1); - fclose(pfd); - } -restart: - logged_in = 0; - if (++tries > MAXTRIES) { - syslog(LOG_ERR, "exiting after %d tries\n", tries); - /* ??? - if (first) - */ - exit(1); - } - - /* - * We may get a HUP below, when the parent (session leader/ - * controlling process) exits; ignore HUP until into new session. - */ - signal(SIGHUP, SIG_IGN); - hup = 0; - if (fork() > 0) { - if (pausefirst) - sleep(pausefirst); - if (first) - printd("parent exit\n"); - exit(0); - } - pausefirst = 0; -#ifdef POSIX - if (setsid() == -1) - perror("setsid"); -#endif - pid = getpid(); - printd("restart: pid %d: ", pid); - if (pfd = fopen(PIDFILE, "w")) { - fprintf(pfd, "%d\n", pid); - fclose(pfd); - } - if (wfd) { - printd("fclose, "); - fclose(wfd); - wfd == NULL; - } - if (fd >= 0) { - printd("close, "); - close(fd); - sleep(5); - } - printd("open"); - if ((fd = open(argv[0], O_RDWR)) < 0) { - perror(argv[0]); - syslog(LOG_ERR, "open %s: %m\n", argv[0]); - if (first) - exit(1); - else { - sleep(wait_time * tries); - goto restart; - } - } - printd(" %d", fd); -#ifdef TIOCSCTTY - if (ioctl(fd, TIOCSCTTY, 0) < 0) - perror("ioctl (TIOCSCTTY)"); -#endif - signal(SIGHUP, sighup); - if (debug) { - if (ioctl(fd, TIOCGETD, &disc) < 0) - perror("ioctl(TIOCSETD)"); - printf(" (disc was %d)", disc); - } - disc = TTYDISC; - if (ioctl(fd, TIOCSETD, &disc) < 0) { - perror("ioctl(TIOCSETD)"); - syslog(LOG_ERR, "%s: ioctl (TIOCSETD 0): %m\n", - argv[0]); - } - printd(", ioctl"); -#ifdef POSIX - if (tcgetattr(fd, &t) < 0) { - perror("tcgetattr"); - syslog(LOG_ERR, "%s: tcgetattr: %m\n", argv[0]); - exit(2); - } - cfmakeraw(&t); - t.c_iflag &= ~IMAXBEL; - switch (flowcontrol) { - case FC_HW: - t.c_cflag |= (CRTS_IFLOW|CCTS_OFLOW); - break; - case FC_SW: - t.c_iflag |= (IXON|IXOFF); - break; - case FC_NONE: - t.c_cflag &= ~(CRTS_IFLOW|CCTS_OFLOW); - t.c_iflag &= ~(IXON|IXOFF); - break; - } - cfsetspeed(&t, speed); - if (tcsetattr(fd, TCSAFLUSH, &t) < 0) { - perror("tcsetattr"); - syslog(LOG_ERR, "%s: tcsetattr: %m\n", argv[0]); - if (first) - exit(2); - else { - sleep(wait_time * tries); - goto restart; - } - } -#else - if (ioctl(fd, TIOCGETP, &sgtty) < 0) { - perror("ioctl (TIOCGETP)"); - syslog(LOG_ERR, "%s: ioctl (TIOCGETP): %m\n", - argv[0]); - exit(2); - } - sgtty.sg_flags = RAW | ANYP; - sgtty.sg_erase = sgtty.sg_kill = 0377; - sgtty.sg_ispeed = sgtty.sg_ospeed = speed; - if (ioctl(fd, TIOCSETP, &sgtty) < 0) { - perror("ioctl (TIOCSETP)"); - syslog(LOG_ERR, "%s: ioctl (TIOCSETP): %m\n", - argv[0]); - if (first) - exit(2); - else { - sleep(wait_time * tries); - goto restart; - } - } -#endif - sleep(2); /* wait for flakey line to settle */ - if (hup) - goto restart; - - wfd = fdopen(fd, "w+"); - if (wfd == NULL) { - syslog(LOG_ERR, "can't fdopen slip line\n"); - exit(10); - } - setbuf(wfd, (char *)0); - if (dialerstring) { - printd(", send dialstring"); - fprintf(wfd, "%s\r", dialerstring); - } else - putc('\r', wfd); - printd("\n"); - - /* - * Log in - */ - printd("look for login: "); - for (;;) { - if (getline(buf, BUFSIZ, fd) == 0 || hup) { - sleep(wait_time * tries); - goto restart; - } - if (annex) { - if (bcmp(buf, annex, strlen(annex)) == 0) { - fprintf(wfd, "slip\r"); - printd("Sent \"slip\"\n"); - continue; - } - if (bcmp(&buf[1], "sername:", 8) == 0) { - fprintf(wfd, "%s\r", argv[1]); - printd("Sent login: %s\n", argv[1]); - continue; - } - if (bcmp(&buf[1], "assword:", 8) == 0) { - fprintf(wfd, "%s\r", argv[2]); - printd("Sent password: %s\n", argv[2]); - break; - } - } else { - if (bcmp(&buf[1], "ogin:", 5) == 0) { - fprintf(wfd, "%s\r", argv[1]); - printd("Sent login: %s\n", argv[1]); - continue; - } - if (bcmp(&buf[1], "assword:", 8) == 0) { - fprintf(wfd, "%s\r", argv[2]); - printd("Sent password: %s\n", argv[2]); - break; - } - } - } - - /* - * Security hack. Do not want private information such as the - * password and possible phone number to be left around. - * So we clobber the arguments. - */ - for (ap = argv - optind + 1; ap < argv + 3; ap++) - for (cp = *ap; *cp != 0; cp++) - *cp = '\0'; - - /* - * Attach - */ - printd("setd"); - disc = SLIPDISC; - if (ioctl(fd, TIOCSETD, &disc) < 0) { - perror("ioctl(TIOCSETD)"); - syslog(LOG_ERR, "%s: ioctl (TIOCSETD SLIP): %m\n", - argv[0]); - exit(1); - } - if (first && debug == 0) { - close(0); - close(1); - close(2); - (void) open("/dev/null", O_RDWR); - (void) dup2(0, 1); - (void) dup2(0, 2); - } - (void) system("ifconfig sl0 up"); - printd(", ready\n"); - if (!first) - syslog(LOG_INFO, "reconnected (%d tries).\n", tries); - first = 0; - tries = 0; - logged_in = 1; - while (hup == 0) { - sigpause(0L); - printd("sigpause return\n"); - } - goto restart; -} - -void -sighup() -{ - - printd("hup\n"); - if (hup == 0 && logged_in) - syslog(LOG_INFO, "hangup signal\n"); - hup = 1; -} - -getline(buf, size, fd) - char *buf; - int size, fd; -{ - register int i; - int ret; - - size--; - for (i = 0; i < size; i++) { - if (hup) - return (0); - if ((ret = read(fd, &buf[i], 1)) == 1) { - buf[i] &= 0177; - if (buf[i] == '\r' || buf[i] == '\0') - buf[i] = '\n'; - if (buf[i] != '\n' && buf[i] != ':') - continue; - buf[i + 1] = '\0'; - printd("Got %d: \"%s\"\n", i + 1, buf); - return (i+1); - } - if (ret <= 0) { - if (ret < 0) - perror("getline: read"); - else - fprintf(stderr, "read returned 0\n"); - buf[i] = '\0'; - printd("returning 0 after %d: \"%s\"\n", i, buf); - return (0); - } - } - return (0); -} - -usage() -{ - (void)fprintf(stderr, - "usage: startslip [-d] [-b speed] [-s string] [-A annexname] [-F flowcontrol] dev user passwd\n"); - exit(1); -} diff --git a/syslogd.tproj/syslogd.c b/syslogd.tproj/syslogd.c index 27cb99b..7de133b 100644 --- a/syslogd.tproj/syslogd.c +++ b/syslogd.tproj/syslogd.c @@ -209,6 +209,8 @@ int LogPort; /* port number for INET connections */ int Initialized = 0; /* set when we have initialized ourselves */ int MarkInterval = 20 * 60; /* interval between marks in seconds */ int MarkSeq = 0; /* mark sequence number */ +int NoAddressToName = 0; /* Do not convert address to name */ +int RcvSockBufSize = 42080; /* Our default receive socket buffer size */ void cfline __P((char *, struct filed *)); char *cvthname __P((struct sockaddr_in *)); @@ -237,7 +239,7 @@ main(argc, argv) FILE *fp; char *p, line[MSG_BSIZE + 1]; - while ((ch = getopt(argc, argv, "duf:m:p:")) != EOF) + while ((ch = getopt(argc, argv, "duf:m:p:ns:")) != EOF) switch(ch) { case 'd': /* debug */ Debug++; @@ -254,6 +256,13 @@ main(argc, argv) case 'p': /* path */ LogName = optarg; break; + case 'n': + NoAddressToName++; + break; + case 's': + if ((len = atoi(optarg)) > 0) + RcvSockBufSize = len; + break; case '?': default: usage(); @@ -297,6 +306,8 @@ main(argc, argv) dprintf("cannot create %s (%d)\n", LogName, errno); die(0); } + if (setsockopt(funix, SOL_SOCKET, SO_RCVBUF, &RcvSockBufSize, sizeof(int)) < 0) + logerror("setsockopt funix"); finet = socket(AF_INET, SOCK_DGRAM, 0); inetm = 0; if (finet >= 0) { @@ -319,6 +330,8 @@ main(argc, argv) inetm = FDMASK(finet); InetInuse = 1; } + if (setsockopt(finet, SOL_SOCKET, SO_RCVBUF, &RcvSockBufSize, sizeof(int)) < 0) + logerror("setsockopt finet"); } if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0) klogm = FDMASK(fklog); @@ -394,7 +407,7 @@ usage() { (void)fprintf(stderr, - "usage: syslogd [-f conffile] [-m markinterval] [-p logpath]\n"); + "usage: syslogd [-f conffile] [-m markinterval] [-p logpath] [-u] [-n] [-s size]\n"); exit(1); } @@ -807,13 +820,17 @@ cvthname(f) dprintf("Malformed from address\n"); return ("???"); } - hp = gethostbyaddr((char *)&f->sin_addr, - sizeof(struct in_addr), f->sin_family); - if (hp == 0) { - dprintf("Host name for your address (%s) unknown\n", - inet_ntoa(f->sin_addr)); - return (inet_ntoa(f->sin_addr)); + if (NoAddressToName) { + hp = 0; + } else { + hp = gethostbyaddr((char *)&f->sin_addr, + sizeof(struct in_addr), f->sin_family); + dprintf("Host name for your address (%s) unknown\n", + inet_ntoa(f->sin_addr)); } + if (hp == 0) + return (inet_ntoa(f->sin_addr)); + if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) *p = '\0'; return (hp->h_name); diff --git a/talk.tproj/Makefile b/talk.tproj/Makefile index de9a8fa..6a97894 100644 --- a/talk.tproj/Makefile +++ b/talk.tproj/Makefile @@ -26,7 +26,7 @@ MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /usr/bin WINDOWS_INSTALLDIR = /usr/bin PDO_UNIX_INSTALLDIR = /usr/bin -LIBS = +LIBS = -lcurses DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) diff --git a/talk.tproj/io.c b/talk.tproj/io.c index efd3c30..7d6fd55 100644 --- a/talk.tproj/io.c +++ b/talk.tproj/io.c @@ -128,9 +128,6 @@ talk() } } -extern int errno; -extern int sys_nerr; - /* * p_error prints the system error message on the standard location * on the screen and then exits. (i.e. a curses version of perror) diff --git a/telnet.tproj/Makefile b/telnet.tproj/Makefile index 0a096f6..a1b8b2a 100644 --- a/telnet.tproj/Makefile +++ b/telnet.tproj/Makefile @@ -13,7 +13,7 @@ PROJECTVERSION = 2.8 PROJECT_TYPE = Tool HFILES = externs.h fdset.h general.h krb4-proto.h ring.h types.h\ - defines.h + defines.h misc.h misc-proto.h CFILES = authenc.c commands.c main.c network.c ring.c sys_bsd.c\ telnet.c terminal.c tn3270.c utilities.c @@ -27,14 +27,14 @@ MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /usr/bin WINDOWS_INSTALLDIR = /usr/bin PDO_UNIX_INSTALLDIR = /usr/bin -LIBS = +LIBS = -lcurses -lkrb4 -lkrb5 -lipsec DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) -NEXTSTEP_PB_CFLAGS = -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK # -DAUTHENTICATION -DENCRYPTION -DKRB4 -WINDOWS_PB_CFLAGS = -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK # -DAUTHENTICATION -DENCRYPTION -DKRB4 -PDO_UNIX_PB_CFLAGS = -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK # -DAUTHENTICATION -DENCRYPTION -DKRB4 +NEXTSTEP_PB_CFLAGS = -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK -DAUTHENTICATION -DENCRYPTION -DKRB4 -DKRB5 -DSKEY -DIPSEC -DINET6 -DFORWARD +WINDOWS_PB_CFLAGS = -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK -DAUTHENTICATION -DENCRYPTION -DKRB4 -DKRB5 -DSKEY -DIPSEC -DINET6 -DFORWARD +PDO_UNIX_PB_CFLAGS = -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK -DAUTHENTICATION -DENCRYPTION -DKRB4 -DKRB5 -DSKEY -DIPSEC -DINET6 -DFORWARD NEXTSTEP_BUILD_OUTPUT_DIR = /$(USER)/BUILD diff --git a/telnet.tproj/authenc.c b/telnet.tproj/authenc.c index 9d5330d..c04bb7d 100644 --- a/telnet.tproj/authenc.c +++ b/telnet.tproj/authenc.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -54,13 +31,22 @@ * SUCH DAMAGE. */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/authenc.c,v 1.2.8.2 2002/04/13 10:59:08 markm Exp $"); +#endif + #ifndef lint -static char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ +static const char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; +#endif -#if defined(AUTHENTICATION) || defined(ENCRYPTION) +#ifdef AUTHENTICATION +#ifdef ENCRYPTION #include #include +#include +#include #include #include @@ -70,10 +56,8 @@ static char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93"; #include "defines.h" #include "types.h" - int -net_write(str, len) - unsigned char *str; - int len; +int +net_write(unsigned char *str, int len) { if (NETROOM() > len) { ring_supply_data(&netoring, str, len); @@ -84,8 +68,8 @@ net_write(str, len) return(0); } - void -net_encrypt() +void +net_encrypt(void) { #ifdef ENCRYPTION if (encrypt_output) @@ -95,40 +79,35 @@ net_encrypt() #endif /* ENCRYPTION */ } - int -telnet_spin() +int +telnet_spin(void) { return(-1); } - char * -telnet_getenv(val) - char *val; +char * +telnet_getenv(char *val) { return((char *)env_getvalue((unsigned char *)val)); } - char * -telnet_gets(prompt, result, length, echo) - char *prompt; - char *result; - int length; - int echo; +char * +telnet_gets(const char *prom, char *result, int length, int echo) { - extern char *getpass(); extern int globalmode; int om = globalmode; char *res; TerminalNewMode(-1); if (echo) { - printf("%s", prompt); + printf("%s", prom); res = fgets(result, length, stdin); - } else if (res = getpass(prompt)) { + } else if ((res = getpass(prom))) { strncpy(result, res, length); res = result; } TerminalNewMode(om); return(res); } -#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ +#endif /* ENCRYPTION */ +#endif /* AUTHENTICATION */ diff --git a/telnet.tproj/commands.c b/telnet.tproj/commands.c index 903bda3..849ed67 100644 --- a/telnet.tproj/commands.c +++ b/telnet.tproj/commands.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -54,35 +31,39 @@ * SUCH DAMAGE. */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/commands.c,v 1.12.2.5 2002/04/13 10:59:08 markm Exp $"); +#endif + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + #ifndef lint -static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95"; -#endif /* not lint */ +static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95"; +#endif -#if defined(unix) || defined(__APPLE__) #include -#if defined(CRAY) || defined(sysV88) -#include -#endif +#include #include -#else -#include -#endif /* defined(unix) || defined(__APPLE__) */ #include #include -#ifdef CRAY -#include -#endif /* CRAY */ -#include -#include #include -#include -#if !defined(__APPLE__) -#include -#endif +#include #include +#include +#include +#include +#include +#include +#include +#include #include +#include #include "general.h" @@ -91,20 +72,34 @@ static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95"; #include "externs.h" #include "defines.h" #include "types.h" +#include "misc.h" + +#ifdef AUTHENTICATION +#include +#endif +#ifdef ENCRYPTION +#include +#endif -#if !defined(CRAY) && !defined(sysV88) #include -# if (defined(vax) || defined(tahoe) || defined(hp300)) && !defined(ultrix) -# include -# endif /* vax */ -#endif /* !defined(CRAY) && !defined(sysV88) */ #include +#include +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif MAXHOSTNAMELEN -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif MAXHOSTNAMELEN +typedef int (*intrtn_t)(int, char **); +#ifdef AUTHENTICATION +extern int auth_togdebug(int); +#endif +#ifdef ENCRYPTION +extern int EncryptAutoEnc(int); +extern int EncryptAutoDec(int); +extern int EncryptDebug(int); +extern int EncryptVerbose(int); +#endif /* ENCRYPTION */ #if defined(IPPROTO_IP) && defined(IP_TOS) int tos = -1; #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ @@ -112,23 +107,23 @@ int tos = -1; char *hostname; static char _hostname[MAXHOSTNAMELEN]; -extern char *getenv(); - -extern int isprefix(); -extern char **genget(); -extern int Ambiguous(); - -typedef int (*intrtn_t)(); -#if __STDC__ -static call(intrtn_t routine, ...); -#else -static call(); +static int help(int, char **); +static int call(intrtn_t, ...); +static void cmdrc(char *, char *); +#ifdef INET6 +static int switch_af(struct addrinfo **); #endif +static int togglehelp(void); +static int send_tncmd(void (*)(int, int), const char *, char *); +static int setmod(int); +static int clearmode(int); +static int modehelp(void); +static int sourceroute(struct addrinfo *, char *, char **, int *, int *, int *); typedef struct { - char *name; /* command name */ - char *help; /* help string (NULL for no help) */ - int (*handler)(); /* routine which executes command */ + const char *name; /* command name */ + const char *help; /* help string (NULL for no help) */ + int (*handler)(int, char **); /* routine which executes command */ int needconnect; /* Do we need to be connected to execute? */ } Command; @@ -137,22 +132,51 @@ static char saveline[256]; static int margc; static char *margv[20]; - static void -makeargv() +#ifdef OPIE +#include +#define PATH_OPIEKEY "/usr/bin/opiekey" +static int +opie_calc(int argc, char *argv[]) +{ + int status; + + if(argc != 3) { + printf("%s sequence challenge\n", argv[0]); + return (0); + } + + switch(fork()) { + case 0: + execv(PATH_OPIEKEY, argv); + exit (1); + case -1: + perror("fork"); + break; + default: + (void) wait(&status); + if (WIFEXITED(status)) + return (WEXITSTATUS(status)); + } + return (0); +} +#endif + +static void +makeargv(void) { - register char *cp, *cp2, c; - register char **argp = margv; + char *cp, *cp2, c; + char **argp = margv; margc = 0; cp = line; if (*cp == '!') { /* Special case shell escape */ strcpy(saveline, line); /* save for shell command */ - *argp++ = "!"; /* No room in string to get this */ + *argp++ = strdup("!"); /* No room in string to get this */ margc++; cp++; } - while (c = *cp) { - register int inquote = 0; + while ((c = *cp)) { + int inquote = 0; while (isspace(c)) c = *++cp; if (c == '\0') @@ -194,11 +218,10 @@ makeargv() * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). */ - static -special(s) - register char *s; +static int +special(char *s) { - register char c; + char c; char b; switch (*s) { @@ -221,9 +244,8 @@ special(s) * Construct a control character sequence * for a special character. */ - static char * -control(c) - register cc_t c; +static const char * +control(cc_t c) { static char buf[5]; /* @@ -233,7 +255,7 @@ control(c) * was to assign "c" to an unsigned int variable... * Arggg.... */ - register unsigned int uic = (unsigned int)c; + unsigned int uic = (unsigned int)c; if (uic == 0x7f) return ("^?"); @@ -257,8 +279,6 @@ control(c) return (buf); } - - /* * The following are data structures and routines for * the "send" command. @@ -266,64 +286,61 @@ control(c) */ struct sendlist { - char *name; /* How user refers to it (case independent) */ - char *help; /* Help information (0 ==> no help) */ + const char *name; /* How user refers to it (case independent) */ + const char *help; /* Help information (0 ==> no help) */ int needconnect; /* Need to be connected */ int narg; /* Number of arguments */ - int (*handler)(); /* Routine to perform (for special ops) */ + int (*handler)(char *, ...); /* Routine to perform (for special ops) */ int nbyte; /* Number of bytes to send this command */ int what; /* Character to be sent (<0 ==> special) */ }; static int - send_esc P((void)), - send_help P((void)), - send_docmd P((char *)), - send_dontcmd P((char *)), - send_willcmd P((char *)), - send_wontcmd P((char *)); + send_esc(void), + send_help(void), + send_docmd(char *), + send_dontcmd(char *), + send_willcmd(char *), + send_wontcmd(char *); static struct sendlist Sendlist[] = { - { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, - { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, - { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, - { "break", 0, 1, 0, 0, 2, BREAK }, - { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, - { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, - { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, - { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, - { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, - { "intp", 0, 1, 0, 0, 2, IP }, - { "interrupt", 0, 1, 0, 0, 2, IP }, - { "intr", 0, 1, 0, 0, 2, IP }, - { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, - { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, - { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, - { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, - { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, - { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, - { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, - { "?", "Display send options", 0, 0, send_help, 0, 0 }, - { "help", 0, 0, 0, send_help, 0, 0 }, - { "do", 0, 0, 1, send_docmd, 3, 0 }, - { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, - { "will", 0, 0, 1, send_willcmd, 3, 0 }, - { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, - { 0 } + { "ao", "Send Telnet Abort output", 1, 0, NULL, 2, AO }, + { "ayt", "Send Telnet 'Are You There'", 1, 0, NULL, 2, AYT }, + { "brk", "Send Telnet Break", 1, 0, NULL, 2, BREAK }, + { "break", NULL, 1, 0, NULL, 2, BREAK }, + { "ec", "Send Telnet Erase Character", 1, 0, NULL, 2, EC }, + { "el", "Send Telnet Erase Line", 1, 0, NULL, 2, EL }, + { "escape", "Send current escape character",1, 0, (int (*)(char *, ...))send_esc, 1, 0 }, + { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, NULL, 2, GA }, + { "ip", "Send Telnet Interrupt Process",1, 0, NULL, 2, IP }, + { "intp", NULL, 1, 0, NULL, 2, IP }, + { "interrupt", NULL, 1, 0, NULL, 2, IP }, + { "intr", NULL, 1, 0, NULL, 2, IP }, + { "nop", "Send Telnet 'No operation'", 1, 0, NULL, 2, NOP }, + { "eor", "Send Telnet 'End of Record'", 1, 0, NULL, 2, EOR }, + { "abort", "Send Telnet 'Abort Process'", 1, 0, NULL, 2, ABORT }, + { "susp", "Send Telnet 'Suspend Process'",1, 0, NULL, 2, SUSP }, + { "eof", "Send Telnet End of File Character", 1, 0, NULL, 2, xEOF }, + { "synch", "Perform Telnet 'Synch operation'", 1, 0, (int (*)(char *, ...))dosynch, 2, 0 }, + { "getstatus", "Send request for STATUS", 1, 0, (int (*)(char *, ...))get_status, 6, 0 }, + { "?", "Display send options", 0, 0, (int (*)(char *, ...))send_help, 0, 0 }, + { "help", NULL, 0, 0, (int (*)(char *, ...))send_help, 0, 0 }, + { "do", NULL, 0, 1, (int (*)(char *, ...))send_docmd, 3, 0 }, + { "dont", NULL, 0, 1, (int (*)(char *, ...))send_dontcmd, 3, 0 }, + { "will", NULL, 0, 1, (int (*)(char *, ...))send_willcmd, 3, 0 }, + { "wont", NULL, 0, 1, (int (*)(char *, ...))send_wontcmd, 3, 0 }, + { NULL, NULL, 0, 0, NULL, 0, 0 } }; #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ sizeof(struct sendlist))) - static int -sendcmd(argc, argv) - int argc; - char **argv; +static int +sendcmd(int argc, char *argv[]) { int count; /* how many bytes we are going to need to send */ int i; - int question = 0; /* was at least one argument a question */ struct sendlist *s; /* pointer to current command */ int success = 0; int needconnect = 0; @@ -346,7 +363,7 @@ sendcmd(argc, argv) printf("Unknown send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; - } else if (Ambiguous(s)) { + } else if (Ambiguous((void *)s)) { printf("Ambiguous send argument '%s'\n'send ?' for help.\n", argv[i]); return 0; @@ -358,7 +375,7 @@ sendcmd(argc, argv) return 0; } count += s->nbyte; - if (s->handler == send_help) { + if ((void *)s->handler == (void *)send_help) { send_help(); return 0; } @@ -384,7 +401,7 @@ sendcmd(argc, argv) for (i = 1; i < argc; i++) { if ((s = GETSEND(argv[i])) == 0) { fprintf(stderr, "Telnet 'send' error - argument disappeared!\n"); - (void) quit(); + quit(); /*NOTREACHED*/ } if (s->handler) { @@ -400,50 +417,47 @@ sendcmd(argc, argv) return (count == success); } - static int -send_esc() +static int +send_esc(void) { NETADD(escape); return 1; } - static int -send_docmd(name) - char *name; +static int +send_docmd(char *name) { return(send_tncmd(send_do, "do", name)); } - static int +static int send_dontcmd(name) char *name; { return(send_tncmd(send_dont, "dont", name)); } - static int -send_willcmd(name) - char *name; + +static int +send_willcmd(char *name) { return(send_tncmd(send_will, "will", name)); } - static int -send_wontcmd(name) - char *name; + +static int +send_wontcmd(char *name) { return(send_tncmd(send_wont, "wont", name)); } - int -send_tncmd(func, cmd, name) - void (*func)(); - char *cmd, *name; +static int +send_tncmd(void (*func)(int, int), const char *cmd, char *name) { char **cpp; extern char *telopts[]; - register int val = 0; + int val = 0; if (isprefix(name, "help") || isprefix(name, "?")) { - register int col, len; + int col, len; printf("Usage: send %s \n", cmd); printf("\"value\" must be from 0 to 255\n"); @@ -471,7 +485,7 @@ send_tncmd(func, cmd, name) if (cpp) { val = cpp - telopts; } else { - register char *cp = name; + char *cp = name; while (*cp >= '0' && *cp <= '9') { val *= 10; @@ -496,8 +510,8 @@ send_tncmd(func, cmd, name) return 1; } - static int -send_help() +static int +send_help(void) { struct sendlist *s; /* pointer to current command */ for (s = Sendlist; s->name; s++) { @@ -512,15 +526,15 @@ send_help() * to by the arguments to the "toggle" command. */ - static int -lclchars() +static int +lclchars(void) { donelclchars = 1; return 1; } - static int -togdebug() +static int +togdebug(void) { #ifndef NOT43 if (net > 0 && @@ -529,7 +543,7 @@ togdebug() } #else /* NOT43 */ if (debug) { - if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) + if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) perror("setsockopt (SO_DEBUG)"); } else printf("Cannot turn off socket debugging\n"); @@ -538,8 +552,8 @@ togdebug() } - static int -togcrlf() +static int +togcrlf(void) { if (crlf) { printf("Will send carriage returns as telnet .\n"); @@ -551,9 +565,8 @@ togcrlf() int binmode; - static int -togbinary(val) - int val; +static int +togbinary(int val) { donebinarytoggle = 1; @@ -590,9 +603,8 @@ togbinary(val) return 1; } - static int -togrbinary(val) - int val; +static int +togrbinary(int val) { donebinarytoggle = 1; @@ -617,9 +629,8 @@ togrbinary(val) return 1; } - static int -togxbinary(val) - int val; +static int +togxbinary(int val) { donebinarytoggle = 1; @@ -644,24 +655,12 @@ togxbinary(val) return 1; } - -static int togglehelp P((void)); -#if defined(AUTHENTICATION) -extern int auth_togdebug P((int)); -#endif -#ifdef ENCRYPTION -extern int EncryptAutoEnc P((int)); -extern int EncryptAutoDec P((int)); -extern int EncryptDebug P((int)); -extern int EncryptVerbose P((int)); -#endif /* ENCRYPTION */ - struct togglelist { - char *name; /* name of toggle */ - char *help; /* help message */ - int (*handler)(); /* routine to do actual setting */ + const char *name; /* name of toggle */ + const char *help; /* help message */ + int (*handler)(int); /* routine to do actual setting */ int *variable; - char *actionexplanation; + const char *actionexplanation; }; static struct togglelist Togglelist[] = { @@ -675,7 +674,7 @@ static struct togglelist Togglelist[] = { 0, &autosynch, "send interrupt characters in urgent mode" }, -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION { "autologin", "automatic sending of login and/or authentication info", 0, @@ -731,7 +730,7 @@ static struct togglelist Togglelist[] = { 0 }, { "crlf", "sending carriage returns as telnet ", - togcrlf, + (int (*)(int))togcrlf, &crlf, 0 }, { "crmod", @@ -741,25 +740,13 @@ static struct togglelist Togglelist[] = { "map carriage return on output" }, { "localchars", "local recognition of certain control characters", - lclchars, + (int (*)(int))lclchars, &localchars, "recognize certain control characters" }, - { " ", "", 0 }, /* empty line */ -#if (defined(unix) || defined(__APPLE__)) && defined(TN3270) - { "apitrace", - "(debugging) toggle tracing of API transactions", - 0, - &apitrace, - "trace API transactions" }, - { "cursesdata", - "(debugging) toggle printing of hexadecimal curses data", - 0, - &cursesdata, - "print hexadecimal representation of curses data" }, -#endif /* (defined(unix) || defined(__APPLE__)) && defined(TN3270) */ + { " ", "", NULL, NULL, NULL }, /* empty line */ { "debug", "debugging", - togdebug, + (int (*)(int))togdebug, &debug, "turn on socket level debugging" }, { "netdata", @@ -777,24 +764,27 @@ static struct togglelist Togglelist[] = { 0, &showoptions, "show option processing" }, -#if defined(unix) || defined(__APPLE__) { "termdata", "(debugging) toggle printing of hexadecimal terminal data", 0, &termdata, "print hexadecimal representation of terminal traffic" }, -#endif /* defined(unix) || defined(__APPLE__) */ { "?", - 0, - togglehelp }, + NULL, + (int (*)(int))togglehelp, + NULL, + NULL }, + { NULL, NULL, NULL, NULL, NULL }, { "help", - 0, - togglehelp }, - { 0 } + NULL, + (int (*)(int))togglehelp, + NULL, + NULL }, + { NULL, NULL, NULL, NULL, NULL } }; - static int -togglehelp() +static int +togglehelp(void) { struct togglelist *c; @@ -811,9 +801,8 @@ togglehelp() return 0; } - static void -settogglehelp(set) - int set; +static void +settogglehelp(int set) { struct togglelist *c; @@ -831,10 +820,8 @@ settogglehelp(set) #define GETTOGGLE(name) (struct togglelist *) \ genget(name, (char **) Togglelist, sizeof(struct togglelist)) - static int -toggle(argc, argv) - int argc; - char *argv[]; +static int +toggle(int argc, char *argv[]) { int retval = 1; char *name; @@ -850,7 +837,7 @@ toggle(argc, argv) while (argc--) { name = *argv++; c = GETTOGGLE(name); - if (Ambiguous(c)) { + if (Ambiguous((void *)c)) { fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n", name); return 0; @@ -879,85 +866,54 @@ toggle(argc, argv) */ #ifdef USE_TERMIO -struct termio new_tc = { 0 }; +struct termio new_tc = { 0, 0, 0, 0, {}, 0, 0 }; #endif struct setlist { - char *name; /* name */ - char *help; /* help information */ - void (*handler)(); + const char *name; /* name */ + const char *help; /* help information */ + void (*handler)(char *); cc_t *charp; /* where it is located at */ }; static struct setlist Setlist[] = { #ifdef KLUDGELINEMODE - { "echo", "character to toggle local echoing on/off", 0, &echoc }, + { "echo", "character to toggle local echoing on/off", NULL, &echoc }, #endif - { "escape", "character to escape back to telnet command mode", 0, &escape }, + { "escape", "character to escape back to telnet command mode", NULL, &escape }, { "rlogin", "rlogin escape character", 0, &rlogin }, { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, - { " ", "" }, - { " ", "The following need 'localchars' to be toggled true", 0, 0 }, - { "flushoutput", "character to cause an Abort Output", 0, termFlushCharp }, - { "interrupt", "character to cause an Interrupt Process", 0, termIntCharp }, - { "quit", "character to cause an Abort process", 0, termQuitCharp }, - { "eof", "character to cause an EOF ", 0, termEofCharp }, - { " ", "" }, - { " ", "The following are for local editing in linemode", 0, 0 }, - { "erase", "character to use to erase a character", 0, termEraseCharp }, - { "kill", "character to use to erase a line", 0, termKillCharp }, - { "lnext", "character to use for literal next", 0, termLiteralNextCharp }, - { "susp", "character to cause a Suspend Process", 0, termSuspCharp }, - { "reprint", "character to use for line reprint", 0, termRprntCharp }, - { "worderase", "character to use to erase a word", 0, termWerasCharp }, - { "start", "character to use for XON", 0, termStartCharp }, - { "stop", "character to use for XOFF", 0, termStopCharp }, - { "forw1", "alternate end of line character", 0, termForw1Charp }, - { "forw2", "alternate end of line character", 0, termForw2Charp }, - { "ayt", "alternate AYT character", 0, termAytCharp }, - { 0 } + { " ", "", NULL, NULL }, + { " ", "The following need 'localchars' to be toggled true", NULL, NULL }, + { "flushoutput", "character to cause an Abort Output", NULL, termFlushCharp }, + { "interrupt", "character to cause an Interrupt Process", NULL, termIntCharp }, + { "quit", "character to cause an Abort process", NULL, termQuitCharp }, + { "eof", "character to cause an EOF ", NULL, termEofCharp }, + { " ", "", NULL, NULL }, + { " ", "The following are for local editing in linemode", NULL, NULL }, + { "erase", "character to use to erase a character", NULL, termEraseCharp }, + { "kill", "character to use to erase a line", NULL, termKillCharp }, + { "lnext", "character to use for literal next", NULL, termLiteralNextCharp }, + { "susp", "character to cause a Suspend Process", NULL, termSuspCharp }, + { "reprint", "character to use for line reprint", NULL, termRprntCharp }, + { "worderase", "character to use to erase a word", NULL, termWerasCharp }, + { "start", "character to use for XON", NULL, termStartCharp }, + { "stop", "character to use for XOFF", NULL, termStopCharp }, + { "forw1", "alternate end of line character", NULL, termForw1Charp }, + { "forw2", "alternate end of line character", NULL, termForw2Charp }, + { "ayt", "alternate AYT character", NULL, termAytCharp }, + { NULL, NULL, NULL, NULL } }; -#if defined(CRAY) && !defined(__STDC__) -/* Work around compiler bug in pcc 4.1.5 */ - void -_setlist_init() -{ -#ifndef KLUDGELINEMODE -#define N 5 -#else -#define N 6 -#endif - Setlist[N+0].charp = &termFlushChar; - Setlist[N+1].charp = &termIntChar; - Setlist[N+2].charp = &termQuitChar; - Setlist[N+3].charp = &termEofChar; - Setlist[N+6].charp = &termEraseChar; - Setlist[N+7].charp = &termKillChar; - Setlist[N+8].charp = &termLiteralNextChar; - Setlist[N+9].charp = &termSuspChar; - Setlist[N+10].charp = &termRprntChar; - Setlist[N+11].charp = &termWerasChar; - Setlist[N+12].charp = &termStartChar; - Setlist[N+13].charp = &termStopChar; - Setlist[N+14].charp = &termForw1Char; - Setlist[N+15].charp = &termForw2Char; - Setlist[N+16].charp = &termAytChar; -#undef N -} -#endif /* defined(CRAY) && !defined(__STDC__) */ - - static struct setlist * -getset(name) - char *name; +static struct setlist * +getset(char *name) { return (struct setlist *) genget(name, (char **) Setlist, sizeof(struct setlist)); } - void -set_escape_char(s) - char *s; +void +set_escape_char(char *s) { if (rlogin != _POSIX_VDISABLE) { rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; @@ -969,10 +925,8 @@ set_escape_char(s) } } - static int -setcmd(argc, argv) - int argc; - char *argv[]; +static int +setcmd(int argc, char *argv[]) { int value; struct setlist *ct; @@ -998,7 +952,7 @@ setcmd(argc, argv) fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n", argv[1]); return 0; - } else if (Ambiguous(c)) { + } else if (Ambiguous((void *)c)) { fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); return 0; @@ -1022,7 +976,7 @@ setcmd(argc, argv) } else if (argc != 3) { printf("Format is 'set Name Value'\n'set ?' for help.\n"); return 0; - } else if (Ambiguous(ct)) { + } else if (Ambiguous((void *)ct)) { fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); return 0; @@ -1042,14 +996,12 @@ setcmd(argc, argv) return 1; } - static int -unsetcmd(argc, argv) - int argc; - char *argv[]; +static int +unsetcmd(int argc, char *argv[]) { struct setlist *ct; struct togglelist *c; - register char *name; + char *name; if (argc < 2) { fprintf(stderr, @@ -1076,7 +1028,7 @@ unsetcmd(argc, argv) fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n", name); return 0; - } else if (Ambiguous(c)) { + } else if (Ambiguous((void *)c)) { fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); return 0; @@ -1090,7 +1042,7 @@ unsetcmd(argc, argv) } if (c->handler) (*c->handler)(0); - } else if (Ambiguous(ct)) { + } else if (Ambiguous((void *)ct)) { fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n", name); return 0; @@ -1112,18 +1064,19 @@ unsetcmd(argc, argv) #ifdef KLUDGELINEMODE extern int kludgelinemode; - static int -dokludgemode() +static int +dokludgemode(void) { kludgelinemode = 1; send_wont(TELOPT_LINEMODE, 1); send_dont(TELOPT_SGA, 1); send_dont(TELOPT_ECHO, 1); + return 1; } #endif - static int -dolinemode() +static int +dolinemode(void) { #ifdef KLUDGELINEMODE if (kludgelinemode) @@ -1134,8 +1087,8 @@ dolinemode() return 1; } - static int -docharmode() +static int +docharmode(void) { #ifdef KLUDGELINEMODE if (kludgelinemode) @@ -1147,9 +1100,8 @@ docharmode() return 1; } - static int -dolmmode(bit, on) - int bit, on; +static int +dolmmode(int bit, int on) { unsigned char c; extern int linemode; @@ -1168,63 +1120,61 @@ dolmmode(bit, on) return 1; } - int -setmode(bit) +static int +setmod(int bit) { return dolmmode(bit, 1); } - int -clearmode(bit) +static int +clearmode(int bit) { return dolmmode(bit, 0); } struct modelist { - char *name; /* command name */ - char *help; /* help string */ - int (*handler)(); /* routine which executes command */ + const char *name; /* command name */ + const char *help; /* help string */ + int (*handler)(int);/* routine which executes command */ int needconnect; /* Do we need to be connected to execute? */ int arg1; }; -extern int modehelp(); - static struct modelist ModeList[] = { - { "character", "Disable LINEMODE option", docharmode, 1 }, + { "character", "Disable LINEMODE option", (int (*)(int))docharmode, 1, 0 }, #ifdef KLUDGELINEMODE - { "", "(or disable obsolete line-by-line mode)", 0 }, + { "", "(or disable obsolete line-by-line mode)", NULL, 0, 0 }, #endif - { "line", "Enable LINEMODE option", dolinemode, 1 }, + { "line", "Enable LINEMODE option", (int (*)(int))dolinemode, 1, 0 }, #ifdef KLUDGELINEMODE - { "", "(or enable obsolete line-by-line mode)", 0 }, + { "", "(or enable obsolete line-by-line mode)", NULL, 0, 0 }, #endif - { "", "", 0 }, - { "", "These require the LINEMODE option to be enabled", 0 }, - { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, - { "+isig", 0, setmode, 1, MODE_TRAPSIG }, + { "", "", NULL, 0, 0 }, + { "", "These require the LINEMODE option to be enabled", NULL, 0, 0 }, + { "isig", "Enable signal trapping", setmod, 1, MODE_TRAPSIG }, + { "+isig", 0, setmod, 1, MODE_TRAPSIG }, { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, - { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, - { "+edit", 0, setmode, 1, MODE_EDIT }, + { "edit", "Enable character editing", setmod, 1, MODE_EDIT }, + { "+edit", 0, setmod, 1, MODE_EDIT }, { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, - { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB }, - { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB }, + { "softtabs", "Enable tab expansion", setmod, 1, MODE_SOFT_TAB }, + { "+softtabs", 0, setmod, 1, MODE_SOFT_TAB }, { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB }, - { "litecho", "Enable literal character echo", setmode, 1, MODE_LIT_ECHO }, - { "+litecho", 0, setmode, 1, MODE_LIT_ECHO }, + { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO }, + { "+litecho", 0, setmod, 1, MODE_LIT_ECHO }, { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO }, - { "help", 0, modehelp, 0 }, + { "help", 0, (int (*)(int))modehelp, 0, 0 }, #ifdef KLUDGELINEMODE - { "kludgeline", 0, dokludgemode, 1 }, + { "kludgeline", 0, (int (*)(int))dokludgemode, 1, 0 }, #endif - { "", "", 0 }, - { "?", "Print help information", modehelp, 0 }, - { 0 }, + { "", "", NULL, 0, 0 }, + { "?", "Print help information", (int (*)(int))modehelp, 0, 0 }, + { NULL, NULL, NULL, 0, 0 }, }; - int -modehelp() +static int +modehelp(void) { struct modelist *mt; @@ -1243,10 +1193,8 @@ modehelp() #define GETMODECMD(name) (struct modelist *) \ genget(name, (char **) ModeList, sizeof(struct modelist)) - static int -modecmd(argc, argv) - int argc; - char *argv[]; +static int +modecmd(int argc, char *argv[]) { struct modelist *mt; @@ -1255,7 +1203,7 @@ modecmd(argc, argv) printf("'mode ?' for help.\n"); } else if ((mt = GETMODECMD(argv[1])) == 0) { fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); - } else if (Ambiguous(mt)) { + } else if (Ambiguous((void *)mt)) { fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); } else if (mt->needconnect && !connected) { printf("?Need to be connected first.\n"); @@ -1271,10 +1219,8 @@ modecmd(argc, argv) * "display" command. */ - static int -display(argc, argv) - int argc; - char *argv[]; +static int +display(int argc, char *argv[]) { struct togglelist *tl; struct setlist *sl; @@ -1309,7 +1255,7 @@ display(argc, argv) for (i = 1; i < argc; i++) { sl = getset(argv[i]); tl = GETTOGGLE(argv[i]); - if (Ambiguous(sl) || Ambiguous(tl)) { + if (Ambiguous((void *)sl) || Ambiguous((void *)tl)) { printf("?Ambiguous argument '%s'.\n", argv[i]); return 0; } else if (!sl && !tl) { @@ -1342,12 +1288,10 @@ display(argc, argv) /* * Set the escape character. */ - static int -setescape(argc, argv) - int argc; - char *argv[]; +static int +setescape(int argc, char *argv[]) { - register char *arg; + char *arg; char buf[50]; printf( @@ -1362,16 +1306,12 @@ setescape(argc, argv) } if (arg[0] != '\0') escape = arg[0]; - if (!In3270) { - printf("Escape character is '%s'.\n", control(escape)); - } (void) fflush(stdout); return 1; } - /*VARARGS*/ - static int -togcrmod() +static int +togcrmod(void) { crmod = !crmod; printf("Deprecated usage - please use 'toggle crmod' in the future.\n"); @@ -1380,16 +1320,15 @@ togcrmod() return 1; } - /*VARARGS*/ - int -suspend() +static int +suspend(void) { #ifdef SIGTSTP setcommandmode(); { - long oldrows, oldcols, newrows, newcols, err; + long oldrows, oldcols, newrows, newcols, err_; - err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; + err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; (void) kill(0, SIGTSTP); /* * If we didn't get the window size before the SUSPEND, but we @@ -1397,7 +1336,7 @@ suspend() * we are set up for the right window size. */ if (TerminalWindowSize(&newrows, &newcols) && connected && - (err || ((oldrows != newrows) || (oldcols != newcols)))) { + (err_ || ((oldrows != newrows) || (oldcols != newcols)))) { sendnaws(); } } @@ -1410,18 +1349,14 @@ suspend() return 1; } -#if !defined(TN3270) - /*ARGSUSED*/ - int -shell(argc, argv) - int argc; - char *argv[]; +static int +shell(int argc, char *argv[] __unused) { - long oldrows, oldcols, newrows, newcols, err; + long oldrows, oldcols, newrows, newcols, err_; setcommandmode(); - err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; + err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; switch(vfork()) { case -1: perror("Fork failed\n"); @@ -1432,8 +1367,7 @@ shell(argc, argv) /* * Fire up the shell in the child. */ - register char *shellp, *shellname; - extern char *strrchr(); + const char *shellp, *shellname; shellp = getenv("SHELL"); if (shellp == NULL) @@ -1443,9 +1377,9 @@ shell(argc, argv) else shellname++; if (argc > 1) - execl(shellp, shellname, "-c", &saveline[1], 0); + execl(shellp, shellname, "-c", &saveline[1], (char *)0); else - execl(shellp, shellname, 0); + execl(shellp, shellname, (char *)0); perror("Execl"); _exit(1); } @@ -1453,22 +1387,16 @@ shell(argc, argv) (void)wait((int *)0); /* Wait for the shell to complete */ if (TerminalWindowSize(&newrows, &newcols) && connected && - (err || ((oldrows != newrows) || (oldcols != newcols)))) { + (err_ || ((oldrows != newrows) || (oldcols != newcols)))) { sendnaws(); } break; } return 1; } -#else /* !defined(TN3270) */ -extern int shell(); -#endif /* !defined(TN3270) */ - /*VARARGS*/ - static -bye(argc, argv) - int argc; /* Number of arguments */ - char *argv[]; /* arguments */ +static int +bye(int argc, char *argv[]) { extern int resettermname; @@ -1478,14 +1406,13 @@ bye(argc, argv) (void) NetClose(net); connected = 0; resettermname = 1; -#if defined(AUTHENTICATION) || defined(ENCRYPTION) +#ifdef AUTHENTICATION +#ifdef ENCRYPTION auth_encrypt_connect(connected); -#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ +#endif +#endif /* reset options */ tninit(); -#if defined(TN3270) - SetIn3270(); /* Get out of 3270 mode */ -#endif /* defined(TN3270) */ } if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { longjmp(toplevel, 1); @@ -1494,17 +1421,15 @@ bye(argc, argv) return 1; /* Keep lint, etc., happy */ } -/*VARARGS*/ -quit() +void +quit(void) { (void) call(bye, "bye", "fromquit", 0); Exit(0); - /*NOTREACHED*/ } -/*VARARGS*/ - int -logout() +static int +logout(void) { send_do(TELOPT_LOGOUT, 1); (void) netflush(); @@ -1517,28 +1442,28 @@ logout() */ struct slclist { - char *name; - char *help; - void (*handler)(); + const char *name; + const char *help; + void (*handler)(int); int arg; }; -static void slc_help(); +static void slc_help(void); struct slclist SlcList[] = { { "export", "Use local special character definitions", - slc_mode_export, 0 }, + (void (*)(int))slc_mode_export, 0 }, { "import", "Use remote special character definitions", slc_mode_import, 1 }, { "check", "Verify remote special character definitions", slc_mode_import, 0 }, - { "help", 0, slc_help, 0 }, - { "?", "Print help information", slc_help, 0 }, - { 0 }, + { "help", NULL, (void (*)(int))slc_help, 0 }, + { "?", "Print help information", (void (*)(int))slc_help, 0 }, + { NULL, NULL, NULL, 0 }, }; - static void -slc_help() +static void +slc_help(void) { struct slclist *c; @@ -1552,18 +1477,15 @@ slc_help() } } - static struct slclist * -getslc(name) - char *name; +static struct slclist * +getslc(char *name) { return (struct slclist *) genget(name, (char **) SlcList, sizeof(struct slclist)); } - static -slccmd(argc, argv) - int argc; - char *argv[]; +static int +slccmd(int argc, char *argv[]) { struct slclist *c; @@ -1578,7 +1500,7 @@ slccmd(argc, argv) argv[1]); return 0; } - if (Ambiguous(c)) { + if (Ambiguous((void *)c)) { fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]); return 0; @@ -1593,49 +1515,49 @@ slccmd(argc, argv) */ struct envlist { - char *name; - char *help; - void (*handler)(); + const char *name; + const char *help; + void (*handler)(unsigned char *, unsigned char *); int narg; }; extern struct env_lst * - env_define P((unsigned char *, unsigned char *)); + env_define(const unsigned char *, unsigned char *); extern void - env_undefine P((unsigned char *)), - env_export P((unsigned char *)), - env_unexport P((unsigned char *)), - env_send P((unsigned char *)), + env_undefine(unsigned char *), + env_export(const unsigned char *), + env_unexport(const unsigned char *), + env_send(unsigned char *), #if defined(OLD_ENVIRON) && defined(ENV_HACK) - env_varval P((unsigned char *)), + env_varval(unsigned char *), #endif - env_list P((void)); + env_list(void); static void - env_help P((void)); + env_help(void); struct envlist EnvList[] = { { "define", "Define an environment variable", - (void (*)())env_define, 2 }, + (void (*)(unsigned char *, unsigned char *))env_define, 2 }, { "undefine", "Undefine an environment variable", - env_undefine, 1 }, + (void (*)(unsigned char *, unsigned char *))env_undefine, 1 }, { "export", "Mark an environment variable for automatic export", - env_export, 1 }, + (void (*)(unsigned char *, unsigned char *))env_export, 1 }, { "unexport", "Don't mark an environment variable for automatic export", - env_unexport, 1 }, - { "send", "Send an environment variable", env_send, 1 }, + (void (*)(unsigned char *, unsigned char *))env_unexport, 1 }, + { "send", "Send an environment variable", (void (*)(unsigned char *, unsigned char *))env_send, 1 }, { "list", "List the current environment variables", - env_list, 0 }, + (void (*)(unsigned char *, unsigned char *))env_list, 0 }, #if defined(OLD_ENVIRON) && defined(ENV_HACK) { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", - env_varval, 1 }, + (void (*)(unsigned char *, unsigned char *))env_varval, 1 }, #endif - { "help", 0, env_help, 0 }, - { "?", "Print help information", env_help, 0 }, - { 0 }, + { "help", NULL, (void (*)(unsigned char *, unsigned char *))env_help, 0 }, + { "?", "Print help information", (void (*)(unsigned char *, unsigned char *))env_help, 0 }, + { NULL, NULL, NULL, 0 }, }; - static void -env_help() +static void +env_help(void) { struct envlist *c; @@ -1649,17 +1571,15 @@ env_help() } } - static struct envlist * -getenvcmd(name) - char *name; +static struct envlist * +getenvcmd(char *name) { return (struct envlist *) genget(name, (char **) EnvList, sizeof(struct envlist)); } -env_cmd(argc, argv) - int argc; - char *argv[]; +static int +env_cmd(int argc, char *argv[]) { struct envlist *c; @@ -1674,7 +1594,7 @@ env_cmd(argc, argv) argv[1]); return 0; } - if (Ambiguous(c)) { + if (Ambiguous((void *)c)) { fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n", argv[1]); return 0; @@ -1701,29 +1621,27 @@ struct env_lst { struct env_lst envlisthead; - struct env_lst * -env_find(var) - unsigned char *var; +static struct env_lst * +env_find(const unsigned char *var) { - register struct env_lst *ep; + struct env_lst *ep; for (ep = envlisthead.next; ep; ep = ep->next) { - if (strcmp((char *)ep->var, (char *)var) == 0) + if (strcmp(ep->var, var) == 0) return(ep); } return(NULL); } - void -env_init() +void +env_init(void) { extern char **environ; - register char **epp, *cp; - register struct env_lst *ep; - extern char *strchr(); + char **epp, *cp; + struct env_lst *ep; for (epp = environ; *epp; epp++) { - if (cp = strchr(*epp, '=')) { + if ((cp = strchr(*epp, '='))) { *cp = '\0'; ep = env_define((unsigned char *)*epp, (unsigned char *)cp+1); @@ -1755,20 +1673,19 @@ env_init() * don't export the USER variable. */ if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { - env_define((unsigned char *)"USER", ep->value); - env_unexport((unsigned char *)"USER"); + env_define("USER", ep->value); + env_unexport("USER"); } - env_export((unsigned char *)"DISPLAY"); - env_export((unsigned char *)"PRINTER"); + env_export("DISPLAY"); + env_export("PRINTER"); } - struct env_lst * -env_define(var, value) - unsigned char *var, *value; +struct env_lst * +env_define(const unsigned char *var, unsigned char *value) { - register struct env_lst *ep; + struct env_lst *ep; - if (ep = env_find(var)) { + if ((ep = env_find(var))) { if (ep->var) free(ep->var); if (ep->value) @@ -1783,18 +1700,17 @@ env_define(var, value) } ep->welldefined = opt_welldefined(var); ep->export = 1; - ep->var = (unsigned char *)strdup((char *)var); - ep->value = (unsigned char *)strdup((char *)value); + ep->var = strdup(var); + ep->value = strdup(value); return(ep); } - void -env_undefine(var) - unsigned char *var; +void +env_undefine(unsigned char *var) { - register struct env_lst *ep; + struct env_lst *ep; - if (ep = env_find(var)) { + if ((ep = env_find(var))) { ep->prev->next = ep->next; if (ep->next) ep->next->prev = ep->prev; @@ -1806,31 +1722,28 @@ env_undefine(var) } } - void -env_export(var) - unsigned char *var; +void +env_export(const unsigned char *var) { - register struct env_lst *ep; + struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) ep->export = 1; } - void -env_unexport(var) - unsigned char *var; +void +env_unexport(const unsigned char *var) { - register struct env_lst *ep; + struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) ep->export = 0; } - void -env_send(var) - unsigned char *var; +void +env_send(unsigned char *var) { - register struct env_lst *ep; + struct env_lst *ep; if (my_state_is_wont(TELOPT_NEW_ENVIRON) #ifdef OLD_ENVIRON @@ -1853,10 +1766,10 @@ env_send(var) env_opt_end(0); } - void -env_list() +void +env_list(void) { - register struct env_lst *ep; + struct env_lst *ep; for (ep = envlisthead.next; ep; ep = ep->next) { printf("%c %-20s %s\n", ep->export ? '*' : ' ', @@ -1864,18 +1777,17 @@ env_list() } } - unsigned char * -env_default(init, welldefined) - int init; +unsigned char * +env_default(int init, int welldefined) { static struct env_lst *nep = NULL; if (init) { nep = &envlisthead; - return; + return(NULL); } if (nep) { - while (nep = nep->next) { + while ((nep = nep->next)) { if (nep->export && (nep->welldefined == welldefined)) return(nep->var); } @@ -1883,21 +1795,19 @@ env_default(init, welldefined) return(NULL); } - unsigned char * -env_getvalue(var) - unsigned char *var; +unsigned char * +env_getvalue(const unsigned char *var) { - register struct env_lst *ep; + struct env_lst *ep; - if (ep = env_find(var)) + if ((ep = env_find(var))) return(ep->value); return(NULL); } #if defined(OLD_ENVIRON) && defined(ENV_HACK) - void -env_varval(what) - unsigned char *what; +void +env_varval(unsigned char *what) { extern int old_env_var, old_env_value, env_auto; int len = strlen((char *)what); @@ -1932,39 +1842,39 @@ unknown: } #endif -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION /* * The AUTHENTICATE command. */ struct authlist { - char *name; - char *help; - int (*handler)(); + const char *name; + const char *help; + int (*handler)(char *); int narg; }; extern int - auth_enable P((char *)), - auth_disable P((char *)), - auth_status P((void)); + auth_enable(char *), + auth_disable(char *), + auth_status(void); static int - auth_help P((void)); + auth_help(void); struct authlist AuthList[] = { { "status", "Display current status of authentication information", - auth_status, 0 }, + (int (*)(char *))auth_status, 0 }, { "disable", "Disable an authentication type ('auth disable ?' for more)", auth_disable, 1 }, { "enable", "Enable an authentication type ('auth enable ?' for more)", auth_enable, 1 }, - { "help", 0, auth_help, 0 }, - { "?", "Print help information", auth_help, 0 }, - { 0 }, + { "help", NULL, (int (*)(char *))auth_help, 0 }, + { "?", "Print help information", (int (*)(char *))auth_help, 0 }, + { NULL, NULL, NULL, 0 }, }; - static int -auth_help() +static int +auth_help(void) { struct authlist *c; @@ -1979,9 +1889,8 @@ auth_help() return 0; } -auth_cmd(argc, argv) - int argc; - char *argv[]; +int +auth_cmd(int argc, char *argv[]) { struct authlist *c; @@ -1998,7 +1907,7 @@ auth_cmd(argc, argv) argv[1]); return 0; } - if (Ambiguous(c)) { + if (Ambiguous((void *)c)) { fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]); return 0; @@ -2010,7 +1919,7 @@ auth_cmd(argc, argv) c->narg, c->narg == 1 ? "" : "s", c->name); return 0; } - return((*c->handler)(argv[2], argv[3])); + return((*c->handler)(argv[2])); } #endif @@ -2020,27 +1929,27 @@ auth_cmd(argc, argv) */ struct encryptlist { - char *name; - char *help; - int (*handler)(); + const char *name; + const char *help; + int (*handler)(char *, char *); int needconnect; int minarg; int maxarg; }; extern int - EncryptEnable P((char *, char *)), - EncryptDisable P((char *, char *)), - EncryptType P((char *, char *)), - EncryptStart P((char *)), - EncryptStartInput P((void)), - EncryptStartOutput P((void)), - EncryptStop P((char *)), - EncryptStopInput P((void)), - EncryptStopOutput P((void)), - EncryptStatus P((void)); + EncryptEnable(char *, char *), + EncryptDisable(char *, char *), + EncryptType(char *, char *), + EncryptStart(char *), + EncryptStartInput(void), + EncryptStartOutput(void), + EncryptStop(char *), + EncryptStopInput(void), + EncryptStopOutput(void), + EncryptStatus(void); static int - EncryptHelp P((void)); + EncryptHelp(void); struct encryptlist EncryptList[] = { { "enable", "Enable encryption. ('encrypt enable ?' for more)", @@ -2050,27 +1959,27 @@ struct encryptlist EncryptList[] = { { "type", "Set encryption type. ('encrypt type ?' for more)", EncryptType, 0, 1, 1 }, { "start", "Start encryption. ('encrypt start ?' for more)", - EncryptStart, 1, 0, 1 }, + (int (*)(char *, char *))EncryptStart, 1, 0, 1 }, { "stop", "Stop encryption. ('encrypt stop ?' for more)", - EncryptStop, 1, 0, 1 }, + (int (*)(char *, char *))EncryptStop, 1, 0, 1 }, { "input", "Start encrypting the input stream", - EncryptStartInput, 1, 0, 0 }, + (int (*)(char *, char *))EncryptStartInput, 1, 0, 0 }, { "-input", "Stop encrypting the input stream", - EncryptStopInput, 1, 0, 0 }, + (int (*)(char *, char *))EncryptStopInput, 1, 0, 0 }, { "output", "Start encrypting the output stream", - EncryptStartOutput, 1, 0, 0 }, + (int (*)(char *, char *))EncryptStartOutput, 1, 0, 0 }, { "-output", "Stop encrypting the output stream", - EncryptStopOutput, 1, 0, 0 }, + (int (*)(char *, char *))EncryptStopOutput, 1, 0, 0 }, { "status", "Display current status of authentication information", - EncryptStatus, 0, 0, 0 }, - { "help", 0, EncryptHelp, 0, 0, 0 }, - { "?", "Print help information", EncryptHelp, 0, 0, 0 }, - { 0 }, + (int (*)(char *, char *))EncryptStatus, 0, 0, 0 }, + { "help", NULL, (int (*)(char *, char *))EncryptHelp, 0, 0, 0 }, + { "?", "Print help information", (int (*)(char *, char *))EncryptHelp, 0, 0, 0 }, + { NULL, NULL, NULL, 0, 0, 0 }, }; - static int -EncryptHelp() +static int +EncryptHelp(void) { struct encryptlist *c; @@ -2085,9 +1994,8 @@ EncryptHelp() return 0; } -encrypt_cmd(argc, argv) - int argc; - char *argv[]; +static int +encrypt_cmd(int argc, char *argv[]) { struct encryptlist *c; @@ -2104,7 +2012,7 @@ encrypt_cmd(argc, argv) argv[1]); return 0; } - if (Ambiguous(c)) { + if (Ambiguous((void *)c)) { fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n", argv[1]); return 0; @@ -2130,52 +2038,16 @@ encrypt_cmd(argc, argv) } } return ((*c->handler)(argc > 0 ? argv[2] : 0, - argc > 1 ? argv[3] : 0, - argc > 2 ? argv[4] : 0)); + argc > 1 ? argv[3] : 0)); } #endif /* ENCRYPTION */ -#if (defined(unix) || defined(__APPLE__)) && defined(TN3270) - static void -filestuff(fd) - int fd; -{ - int res; - -#ifdef F_GETOWN - setconnmode(0); - res = fcntl(fd, F_GETOWN, 0); - setcommandmode(); - - if (res == -1) { - perror("fcntl"); - return; - } - printf("\tOwner is %d.\n", res); -#endif - - setconnmode(0); - res = fcntl(fd, F_GETFL, 0); - setcommandmode(); - - if (res == -1) { - perror("fcntl"); - return; - } -#ifdef notdef - printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); -#endif -} -#endif /* (defined(unix) || defined(__APPLE__)) && defined(TN3270) */ - /* * Print status about the connection. */ - /*ARGSUSED*/ - static -status(argc, argv) - int argc; - char *argv[]; +/*ARGSUSED*/ +static int +status(int argc, char *argv[]) { if (connected) { printf("Connected to %s.\n", hostname); @@ -2207,37 +2079,8 @@ status(argc, argv) } else { printf("No connection.\n"); } -# if !defined(TN3270) printf("Escape character is '%s'.\n", control(escape)); (void) fflush(stdout); -# else /* !defined(TN3270) */ - if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { - printf("Escape character is '%s'.\n", control(escape)); - } -# if defined(unix) || defined(__APPLE__) - if ((argc >= 2) && !strcmp(argv[1], "everything")) { - printf("SIGIO received %d time%s.\n", - sigiocount, (sigiocount == 1)? "":"s"); - if (In3270) { - printf("Process ID %d, process group %d.\n", - getpid(), getpgrp(getpid())); - printf("Terminal input:\n"); - filestuff(tin); - printf("Terminal output:\n"); - filestuff(tout); - printf("Network socket:\n"); - filestuff(net); - } - } - if (In3270 && transcom) { - printf("Transparent mode command is '%s'.\n", transcom); - } -# endif /* defined(unix) || defined(__APPLE__) */ - (void) fflush(stdout); - if (In3270) { - return 0; - } -# endif /* defined(TN3270) */ return 1; } @@ -2245,32 +2088,102 @@ status(argc, argv) /* * Function that gets called when SIGINFO is received. */ -ayt_status() +void +ayt_status(void) { (void) call(status, "status", "notmuch", 0); } #endif -unsigned long inet_addr(); - - int -tn(argc, argv) - int argc; - char *argv[]; -{ - register struct hostent *host = 0; - struct sockaddr_in sin; - struct servent *sp = 0; - unsigned long temp; - extern char *inet_ntoa(); -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) - char *srp = 0, *strrchr(); - unsigned long sourceroute(), srlen; +static const char * +sockaddr_ntop(struct sockaddr *sa) +{ + void *addr; + static char addrbuf[INET6_ADDRSTRLEN]; + + switch (sa->sa_family) { + case AF_INET: + addr = &((struct sockaddr_in *)sa)->sin_addr; + break; + case AF_UNIX: + addr = &((struct sockaddr_un *)sa)->sun_path; + break; +#ifdef INET6 + case AF_INET6: + addr = &((struct sockaddr_in6 *)sa)->sin6_addr; + break; #endif - char *cmd, *hostp = 0, *portp = 0, *user = 0; + default: + return NULL; + } + inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf)); + return addrbuf; +} + +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) +static int +setpolicy(int lnet, struct addrinfo *res, char *policy) +{ + char *buf; + int level; + int optname; - /* clear the socket address prior to use */ - memset((char *)&sin, 0, sizeof(sin)); + if (policy == NULL) + return 0; + + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) { + printf("%s\n", ipsec_strerror()); + return -1; + } + level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; + optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY; + if (setsockopt(lnet, level, optname, buf, ipsec_get_policylen(buf)) < 0){ + perror("setsockopt"); + return -1; + } + + free(buf); + return 0; +} +#endif + +#ifdef INET6 +/* + * When an Address Family related error happend, check if retry with + * another AF is possible or not. + * Return 1, if retry with another af is OK. Else, return 0. + */ +static int +switch_af(struct addrinfo **aip) +{ + int nextaf; + struct addrinfo *ai; + + ai = *aip; + nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET; + do + ai=ai->ai_next; + while (ai != NULL && ai->ai_family != nextaf); + *aip = ai; + if (*aip != NULL) { + return 1; + } + return 0; +} +#endif + +int +tn(int argc, char *argv[]) +{ + char *srp = 0; + int proto, opt; + int srlen; + int srcroute = 0, result; + char *cmd, *hostp = 0, *portp = 0, *user = 0; + char *src_addr = NULL; + struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL; + int error = 0, af_error = 0; if (connected) { printf("?Already connected to %s\n", hostname); @@ -2303,6 +2216,14 @@ tn(argc, argv) autologin = 1; continue; } + if (strcmp(*argv, "-s") == 0) { + --argc; ++argv; + if (argc == 0) + goto usage; + src_addr = *argv++; + --argc; + continue; + } if (hostp == 0) { hostp = *argv++; --argc; @@ -2314,117 +2235,170 @@ tn(argc, argv) continue; } usage: - printf("usage: %s [-l user] [-a] host-name [port]\n", cmd); + printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd); setuid(getuid()); return 0; } if (hostp == 0) goto usage; -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) - if (hostp[0] == '@' || hostp[0] == '!') { - if ((hostname = strrchr(hostp, ':')) == NULL) - hostname = strrchr(hostp, '@'); - hostname++; - srp = 0; - temp = sourceroute(hostp, &srp, &srlen); - if (temp == 0) { - herror(srp); - setuid(getuid()); - return 0; - } else if (temp == -1) { - printf("Bad source route option: %s\n", hostp); - setuid(getuid()); - return 0; - } else { - sin.sin_addr.s_addr = temp; - sin.sin_family = AF_INET; - } - } else { -#endif - temp = inet_addr(hostp); - if (temp != (unsigned long) -1) { - sin.sin_addr.s_addr = temp; - sin.sin_family = AF_INET; - (void) strcpy(_hostname, hostp); - hostname = _hostname; - } else { - host = gethostbyname(hostp); - if (host) { - sin.sin_family = host->h_addrtype; -#if defined(h_addr) /* In 4.3, this is a #define */ - memmove((caddr_t)&sin.sin_addr, - host->h_addr_list[0], host->h_length); -#else /* defined(h_addr) */ - memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length); -#endif /* defined(h_addr) */ - strncpy(_hostname, host->h_name, sizeof(_hostname)); - _hostname[sizeof(_hostname)-1] = '\0'; - hostname = _hostname; - } else { - herror(hostp); + if (src_addr != NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(src_addr, 0, &hints, &src_res); + if (error == EAI_NODATA) { + hints.ai_flags = 0; + error = getaddrinfo(src_addr, 0, &hints, &src_res); + } + if (error != 0) { + fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error)); + if (error == EAI_SYSTEM) + fprintf(stderr, "%s: %s\n", src_addr, strerror(errno)); setuid(getuid()); return 0; - } } -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) - } + src_res0 = src_res; + } + if (hostp[0] == '/') { + struct sockaddr_un su; + + if (strlen(hostp) >= sizeof(su.sun_path)) { + fprintf(stderr, "hostname too long for unix domain socket: %s", + hostp); + goto fail; + } + memset(&su, 0, sizeof su); + su.sun_family = AF_UNIX; + strncpy(su.sun_path, hostp, sizeof su.sun_path); + printf("Trying %s...\n", hostp); + net = socket(PF_UNIX, SOCK_STREAM, 0); + if ( net < 0) { + perror("socket"); + goto fail; + } + if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) { + perror(su.sun_path); + (void) NetClose(net); + goto fail; + } + goto af_unix; + } else if (hostp[0] == '@' || hostp[0] == '!') { + if ( +#ifdef INET6 + family == AF_INET6 || #endif - if (portp) { - if (*portp == '-') { - portp++; - telnetport = 1; - } else - telnetport = 0; - sin.sin_port = atoi(portp); - if (sin.sin_port == 0) { - sp = getservbyname(portp, "tcp"); - if (sp) - sin.sin_port = sp->s_port; - else { - printf("%s: bad port number\n", portp); - setuid(getuid()); - return 0; - } - } else { -#if !defined(htons) - u_short htons P((unsigned short)); -#endif /* !defined(htons) */ - sin.sin_port = htons(sin.sin_port); - } + (hostname = strrchr(hostp, ':')) == NULL) + hostname = strrchr(hostp, '@'); + hostname++; + srcroute = 1; + } else + hostname = hostp; + if (!portp) { + telnetport = 1; + portp = strdup("telnet"); + } else if (*portp == '-') { + portp++; + telnetport = 1; + } else + telnetport = 0; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(hostname, portp, &hints, &res); + if (error) { + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(hostname, portp, &hints, &res); + } + if (error != 0) { + fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error)); + if (error == EAI_SYSTEM) + fprintf(stderr, "%s: %s\n", hostname, strerror(errno)); + setuid(getuid()); + goto fail; + } + if (hints.ai_flags == AI_NUMERICHOST) { + /* hostname has numeric */ + int gni_err = 1; + + if (doaddrlookup) + gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len, + _hostname, sizeof(_hostname) - 1, NULL, 0, + NI_NAMEREQD); + if (gni_err != 0) + (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1); + _hostname[sizeof(_hostname)-1] = '\0'; + hostname = _hostname; } else { - if (sp == 0) { - sp = getservbyname("telnet", "tcp"); - if (sp == 0) { - fprintf(stderr, "telnet: tcp/telnet: unknown service\n"); - setuid(getuid()); - return 0; + /* hostname has FQDN */ + if (srcroute != 0) + (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1); + else if (res->ai_canonname != NULL) + strcpy(_hostname, res->ai_canonname); + else + (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1); + _hostname[sizeof(_hostname)-1] = '\0'; + hostname = _hostname; + } + res0 = res; + #ifdef INET6 + af_again: + #endif + if (srcroute != 0) { + static char hostbuf[BUFSIZ]; + + if (af_error == 0) { /* save intermediate hostnames for retry */ + strncpy(hostbuf, hostp, BUFSIZ - 1); + hostbuf[BUFSIZ - 1] = '\0'; + } else + hostp = hostbuf; + srp = 0; + result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt); + if (result == 0) { +#ifdef INET6 + if (family == AF_UNSPEC && af_error == 0 && + switch_af(&res) == 1) { + af_error = 1; + goto af_again; } - sin.sin_port = sp->s_port; +#endif + setuid(getuid()); + goto fail; + } else if (result == -1) { + printf("Bad source route option: %s\n", hostp); + setuid(getuid()); + goto fail; } - telnetport = 1; } - printf("Trying %s...\n", inet_ntoa(sin.sin_addr)); do { - net = socket(AF_INET, SOCK_STREAM, 0); + printf("Trying %s...\n", sockaddr_ntop(res->ai_addr)); + net = socket(res->ai_family, res->ai_socktype, res->ai_protocol); setuid(getuid()); if (net < 0) { +#ifdef INET6 + if (family == AF_UNSPEC && af_error == 0 && + switch_af(&res) == 1) { + af_error = 1; + goto af_again; + } +#endif perror("telnet: socket"); - return 0; + goto fail; } -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) - if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0) - perror("setsockopt (IP_OPTIONS)"); -#endif + if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0) + perror("setsockopt (source route)"); #if defined(IPPROTO_IP) && defined(IP_TOS) - { + if (res->ai_family == PF_INET) { # if defined(HAS_GETTOS) struct tosent *tp; if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) tos = tp->t_tos; # endif if (tos < 0) - tos = 020; /* Low Delay bit */ + tos = IPTOS_LOWDELAY; if (tos && (setsockopt(net, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) @@ -2437,46 +2411,82 @@ tn(argc, argv) perror("setsockopt (SO_DEBUG)"); } - if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) { -#if defined(h_addr) /* In 4.3, this is a #define */ - if (host && host->h_addr_list[1]) { - int oerrno = errno; + if (src_addr != NULL) { + for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next) + if (src_res->ai_family == res->ai_family) + break; + if (src_res == NULL) + src_res = src_res0; + if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) { +#ifdef INET6 + if (family == AF_UNSPEC && af_error == 0 && + switch_af(&res) == 1) { + af_error = 1; + (void) NetClose(net); + goto af_again; + } +#endif + perror("bind"); + (void) NetClose(net); + goto fail; + } + } +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + if (setpolicy(net, res, ipsec_policy_in) < 0) { + (void) NetClose(net); + goto fail; + } + if (setpolicy(net, res, ipsec_policy_out) < 0) { + (void) NetClose(net); + goto fail; + } +#endif - fprintf(stderr, "telnet: connect to address %s: ", - inet_ntoa(sin.sin_addr)); - errno = oerrno; - perror((char *)0); - host->h_addr_list++; - memmove((caddr_t)&sin.sin_addr, - host->h_addr_list[0], host->h_length); + if (connect(net, res->ai_addr, res->ai_addrlen) < 0) { + struct addrinfo *next; + + next = res->ai_next; + /* If already an af failed, only try same af. */ + if (af_error != 0) + while (next != NULL && next->ai_family != res->ai_family) + next = next->ai_next; + warn("connect to address %s", sockaddr_ntop(res->ai_addr)); + if (next != NULL) { + res = next; (void) NetClose(net); continue; } -#endif /* defined(h_addr) */ - perror("telnet: Unable to connect to remote host"); - return 0; + warnx("Unable to connect to remote host"); + (void) NetClose(net); + goto fail; } connected++; -#if defined(AUTHENTICATION) || defined(ENCRYPTION) +#ifdef AUTHENTICATION +#ifdef ENCRYPTION auth_encrypt_connect(connected); -#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ +#endif +#endif } while (connected == 0); + freeaddrinfo(res0); + if (src_res0 != NULL) + freeaddrinfo(src_res0); cmdrc(hostp, hostname); + af_unix: if (autologin && user == NULL) { struct passwd *pw; user = getenv("USER"); if (user == NULL || - (pw = getpwnam(user)) && pw->pw_uid != getuid()) { - if (pw = getpwuid(getuid())) + ((pw = getpwnam(user)) && pw->pw_uid != getuid())) { + if ((pw = getpwuid(getuid()))) user = pw->pw_name; else user = NULL; } } if (user) { - env_define((unsigned char *)"USER", (unsigned char *)user); - env_export((unsigned char *)"USER"); + env_define("USER", user); + env_export("USER"); } (void) call(status, "status", "notmuch", 0); if (setjmp(peerdied) == 0) @@ -2484,6 +2494,12 @@ tn(argc, argv) (void) NetClose(net); ExitString("Connection closed by foreign host.\n",1); /*NOTREACHED*/ + fail: + if (res0 != NULL) + freeaddrinfo(res0); + if (src_res0 != NULL) + freeaddrinfo(src_res0); + return 0; } #define HELPINDENT (sizeof ("connect")) @@ -2501,57 +2517,48 @@ static char togglestring[] ="toggle operating parameters ('toggle ?' for more)", slchelp[] = "change state of special charaters ('slc ?' for more)", displayhelp[] = "display operating parameters", -#if defined(TN3270) && (defined(unix) || defined(__APPLE__)) - transcomhelp[] = "specify Unix command for transparent mode pipe", -#endif /* defined(TN3270) && (defined(unix) || defined(__APPLE__)) */ -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION authhelp[] = "turn on (off) authentication ('auth ?' for more)", #endif #ifdef ENCRYPTION encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", #endif /* ENCRYPTION */ -#if defined(unix) || defined(__APPLE__) zhelp[] = "suspend telnet", -#endif /* defined(unix) || defined(__APPLE__) */ +#ifdef OPIE + opiehelp[] = "compute response to OPIE challenge", +#endif shellhelp[] = "invoke a subshell", envhelp[] = "change environment variables ('environ ?' for more)", modestring[] = "try to enter line or character mode ('mode ?' for more)"; -static int help(); - static Command cmdtab[] = { { "close", closehelp, bye, 1 }, - { "logout", logouthelp, logout, 1 }, + { "logout", logouthelp, (int (*)(int, char **))logout, 1 }, { "display", displayhelp, display, 0 }, { "mode", modestring, modecmd, 0 }, + { "telnet", openhelp, tn, 0 }, { "open", openhelp, tn, 0 }, - { "quit", quithelp, quit, 0 }, + { "quit", quithelp, (int (*)(int, char **))quit, 0 }, { "send", sendhelp, sendcmd, 0 }, { "set", sethelp, setcmd, 0 }, { "unset", unsethelp, unsetcmd, 0 }, { "status", statushelp, status, 0 }, { "toggle", togglestring, toggle, 0 }, { "slc", slchelp, slccmd, 0 }, -#if defined(TN3270) && (defined(unix) || defined(__APPLE__)) - { "transcom", transcomhelp, settranscom, 0 }, -#endif /* defined(TN3270) && (defined(unix) || defined(__APPLE__)) */ -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION { "auth", authhelp, auth_cmd, 0 }, #endif #ifdef ENCRYPTION { "encrypt", encrypthelp, encrypt_cmd, 0 }, #endif /* ENCRYPTION */ -#if defined(unix) || defined(__APPLE__) - { "z", zhelp, suspend, 0 }, -#endif /* defined(unix) || defined(__APPLE__) */ -#if defined(TN3270) + { "z", zhelp, (int (*)(int, char **))suspend, 0 }, { "!", shellhelp, shell, 1 }, -#else - { "!", shellhelp, shell, 0 }, -#endif { "environ", envhelp, env_cmd, 0 }, { "?", helphelp, help, 0 }, - { 0 } +#ifdef OPIE + { "opie", opiehelp, opie_calc, 0 }, +#endif + { NULL, NULL, NULL, 0 } }; static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; @@ -2560,8 +2567,8 @@ static char escapehelp[] = "deprecated command -- use 'set escape' instead"; static Command cmdtab2[] = { { "help", 0, help, 0 }, { "escape", escapehelp, setescape, 0 }, - { "crmod", crmodhelp, togcrmod, 0 }, - { 0 } + { "crmod", crmodhelp, (int (*)(int, char **))togcrmod, 0 }, + { NULL, NULL, NULL, 0 } }; @@ -2569,75 +2576,47 @@ static Command cmdtab2[] = { * Call routine with argc, argv set from args (terminated by 0). */ -#if __STDC__ -#include -#else -#include -#endif - - - /*VARARGS1*/ - static -#if __STDC__ +static int call(intrtn_t routine, ...) { -#else -call(va_alist) - va_dcl -{ - intrtn_t routine; -#endif va_list ap; char *args[100]; int argno = 0; -#if __STDC__ va_start(ap, routine); -#else - va_start(ap); - routine = (va_arg(ap, intrtn_t)); -#endif - while ((args[argno++] = va_arg(ap, char *)) != 0) { - ; - } + while ((args[argno++] = va_arg(ap, char *)) != 0); va_end(ap); return (*routine)(argno-1, args); } - static Command * -getcmd(name) - char *name; +static Command * +getcmd(char *name) { Command *cm; - if (cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))) + if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) return cm; return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); } - void -command(top, tbuf, cnt) - int top; - char *tbuf; - int cnt; +void +command(int top, const char *tbuf, int cnt) { - register Command *c; + Command *c; setcommandmode(); if (!top) { putchar('\n'); -#if defined(unix) || defined(__APPLE__) } else { (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); -#endif /* defined(unix) || defined(__APPLE__) */ } for (;;) { if (rlogin == _POSIX_VDISABLE) printf("%s> ", prompt); if (tbuf) { - register char *cp; + char *cp; cp = line; while (cnt > 0 && (*cp++ = *tbuf++) != '\n') cnt--; @@ -2666,7 +2645,7 @@ command(top, tbuf, cnt) break; } c = getcmd(margv[0]); - if (Ambiguous(c)) { + if (Ambiguous((void *)c)) { printf("?Ambiguous command\n"); continue; } @@ -2687,40 +2666,32 @@ command(top, tbuf, cnt) longjmp(toplevel, 1); /*NOTREACHED*/ } -#if defined(TN3270) - if (shell_active == 0) { - setconnmode(0); - } -#else /* defined(TN3270) */ setconnmode(0); -#endif /* defined(TN3270) */ } } /* * Help command. */ - static -help(argc, argv) - int argc; - char *argv[]; +static int +help(int argc, char *argv[]) { - register Command *c; + Command *c; if (argc == 1) { printf("Commands may be abbreviated. Commands are:\n\n"); for (c = cmdtab; c->name; c++) if (c->help) { - printf("%-*s\t%s\n", HELPINDENT, c->name, + printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help); } return 0; } - while (--argc > 0) { - register char *arg; + else while (--argc > 0) { + char *arg; arg = *++argv; c = getcmd(arg); - if (Ambiguous(c)) + if (Ambiguous((void *)c)) printf("?Ambiguous help command %s\n", arg); else if (c == (Command *)0) printf("?Invalid help command %s\n", arg); @@ -2733,25 +2704,25 @@ help(argc, argv) static char *rcname = 0; static char rcbuf[128]; -cmdrc(m1, m2) - char *m1, *m2; +void +cmdrc(char *m1, char *m2) { - register Command *c; + Command *c; FILE *rcfile; int gotmachine = 0; int l1 = strlen(m1); int l2 = strlen(m2); - char m1save[64]; + char m1save[MAXHOSTNAMELEN]; if (skiprc) return; - strcpy(m1save, m1); + strlcpy(m1save, m1, sizeof(m1save)); m1 = m1save; if (rcname == 0) { rcname = getenv("HOME"); - if (rcname) + if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf)) strcpy(rcbuf, rcname); else rcbuf[0] = '\0'; @@ -2793,7 +2764,7 @@ cmdrc(m1, m2) if (margv[0] == 0) continue; c = getcmd(margv[0]); - if (Ambiguous(c)) { + if (Ambiguous((void *)c)) { printf("?Ambiguous command: %s\n", margv[0]); continue; } @@ -2813,8 +2784,6 @@ cmdrc(m1, m2) fclose(rcfile); } -#if defined(IP_OPTIONS) && defined(IPPROTO_IP) - /* * Source route is handed in as * [!]@hop1@hop2...[@|:]dst @@ -2828,6 +2797,10 @@ cmdrc(m1, m2) * be the address to connect() to. * * Arguments: + * + * res: ponter to addrinfo structure which contains sockaddr to + * the host to connect to. + * * arg: pointer to route list to decipher * * cpp: If *cpp is not equal to NULL, this is a @@ -2837,9 +2810,18 @@ cmdrc(m1, m2) * lenp: pointer to an integer that contains the * length of *cpp if *cpp != NULL. * + * protop: pointer to an integer that should be filled in with + * appropriate protocol for setsockopt, as socket + * protocol family. + * + * optp: pointer to an integer that should be filled in with + * appropriate option for setsockopt, as socket protocol + * family. + * * Return values: * - * Returns the address of the host to connect to. If the + * If the return value is 1, then all operations are + * successful. If the * return value is -1, there was a syntax error in the * option, either unknown characters, or too many hosts. * If the return value is 0, one of the hostnames in the @@ -2853,87 +2835,114 @@ cmdrc(m1, m2) * *lenp: This will be filled in with how long the option * pointed to by *cpp is. * + * *protop: This will be filled in with appropriate protocol for + * setsockopt, as socket protocol family. + * + * *optp: This will be filled in with appropriate option for + * setsockopt, as socket protocol family. */ - unsigned long -sourceroute(arg, cpp, lenp) - char *arg; - char **cpp; - int *lenp; -{ - static char lsr[44]; -#ifdef sysV88 - static IOPTN ipopt; +static int +sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop, int *optp) +{ + static char buf[1024 + ALIGNBYTES]; /*XXX*/ + char *cp, *cp2, *lsrp, *ep; + struct sockaddr_in *_sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; + struct cmsghdr *cmsg; #endif - char *cp, *cp2, *lsrp, *lsrep; - register int tmp; - struct in_addr sin_addr; - register struct hostent *host = 0; - register char c; + struct addrinfo hints, *res; + int error; + char c; /* * Verify the arguments, and make sure we have * at least 7 bytes for the option. */ if (cpp == NULL || lenp == NULL) - return((unsigned long)-1); - if (*cpp != NULL && *lenp < 7) - return((unsigned long)-1); + return -1; + if (*cpp != NULL) { + switch (res->ai_family) { + case AF_INET: + if (*lenp < 7) + return -1; + break; +#ifdef INET6 + case AF_INET6: + if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) + + sizeof(struct in6_addr))) + return -1; + break; +#endif + } + } /* * Decide whether we have a buffer passed to us, * or if we need to use our own static buffer. */ if (*cpp) { lsrp = *cpp; - lsrep = lsrp + *lenp; + ep = lsrp + *lenp; } else { - *cpp = lsrp = lsr; - lsrep = lsrp + 44; + *cpp = lsrp = (char *)ALIGN(buf); + ep = lsrp + 1024; } cp = arg; +#ifdef INET6 + if (ai->ai_family == AF_INET6) { + cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0); + if (*cp != '@') + return -1; + *protop = IPPROTO_IPV6; + *optp = IPV6_PKTOPTIONS; + } else +#endif + { /* * Next, decide whether we have a loose source * route or a strict source route, and fill in * the begining of the option. */ -#ifndef sysV88 if (*cp == '!') { cp++; *lsrp++ = IPOPT_SSRR; } else *lsrp++ = IPOPT_LSRR; -#else - if (*cp == '!') { - cp++; - ipopt.io_type = IPOPT_SSRR; - } else - ipopt.io_type = IPOPT_LSRR; -#endif if (*cp != '@') - return((unsigned long)-1); + return -1; -#ifndef sysV88 lsrp++; /* skip over length, we'll fill it in later */ *lsrp++ = 4; -#endif + *protop = IPPROTO_IP; + *optp = IP_OPTIONS; + } cp++; - - sin_addr.s_addr = 0; - + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ai->ai_family; + hints.ai_socktype = SOCK_STREAM; for (c = 0;;) { - if (c == ':') + if ( +#ifdef INET6 + ai->ai_family != AF_INET6 && +#endif + c == ':') cp2 = 0; - else for (cp2 = cp; c = *cp2; cp2++) { + else for (cp2 = cp; (c = *cp2); cp2++) { if (c == ',') { *cp2++ = '\0'; if (*cp2 == '@') cp2++; } else if (c == '@') { *cp2++ = '\0'; - } else if (c == ':') { + } else if ( +#ifdef INET6 + ai->ai_family != AF_INET6 && +#endif + c == ':') { *cp2++ = '\0'; } else continue; @@ -2942,21 +2951,32 @@ sourceroute(arg, cpp, lenp) if (!c) cp2 = 0; - if ((tmp = inet_addr(cp)) != -1) { - sin_addr.s_addr = tmp; - } else if (host = gethostbyname(cp)) { -#if defined(h_addr) - memmove((caddr_t)&sin_addr, - host->h_addr_list[0], host->h_length); -#else - memmove((caddr_t)&sin_addr, host->h_addr, host->h_length); -#endif - } else { + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(cp, NULL, &hints, &res); + if (error == EAI_NODATA) { + hints.ai_flags = 0; + error = getaddrinfo(cp, NULL, &hints, &res); + } + if (error != 0) { + fprintf(stderr, "%s: %s\n", cp, gai_strerror(error)); + if (error == EAI_SYSTEM) + fprintf(stderr, "%s: %s\n", cp, + strerror(errno)); *cpp = cp; return(0); } - memmove(lsrp, (char *)&sin_addr, 4); +#ifdef INET6 + if (res->ai_family == AF_INET6) { + sin6 = (struct sockaddr_in6 *)res->ai_addr; + inet6_rthdr_add(cmsg, &sin6->sin6_addr, + IPV6_RTHDR_LOOSE); + } else +#endif + { + _sin = (struct sockaddr_in *)res->ai_addr; + memcpy(lsrp, (char *)&_sin->sin_addr, 4); lsrp += 4; + } if (cp2) cp = cp2; else @@ -2964,27 +2984,34 @@ sourceroute(arg, cpp, lenp) /* * Check to make sure there is space for next address */ - if (lsrp + 4 > lsrep) - return((unsigned long)-1); - } -#ifndef sysV88 +#ifdef INET6 + if (res->ai_family == AF_INET6) { + if (((char *)CMSG_DATA(cmsg) + + sizeof(struct ip6_rthdr) + + ((inet6_rthdr_segments(cmsg) + 1) * + sizeof(struct in6_addr))) > ep) + return -1; + } else +#endif + if (lsrp + 4 > ep) + return -1; + freeaddrinfo(res); + } +#ifdef INET6 + if (res->ai_family == AF_INET6) { + inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); + *lenp = cmsg->cmsg_len; + } else +#endif + { if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { *cpp = 0; *lenp = 0; - return((unsigned long)-1); + return -1; } *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ *lenp = lsrp - *cpp; -#else - ipopt.io_len = lsrp - *cpp; - if (ipopt.io_len <= 5) { /* Is 3 better ? */ - *cpp = 0; - *lenp = 0; - return((unsigned long)-1); - } - *lenp = sizeof(ipopt); - *cpp = (char *) &ipopt; -#endif - return(sin_addr.s_addr); + } + freeaddrinfo(res); + return 1; } -#endif diff --git a/telnet.tproj/defines.h b/telnet.tproj/defines.h index 51a9283..070770f 100644 --- a/telnet.tproj/defines.h +++ b/telnet.tproj/defines.h @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -54,16 +31,11 @@ * SUCH DAMAGE. * * @(#)defines.h 8.1 (Berkeley) 6/6/93 + * $FreeBSD: src/crypto/telnet/telnet/defines.h,v 1.1.1.1.8.1 2002/04/13 10:59:08 markm Exp $ */ #define settimer(x) clocks.x = clocks.system++ -#if !defined(TN3270) - -#define SetIn3270() - -#endif /* !defined(TN3270) */ - #define NETADD(c) { *netoring.supply = c; ring_supplied(&netoring, 1); } #define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } #define NETBYTES() (ring_full_count(&netoring)) diff --git a/telnet.tproj/externs.h b/telnet.tproj/externs.h index 006efac..afa6fd3 100644 --- a/telnet.tproj/externs.h +++ b/telnet.tproj/externs.h @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -54,6 +31,7 @@ * SUCH DAMAGE. * * @(#)externs.h 8.3 (Berkeley) 5/30/95 + * $FreeBSD: src/crypto/telnet/telnet/externs.h,v 1.4.2.2 2002/04/13 10:59:08 markm Exp $ */ #ifndef BSD @@ -61,7 +39,7 @@ #endif /* - * ucb stdio.h defines BSD as something wierd + * ucb stdio.h defines BSD as something weird */ #if defined(sun) && defined(__svr4__) #define BSD 43 @@ -75,26 +53,13 @@ #include #include -#if defined(CRAY) && !defined(NO_BSD_SETJMP) -#include -#endif -#ifndef FILIO_H #include -#else -#include -#endif -#ifdef CRAY -# include -#endif /* CRAY */ +#include #ifdef USE_TERMIO # ifndef VINTR -# ifdef SYSV_TERMIO -# include -# else -# include -# define termio termios -# endif +# include # endif +# define termio termios #endif #if defined(NO_CC_T) || !defined(USE_TERMIO) # if !defined(USE_TERMIO) @@ -104,10 +69,14 @@ typedef unsigned char cc_t; # endif #endif -#ifndef NO_STRING_H #include -#else -#include + +#if defined(IPSEC) +#include +#if defined(IPSEC_POLICY_IPSEC) +extern char *ipsec_policy_in; +extern char *ipsec_policy_out; +#endif #endif #ifndef _POSIX_VDISABLE @@ -123,10 +92,6 @@ typedef unsigned char cc_t; #define SUBBUFSIZE 256 -#ifndef CRAY -extern int errno; /* outside this world */ -#endif /* !CRAY */ - #if !defined(P) # ifdef __STDC__ # define P(x) x @@ -139,10 +104,10 @@ extern int autologin, /* Autologin enabled */ skiprc, /* Don't process the ~/.telnetrc file */ eight, /* use eight bit mode (binary in and/or out */ + family, /* address family of peer */ flushout, /* flush output */ connected, /* Are we connected to the other side? */ globalmode, /* Mode tty should be in */ - In3270, /* Are we in 3270 mode? */ telnetport, /* Are we connected to the telnet port? */ localflow, /* Flow control handled locally */ restartany, /* If flow control, restart output on any character */ @@ -161,14 +126,10 @@ extern int crmod, netdata, /* Print out network data flow */ prettydump, /* Print "netdata" output in user readable format */ -#if defined(unix) || defined(__APPLE__) -#if defined(TN3270) - cursesdata, /* Print out curses data flow */ - apitrace, /* Trace API transactions */ -#endif /* defined(TN3270) */ termdata, /* Print out terminal data flow */ -#endif /* defined(unix) || defined(__APPLE__) */ - debug; /* Debug level */ + debug, /* Debug level */ + doaddrlookup, /* do a reverse lookup? */ + clienteof; /* Client received EOF */ extern cc_t escape; /* Escape to command mode */ extern cc_t rlogin; /* Rlogin mode escape character */ @@ -187,8 +148,8 @@ extern char options[], /* All the little options */ *hostname; /* Who are we connected to? */ #ifdef ENCRYPTION -extern void (*encrypt_output) P((unsigned char *, int)); -extern int (*decrypt_input) P((int)); +extern void (*encrypt_output)(unsigned char *, int); +extern int (*decrypt_input)(int); #endif /* ENCRYPTION */ /* @@ -253,85 +214,129 @@ extern int (*decrypt_input) P((int)); #define set_his_want_state_dont set_my_want_state_wont #define set_his_want_state_wont set_my_want_state_dont +#if defined(USE_TERMIO) +#define SIG_FUNC_RET void +#else +#define SIG_FUNC_RET int +#endif + +#ifdef SIGINFO +extern SIG_FUNC_RET + ayt_status(void); +#endif extern FILE *NetTrace; /* Where debugging output goes */ extern unsigned char NetTraceFile[]; /* Name of file where debugging output goes */ extern void - SetNetTrace P((char *)); /* Function to change where debugging goes */ + SetNetTrace(char *); /* Function to change where debugging goes */ extern jmp_buf peerdied, toplevel; /* For error conditions. */ extern void - command P((int, char *, int)), - Dump P((int, unsigned char *, int)), - init_3270 P((void)), - printoption P((char *, int, int)), - printsub P((int, unsigned char *, int)), - sendnaws P((void)), - setconnmode P((int)), - setcommandmode P((void)), - setneturg P((void)), - sys_telnet_init P((void)), - telnet P((char *)), - tel_enter_binary P((int)), - TerminalFlushOutput P((void)), - TerminalNewMode P((int)), - TerminalRestoreState P((void)), - TerminalSaveState P((void)), - tninit P((void)), - upcase P((char *)), - willoption P((int)), - wontoption P((int)); + command(int, const char *, int), + Dump(char, unsigned char *, int), + env_init(void), + Exit(int), + ExitString(const char *, int), + init_network(void), + init_sys(void), + init_telnet(void), + init_terminal(void), + intp(void), + optionstatus(void), + printoption(const char *, int, int), + printsub(char, unsigned char *, int), + quit(void), + sendabort(void), + sendbrk(void), + sendeof(void), + sendsusp(void), + sendnaws(void), + sendayt(void), + setconnmode(int), + setcommandmode(void), + set_escape_char(char *s), + setneturg(void), + sys_telnet_init(void), + telnet(char *), + tel_enter_binary(int), + tel_leave_binary(int), + TerminalFlushOutput(void), + TerminalNewMode(int), + TerminalRestoreState(void), + TerminalSaveState(void), + TerminalDefaultChars(void), + TerminalSpeeds(long *, long *), + tninit(void), + upcase(char *), + willoption(int), + wontoption(int); extern void - send_do P((int, int)), - send_dont P((int, int)), - send_will P((int, int)), - send_wont P((int, int)); + send_do(int, int), + send_dont(int, int), + send_will(int, int), + send_wont(int, int); extern void - lm_will P((unsigned char *, int)), - lm_wont P((unsigned char *, int)), - lm_do P((unsigned char *, int)), - lm_dont P((unsigned char *, int)), - lm_mode P((unsigned char *, int, int)); + lm_will(unsigned char *, int), + lm_wont(unsigned char *, int), + lm_do(unsigned char *, int), + lm_dont(unsigned char *, int), + lm_mode(unsigned char *, int, int); extern void - slc_init P((void)), - slcstate P((void)), - slc_mode_export P((void)), - slc_mode_import P((int)), - slc_import P((int)), - slc_export P((void)), - slc P((unsigned char *, int)), - slc_check P((void)), - slc_start_reply P((void)), - slc_add_reply P((int, int, int)), - slc_end_reply P((void)); + slc_init(void), + slcstate(void), + slc_mode_export(void), + slc_mode_import(int), + slc_import(int), + slc_export(void), + slc(unsigned char *, int), + slc_check(void), + slc_start_reply(void), + slc_add_reply(unsigned char, unsigned char, cc_t), + slc_end_reply(void); extern int - slc_update P((void)); + getconnmode(void), + opt_welldefined(const char *), + NetClose(int), + netflush(void), + process_rings(int, int, int, int, int, int), + rlogin_susp(void), + SetSockOpt(int, int, int, int), + slc_update(void), + stilloob(void), + telrcv(void), + TerminalRead(char *, int), + TerminalWrite(char *, int), + TerminalAutoFlush(void), + TerminalWindowSize(long *, long *), + TerminalSpecialChars(int), + tn(int, char **), + ttyflush(int); extern void - env_opt P((unsigned char *, int)), - env_opt_start P((void)), - env_opt_start_info P((void)), - env_opt_add P((unsigned char *)), - env_opt_end P((int)); + env_opt(unsigned char *, int), + env_opt_start(void), + env_opt_start_info(void), + env_opt_add(unsigned char *), + env_opt_end(int); extern unsigned char - *env_default P((int, int)), - *env_getvalue P((unsigned char *)); + *env_default(int, int), + *env_getvalue(const unsigned char *); extern int - get_status P((void)), - dosynch P((void)); + get_status(char *), + dosynch(char *); extern cc_t - *tcval P((int)); + *tcval(int); #ifndef USE_TERMIO @@ -435,7 +440,7 @@ extern cc_t termAytChar; # define termAytChar new_tc.c_cc[VSTATUS] #endif -# if !defined(CRAY) || defined(__STDC__) +# if defined(__STDC__) # define termEofCharp &termEofChar # define termEraseCharp &termEraseChar # define termIntCharp &termIntChar @@ -480,26 +485,7 @@ extern Ring ttyoring, ttyiring; -/* Tn3270 section */ -#if defined(TN3270) - -extern int - HaveInput, /* Whether an asynchronous I/O indication came in */ - noasynchtty, /* Don't do signals on I/O (SIGURG, SIGIO) */ - noasynchnet, /* Don't do signals on I/O (SIGURG, SIGIO) */ - sigiocount, /* Count of SIGIO receptions */ - shell_active; /* Subshell is active */ - -extern char - *Ibackp, /* Oldest byte of 3270 data */ - Ibuf[], /* 3270 buffer */ - *Ifrontp, /* Where next 3270 byte goes */ - tline[], - *transcom; /* Transparent command */ - -extern int - settranscom P((int, char**)); - extern void - inputAvailable P((int)); -#endif /* defined(TN3270) */ + xmitAO(void), + xmitEC(void), + xmitEL(void); diff --git a/telnet.tproj/fdset.h b/telnet.tproj/fdset.h index d0f290a..045bb72 100644 --- a/telnet.tproj/fdset.h +++ b/telnet.tproj/fdset.h @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. diff --git a/telnet.tproj/general.h b/telnet.tproj/general.h index 303ae14..4efa951 100644 --- a/telnet.tproj/general.h +++ b/telnet.tproj/general.h @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. diff --git a/telnet.tproj/main.c b/telnet.tproj/main.c index 94cbfc8..b19e735 100644 --- a/telnet.tproj/main.c +++ b/telnet.tproj/main.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -54,22 +31,33 @@ * SUCH DAMAGE. */ -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1988, 1990, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/main.c,v 1.4.2.5 2002/04/13 10:59:08 markm Exp $"); +#endif #ifndef lint -static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95"; -#endif /* not lint */ +static const char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95"; +#endif #include +#include +#include +#include +#include #include "ring.h" #include "externs.h" #include "defines.h" +#ifdef AUTHENTICATION +#include +#endif +#ifdef ENCRYPTION +#include +#endif + /* These values need to be the same as defined in libtelnet/kerberos5.c */ /* Either define them in both places, or put in some common header file. */ #define OPTS_FORWARD_CREDS 0x00000002 @@ -79,11 +67,18 @@ static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95"; #define FORWARD #endif +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) +char *ipsec_policy_in = NULL; +char *ipsec_policy_out = NULL; +#endif + +int family = AF_UNSPEC; + /* * Initialize variables. */ - void -tninit() +void +tninit(void) { init_terminal(); @@ -92,35 +87,26 @@ tninit() init_telnet(); init_sys(); - -#if defined(TN3270) - init_3270(); -#endif } - void -usage() +static void +usage(void) { fprintf(stderr, "Usage: %s %s%s%s%s\n", prompt, #ifdef AUTHENTICATION - "[-8] [-E] [-K] [-L] [-S tos] [-X atype] [-a] [-c] [-d] [-e char]", - "\n\t[-k realm] [-l user] [-f/-F] [-n tracefile] ", + "[-4] [-6] [-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-c] [-d]", + "\n\t[-e char] [-k realm] [-l user] [-f/-F] [-n tracefile] ", #else - "[-8] [-E] [-L] [-S tos] [-a] [-c] [-d] [-e char] [-l user]", - "\n\t[-n tracefile]", + "[-4] [-6] [-8] [-E] [-L] [-N] [-S tos] [-c] [-d]", + "\n\t[-e char] [-l user] [-n tracefile] ", #endif -#if defined(TN3270) && (defined(unix) || defined(__APPLE__)) -# ifdef AUTHENTICATION - "[-noasynch] [-noasynctty]\n\t[-noasyncnet] [-r] [-t transcom] ", -# else - "[-noasynch] [-noasynctty] [-noasyncnet] [-r]\n\t[-t transcom]", -# endif -#else - "[-r] ", + "[-r] [-s src_addr] [-u] ", +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + "[-P policy] " #endif #ifdef ENCRYPTION - "[-x] [host-name [port]]" + "[-y] [host-name [port]]" #else /* ENCRYPTION */ "[host-name [port]]" #endif /* ENCRYPTION */ @@ -132,27 +118,21 @@ usage() * main. Parse arguments, invoke the protocol or command parser. */ - -main(argc, argv) - int argc; - char *argv[]; +int +main(int argc, char *argv[]) { - extern char *optarg; - extern int optind; int ch; - char *user, *strrchr(); + char *user; + char *src_addr = NULL; #ifdef FORWARD extern int forward_flags; #endif /* FORWARD */ tninit(); /* Clear out things */ -#if defined(CRAY) && !defined(__STDC__) - _setlist_init(); /* Work around compiler bug */ -#endif TerminalSaveState(); - if (prompt = strrchr(argv[0], '/')) + if ((prompt = strrchr(argv[0], '/'))) ++prompt; else prompt = argv[0]; @@ -160,10 +140,35 @@ main(argc, argv) user = NULL; rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE; +#ifdef AUTHENTICATION + autologin = 1; +#else autologin = -1; +#endif - while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != EOF) { +#ifdef ENCRYPTION + encrypt_auto(1); + decrypt_auto(1); +#endif + +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) +#define IPSECOPT "P:" +#else +#define IPSECOPT +#endif + while ((ch = getopt(argc, argv, + "468EKLNS:X:acde:fFk:l:n:rs:t:uxy" IPSECOPT)) != -1) +#undef IPSECOPT + { switch(ch) { + case '4': + family = AF_INET; + break; +#ifdef INET6 + case '6': + family = AF_INET6; + break; +#endif case '8': eight = 3; /* binary output and input */ break; @@ -178,6 +183,9 @@ main(argc, argv) case 'L': eight |= 2; /* binary output only */ break; + case 'N': + doaddrlookup = 0; + break; case 'S': { #ifdef HAS_GETTOS @@ -201,7 +209,11 @@ main(argc, argv) #endif break; case 'a': +#ifdef AUTHENTICATION + /* It's the default now, so ignore */ +#else autologin = 1; +#endif break; case 'c': skiprc = 1; @@ -213,7 +225,8 @@ main(argc, argv) set_escape_char(optarg); break; case 'f': -#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) +#ifdef AUTHENTICATION +#if defined(KRB5) && defined(FORWARD) if (forward_flags & OPTS_FORWARD_CREDS) { fprintf(stderr, "%s: Only one of -f and -F allowed.\n", @@ -221,6 +234,11 @@ main(argc, argv) usage(); } forward_flags |= OPTS_FORWARD_CREDS; +#else + fprintf(stderr, + "%s: Warning: -f ignored, no Kerberos V5 support.\n", + prompt); +#endif #else fprintf(stderr, "%s: Warning: -f ignored, no Kerberos V5 support.\n", @@ -228,7 +246,8 @@ main(argc, argv) #endif break; case 'F': -#if defined(AUTHENTICATION) && defined(KRB5) && defined(FORWARD) +#ifdef AUTHENTICATION +#if defined(KRB5) && defined(FORWARD) if (forward_flags & OPTS_FORWARD_CREDS) { fprintf(stderr, "%s: Only one of -f and -F allowed.\n", @@ -237,6 +256,11 @@ main(argc, argv) } forward_flags |= OPTS_FORWARD_CREDS; forward_flags |= OPTS_FORWARDABLE_CREDS; +#else + fprintf(stderr, + "%s: Warning: -F ignored, no Kerberos V5 support.\n", + prompt); +#endif #else fprintf(stderr, "%s: Warning: -F ignored, no Kerberos V5 support.\n", @@ -244,12 +268,18 @@ main(argc, argv) #endif break; case 'k': -#if defined(AUTHENTICATION) && defined(KRB4) +#ifdef AUTHENTICATION +#if defined(KRB4) { extern char *dest_realm, dst_realm_buf[], dst_realm_sz; dest_realm = dst_realm_buf; (void)strncpy(dest_realm, optarg, dst_realm_sz); } +#else + fprintf(stderr, + "%s: Warning: -k ignored, no Kerberos V4 support.\n", + prompt); +#endif #else fprintf(stderr, "%s: Warning: -k ignored, no Kerberos V4 support.\n", @@ -257,48 +287,52 @@ main(argc, argv) #endif break; case 'l': +#ifdef AUTHENTICATION + /* This is the default now, so ignore it */ +#else autologin = 1; +#endif user = optarg; break; case 'n': -#if defined(TN3270) && (defined(unix) || defined(__APPLE__)) - /* distinguish between "-n oasynch" and "-noasynch" */ - if (argv[optind - 1][0] == '-' && argv[optind - 1][1] - == 'n' && argv[optind - 1][2] == 'o') { - if (!strcmp(optarg, "oasynch")) { - noasynchtty = 1; - noasynchnet = 1; - } else if (!strcmp(optarg, "oasynchtty")) - noasynchtty = 1; - else if (!strcmp(optarg, "oasynchnet")) - noasynchnet = 1; - } else -#endif /* defined(TN3270) && (defined(unix) || defined(__APPLE__)) */ SetNetTrace(optarg); break; case 'r': rlogin = '~'; break; - case 't': -#if defined(TN3270) && (defined(unix) || defined(__APPLE__)) - transcom = tline; - (void)strcpy(transcom, optarg); -#else + case 's': + src_addr = optarg; + break; + case 'u': + family = AF_UNIX; + break; + case 'x': +#ifndef ENCRYPTION fprintf(stderr, - "%s: Warning: -t ignored, no TN3270 support.\n", + "%s: Warning: -x ignored, no ENCRYPT support.\n", prompt); -#endif +#endif /* ENCRYPTION */ break; - case 'x': + case 'y': #ifdef ENCRYPTION - encrypt_auto(1); - decrypt_auto(1); -#else /* ENCRYPTION */ + encrypt_auto(0); + decrypt_auto(0); +#else fprintf(stderr, - "%s: Warning: -x ignored, no ENCRYPT support.\n", + "%s: Warning: -y ignored, no ENCRYPT support.\n", prompt); #endif /* ENCRYPTION */ break; +#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) + case 'P': + if (!strncmp("in", optarg, 2)) + ipsec_policy_in = strdup(optarg); + else if (!strncmp("out", optarg, 3)) + ipsec_policy_out = strdup(optarg); + else + usage(); + break; +#endif case '?': default: usage(); @@ -312,15 +346,19 @@ main(argc, argv) argv += optind; if (argc) { - char *args[7], **argp = args; + char *args[9], **argp = args; if (argc > 2) usage(); *argp++ = prompt; if (user) { - *argp++ = "-l"; + *argp++ = strdup("-l"); *argp++ = user; } + if (src_addr) { + *argp++ = strdup("-s"); + *argp++ = src_addr; + } *argp++ = argv[0]; /* host */ if (argc > 1) *argp++ = argv[1]; /* port */ @@ -335,11 +373,7 @@ main(argc, argv) } (void)setjmp(toplevel); for (;;) { -#ifdef TN3270 - if (shell_active) - shell_continue(); - else -#endif command(1, 0, 0); } + return 0; } diff --git a/ftpd.tproj/ls_extern.h b/telnet.tproj/misc-proto.h similarity index 51% rename from ftpd.tproj/ls_extern.h rename to telnet.tproj/misc-proto.h index 85a1adc..511a1bf 100644 --- a/ftpd.tproj/ls_extern.h +++ b/telnet.tproj/misc-proto.h @@ -30,31 +30,51 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * from: @(#)extern.h 8.1 (Berkeley) 5/31/93 - * $FreeBSD: src/bin/ls/extern.h,v 1.14 2000/07/04 23:09:23 assar Exp $ + * @(#)misc-proto.h 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/crypto/telnet/libtelnet/misc-proto.h,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $ */ -int acccmp __P((const FTSENT *, const FTSENT *)); -int revacccmp __P((const FTSENT *, const FTSENT *)); -int modcmp __P((const FTSENT *, const FTSENT *)); -int revmodcmp __P((const FTSENT *, const FTSENT *)); -int namecmp __P((const FTSENT *, const FTSENT *)); -int revnamecmp __P((const FTSENT *, const FTSENT *)); -int statcmp __P((const FTSENT *, const FTSENT *)); -int revstatcmp __P((const FTSENT *, const FTSENT *)); +/* + * Copyright (C) 1990 by the Massachusetts Institute of Technology + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#ifndef __MISC_PROTO__ +#define __MISC_PROTO__ -void printcol __P((DISPLAY *)); -void printlong __P((DISPLAY *)); -void printscol __P((DISPLAY *)); -void usage __P((void)); -int len_octal __P((const char *, int)); -int prn_octal __P((const char *)); -int prn_printable __P((const char *)); -#ifdef COLORLS -void parsecolors __P((char *cs)); -void colorquit __P((int)); +void auth_encrypt_init(char *, char *, const char *, int); +void auth_encrypt_connect(int); +void printd(const unsigned char *, int); -extern char *ansi_fgcol; -extern char *ansi_bgcol; -extern char *ansi_coloff; +int isprefix(char *, const char *); +char **genget(char *, char **, int); +int Ambiguous(char **); + +int getent(char *, const char *); +char *Getstr(const char *, char **); + +/* + * These functions are imported from the application + */ +int net_write(unsigned char *, int); +void net_encrypt(void); +int telnet_spin(void); +char *telnet_getenv(char *); +char *telnet_gets(const char *, char *, int, int); +void printsub(char, unsigned char *, int); #endif diff --git a/ftpd.tproj/pathnames.h b/telnet.tproj/misc.h similarity index 81% rename from ftpd.tproj/pathnames.h rename to telnet.tproj/misc.h index 24b7464..41ffa7f 100644 --- a/ftpd.tproj/pathnames.h +++ b/telnet.tproj/misc.h @@ -1,5 +1,5 @@ -/* - * Copyright (c) 1989, 1993 +/*- + * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,15 +30,13 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)pathnames.h 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/libexec/ftpd/pathnames.h,v 1.11 1999/08/28 00:09:31 peter Exp $ + * @(#)misc.h 8.1 (Berkeley) 6/4/93 */ -#include +extern char *UserNameRequested; +extern char *LocalHostName; +extern char *RemoteHostName; +extern int ConnectedCount; +extern int ReservedPort; -#define _PATH_FTPCHROOT "/etc/ftpchroot" -#define _PATH_FTPWELCOME "/etc/ftpwelcome" -#define _PATH_FTPLOGINMESG "/etc/ftpmotd" -#define _PATH_FTPHOSTS "/etc/ftphosts" -#define _PATH_FTPDSTATFILE "/var/log/ftpd" -#define _PATH_LS "/bin/ls" +#include "misc-proto.h" diff --git a/telnet.tproj/network.c b/telnet.tproj/network.c index 27cc7bd..800b896 100644 --- a/telnet.tproj/network.c +++ b/telnet.tproj/network.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -54,9 +31,15 @@ * SUCH DAMAGE. */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/network.c,v 1.2.8.2 2002/04/13 10:59:08 markm Exp $"); +#endif + #ifndef lint -static char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; -#endif /* not lint */ +static const char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; +#endif #include #include @@ -65,6 +48,7 @@ static char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93"; #include #include +#include #include "ring.h" @@ -79,8 +63,8 @@ unsigned char netobuf[2*BUFSIZ], netibuf[BUFSIZ]; * Initialize internal network data structures. */ - void -init_network() +void +init_network(void) { if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) { exit(1); @@ -97,10 +81,10 @@ init_network() * Telnet "synch" processing). */ - int -stilloob() +int +stilloob(void) { - static struct timeval timeout = { 0 }; + static struct timeval timeout = { 0, 0 }; fd_set excepts; int value; @@ -129,8 +113,8 @@ stilloob() * Sets "neturg" to the current location. */ - void -setneturg() +void +setneturg(void) { ring_mark(&netoring); } @@ -145,11 +129,10 @@ setneturg() * useful work. */ - - int -netflush() +int +netflush(void) { - register int n, n1; + int n, n1; #ifdef ENCRYPTION if (encrypt_output) diff --git a/telnet.tproj/ring.c b/telnet.tproj/ring.c index 6506ae1..d5e353f 100644 --- a/telnet.tproj/ring.c +++ b/telnet.tproj/ring.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -54,9 +31,15 @@ * SUCH DAMAGE. */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/ring.c,v 1.2.8.2 2002/04/13 10:59:08 markm Exp $"); +#endif + #ifndef lint -static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; -#endif /* not lint */ +static const char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; +#endif /* * This defines a structure for a ring buffer. @@ -69,8 +52,9 @@ static char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95"; * */ -#include #include +#include +#include #ifdef size_t #undef size_t @@ -116,16 +100,10 @@ static u_long ring_clock = 0; #define ring_full(d) (((d)->supply == (d)->consume) && \ ((d)->supplytime > (d)->consumetime)) - - - - /* Buffer state transition routines */ - ring_init(ring, buffer, count) -Ring *ring; - unsigned char *buffer; - int count; +int +ring_init(Ring *ring, unsigned char *buffer, int count) { memset((char *)ring, 0, sizeof *ring); @@ -148,9 +126,8 @@ Ring *ring; * Mark the most recently supplied byte. */ - void -ring_mark(ring) - Ring *ring; +void +ring_mark(Ring *ring) { ring->mark = ring_decrement(ring, ring->supply, 1); } @@ -159,9 +136,8 @@ ring_mark(ring) * Is the ring pointing to the mark? */ - int -ring_at_mark(ring) - Ring *ring; +int +ring_at_mark(Ring *ring) { if (ring->mark == ring->consume) { return 1; @@ -174,9 +150,8 @@ ring_at_mark(ring) * Clear any mark set on the ring. */ - void -ring_clear_mark(ring) - Ring *ring; +void +ring_clear_mark(Ring *ring) { ring->mark = 0; } @@ -184,10 +159,8 @@ ring_clear_mark(ring) /* * Add characters from current segment to ring buffer. */ - void -ring_supplied(ring, count) - Ring *ring; - int count; +void +ring_supplied(Ring *ring, int count) { ring->supply = ring_increment(ring, ring->supply, count); ring->supplytime = ++ring_clock; @@ -196,10 +169,8 @@ ring_supplied(ring, count) /* * We have just consumed "c" bytes. */ - void -ring_consumed(ring, count) - Ring *ring; - int count; +void +ring_consumed(Ring *ring, int count) { if (count == 0) /* don't update anything */ return; @@ -233,9 +204,8 @@ ring_consumed(ring, count) /* Number of bytes that may be supplied */ - int -ring_empty_count(ring) - Ring *ring; +int +ring_empty_count(Ring *ring) { if (ring_empty(ring)) { /* if empty */ return ring->size; @@ -245,9 +215,8 @@ ring_empty_count(ring) } /* number of CONSECUTIVE bytes that may be supplied */ - int -ring_empty_consecutive(ring) - Ring *ring; +int +ring_empty_consecutive(Ring *ring) { if ((ring->consume < ring->supply) || ring_empty(ring)) { /* @@ -267,9 +236,8 @@ ring_empty_consecutive(ring) * (but don't give more than enough to get to cross over set mark) */ - int -ring_full_count(ring) - Ring *ring; +int +ring_full_count(Ring *ring) { if ((ring->mark == 0) || (ring->mark == ring->consume)) { if (ring_full(ring)) { @@ -286,9 +254,8 @@ ring_full_count(ring) * Return the number of CONSECUTIVE bytes available for consuming. * However, don't return more than enough to cross over set mark. */ - int -ring_full_consecutive(ring) - Ring *ring; +int +ring_full_consecutive(Ring *ring) { if ((ring->mark == 0) || (ring->mark == ring->consume)) { if ((ring->supply < ring->consume) || ring_full(ring)) { @@ -308,51 +275,23 @@ ring_full_consecutive(ring) /* * Move data into the "supply" portion of of the ring buffer. */ - void -ring_supply_data(ring, buffer, count) - Ring *ring; - unsigned char *buffer; - int count; +void +ring_supply_data(Ring *ring, unsigned char *buffer, int count) { int i; while (count) { i = MIN(count, ring_empty_consecutive(ring)); - memmove(ring->supply, buffer, i); + memcpy(ring->supply, buffer, i); ring_supplied(ring, i); count -= i; buffer += i; } } -#ifdef notdef - -/* - * Move data from the "consume" portion of the ring buffer - */ - void -ring_consume_data(ring, buffer, count) - Ring *ring; - unsigned char *buffer; - int count; -{ - int i; - - while (count) { - i = MIN(count, ring_full_consecutive(ring)); - memmove(buffer, ring->consume, i); - ring_consumed(ring, i); - count -= i; - buffer += i; - } -} -#endif - #ifdef ENCRYPTION - void -ring_encrypt(ring, encryptor) - Ring *ring; - void (*encryptor)(); +void +ring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int)) { unsigned char *s, *c; diff --git a/telnet.tproj/ring.h b/telnet.tproj/ring.h index a9ef843..57b3ab4 100644 --- a/telnet.tproj/ring.h +++ b/telnet.tproj/ring.h @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -54,6 +31,7 @@ * SUCH DAMAGE. * * @(#)ring.h 8.1 (Berkeley) 6/6/93 + * $FreeBSD: src/crypto/telnet/telnet/ring.h,v 1.1.1.1.8.1 2002/04/13 10:59:08 markm Exp $ */ #if defined(P) @@ -95,34 +73,35 @@ typedef struct { /* Initialization routine */ extern int - ring_init P((Ring *ring, unsigned char *buffer, int count)); + ring_init(Ring *ring, unsigned char *buffer, int count); /* Data movement routines */ extern void - ring_supply_data P((Ring *ring, unsigned char *buffer, int count)); + ring_supply_data(Ring *ring, unsigned char *buffer, int count); #ifdef notdef extern void - ring_consume_data P((Ring *ring, unsigned char *buffer, int count)); + ring_consume_data(Ring *ring, unsigned char *buffer, int count); #endif /* Buffer state transition routines */ extern void - ring_supplied P((Ring *ring, int count)), - ring_consumed P((Ring *ring, int count)); + ring_supplied(Ring *ring, int count), + ring_consumed(Ring *ring, int count); /* Buffer state query routines */ extern int - ring_empty_count P((Ring *ring)), - ring_empty_consecutive P((Ring *ring)), - ring_full_count P((Ring *ring)), - ring_full_consecutive P((Ring *ring)); + ring_at_mark(Ring *), + ring_empty_count(Ring *ring), + ring_empty_consecutive(Ring *ring), + ring_full_count(Ring *ring), + ring_full_consecutive(Ring *ring); #ifdef ENCRYPTION extern void - ring_encrypt P((Ring *ring, void (*func)())), - ring_clearto P((Ring *ring)); + ring_encrypt(Ring *ring, void (*func)(unsigned char *, int)), + ring_clearto(Ring *ring); #endif /* ENCRYPTION */ extern void - ring_clear_mark(), - ring_mark(); + ring_clear_mark(Ring *), + ring_mark(Ring *); diff --git a/telnet.tproj/sys_bsd.c b/telnet.tproj/sys_bsd.c index 8455d4d..b5ea433 100644 --- a/telnet.tproj/sys_bsd.c +++ b/telnet.tproj/sys_bsd.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -54,42 +31,42 @@ * SUCH DAMAGE. */ +#include +#include +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/sys_bsd.c,v 1.2.8.4 2002/04/13 10:59:08 markm Exp $"); +#endif + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + #ifndef lint -static char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95"; -#endif /* not lint */ +static const char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95"; +#endif /* * The following routines try to encapsulate what is system dependent * (at least between 4.x and dos) which is used in telnet.c. */ - -#include #include -#include #include -#include +#include #include +#include +#include +#include #include #include "ring.h" - #include "fdset.h" - #include "defines.h" #include "externs.h" #include "types.h" -#if defined(CRAY) || (defined(USE_TERMIO) && !defined(SYSV_TERMIO)) -#define SIG_FUNC_RET void -#else -#define SIG_FUNC_RET int -#endif - -#ifdef SIGINFO -extern SIG_FUNC_RET ayt_status(); -#endif - int tout, /* Output file descriptor */ tin, /* Input file descriptor */ @@ -105,8 +82,7 @@ int olmode = 0; # define old_tc ottyb #else /* USE_TERMIO */ -struct termio old_tc = { 0 }; -extern struct termio new_tc; +struct termio old_tc = { 0, 0, 0, 0, {}, 0, 0 }; # ifndef TCSANOW # ifdef TCSETS @@ -137,34 +113,38 @@ extern struct termio new_tc; # endif #endif /* USE_TERMIO */ -static fd_set ibits, obits, xbits; +static fd_set *ibitsp, *obitsp, *xbitsp; +int fdsn; +#ifdef SIGINT +static SIG_FUNC_RET intr(int); +#endif /* SIGINT */ +#ifdef SIGQUIT +static SIG_FUNC_RET intr2(int); +#endif /* SIGQUIT */ +#ifdef SIGTSTP +static SIG_FUNC_RET susp(int); +#endif /* SIGTSTP */ +#ifdef SIGINFO +static SIG_FUNC_RET ayt(int); +#endif - void -init_sys() +void +init_sys(void) { tout = fileno(stdout); tin = fileno(stdin); - FD_ZERO(&ibits); - FD_ZERO(&obits); - FD_ZERO(&xbits); - errno = 0; } - - int -TerminalWrite(buf, n) - char *buf; - int n; +int +TerminalWrite(char *buf, int n) { return write(tout, buf, n); } - int -TerminalRead(buf, n) - char *buf; - int n; +int +TerminalRead(char *buf, int n) { return read(tin, buf, n); } @@ -173,8 +153,8 @@ TerminalRead(buf, n) * */ - int -TerminalAutoFlush() +int +TerminalAutoFlush(void) { #if defined(LNOFLSH) int flush; @@ -201,11 +181,8 @@ extern int kludgelinemode; * 1 Do add this character */ -extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk(); - - int -TerminalSpecialChars(c) - int c; +int +TerminalSpecialChars(int c) { if (c == termIntChar) { intp(); @@ -247,8 +224,8 @@ TerminalSpecialChars(c) * Flush output to the terminal */ - void -TerminalFlushOutput() +void +TerminalFlushOutput(void) { #ifdef TIOCFLUSH (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0); @@ -257,8 +234,8 @@ TerminalFlushOutput() #endif } - void -TerminalSaveState() +void +TerminalSaveState(void) { #ifndef USE_TERMIO ioctl(0, TIOCGETP, (char *)&ottyb); @@ -299,9 +276,8 @@ TerminalSaveState() #endif /* USE_TERMIO */ } - cc_t * -tcval(func) - register int func; +cc_t * +tcval(int func) { switch(func) { case SLC_IP: return(&termIntChar); @@ -342,8 +318,8 @@ tcval(func) } } - void -TerminalDefaultChars() +void +TerminalDefaultChars(void) { #ifndef USE_TERMIO ntc = otc; @@ -351,7 +327,7 @@ TerminalDefaultChars() nttyb.sg_kill = ottyb.sg_kill; nttyb.sg_erase = ottyb.sg_erase; #else /* USE_TERMIO */ - memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); + memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); # ifndef VDISCARD termFlushChar = CONTROL('O'); # endif @@ -376,13 +352,6 @@ TerminalDefaultChars() #endif /* USE_TERMIO */ } -#ifdef notdef -void -TerminalRestoreState() -{ -} -#endif - /* * TerminalNewMode - set up terminal to a specific mode. * MODE_ECHO: do local terminal echo @@ -405,10 +374,8 @@ TerminalRestoreState() * local/no signal mapping */ - - void -TerminalNewMode(f) - register int f; +void +TerminalNewMode(int f) { static int prevmode = 0; #ifndef USE_TERMIO @@ -483,10 +450,6 @@ TerminalNewMode(f) #else tmp_tc.c_lflag &= ~ECHO; tmp_tc.c_oflag &= ~ONLCR; -# ifdef notdef - if (crlf) - tmp_tc.c_iflag &= ~ICRNL; -# endif #endif } @@ -633,13 +596,12 @@ TerminalNewMode(f) } if (f != -1) { -#ifdef SIGTSTP - SIG_FUNC_RET susp(); -#endif /* SIGTSTP */ -#ifdef SIGINFO - SIG_FUNC_RET ayt(); +#ifdef SIGINT + (void) signal(SIGINT, intr); +#endif +#ifdef SIGQUIT + (void) signal(SIGQUIT, intr2); #endif - #ifdef SIGTSTP (void) signal(SIGTSTP, susp); #endif /* SIGTSTP */ @@ -686,9 +648,13 @@ TerminalNewMode(f) #endif } else { #ifdef SIGINFO - SIG_FUNC_RET ayt_status(); - - (void) signal(SIGINFO, ayt_status); + (void) signal(SIGINFO, (void (*)(int))ayt_status); +#endif +#ifdef SIGINT + (void) signal(SIGINT, SIG_DFL); +#endif +#ifdef SIGQUIT + (void) signal(SIGQUIT, SIG_DFL); #endif #ifdef SIGTSTP (void) signal(SIGTSTP, SIG_DFL); @@ -717,17 +683,8 @@ TerminalNewMode(f) tcsetattr(tin, TCSANOW, &tmp_tc); #endif -#if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) -# if !defined(sysV88) ioctl(tin, FIONBIO, (char *)&onoff); ioctl(tout, FIONBIO, (char *)&onoff); -# endif -#endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */ -#if defined(TN3270) - if (noasynchtty == 0) { - ioctl(tin, FIOASYNC, (char *)&onoff); - } -#endif /* defined(TN3270) */ } @@ -796,15 +753,13 @@ struct termspeeds { }; #endif /* DECODE_BAUD */ - void -TerminalSpeeds(ispeed, ospeed) - long *ispeed; - long *ospeed; +void +TerminalSpeeds(long *ispeed, long *ospeed) { #ifdef DECODE_BAUD - register struct termspeeds *tp; + struct termspeeds *tp; #endif /* DECODE_BAUD */ - register long in, out; + long in, out; out = cfgetospeed(&old_tc); in = cfgetispeed(&old_tc); @@ -827,9 +782,8 @@ TerminalSpeeds(ispeed, ospeed) #endif /* DECODE_BAUD */ } - int -TerminalWindowSize(rows, cols) - long *rows, *cols; +int +TerminalWindowSize(long *rows, long *cols) { #ifdef TIOCGWINSZ struct winsize ws; @@ -843,59 +797,34 @@ TerminalWindowSize(rows, cols) return 0; } - int -NetClose(fd) - int fd; +int +NetClose(int fd) { return close(fd); } - - void -NetNonblockingIO(fd, onoff) - int fd; - int onoff; +static void +NetNonblockingIO(int fd, int onoff) { ioctl(fd, FIONBIO, (char *)&onoff); } -#if defined(TN3270) - void -NetSigIO(fd, onoff) - int fd; - int onoff; -{ - ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */ -} - - void -NetSetPgrp(fd) - int fd; -{ - int myPid; - - myPid = getpid(); - fcntl(fd, F_SETOWN, myPid); -} -#endif /*defined(TN3270)*/ /* * Various signal handling routines. */ - /* ARGSUSED */ - SIG_FUNC_RET -deadpeer(sig) - int sig; +/* ARGSUSED */ +static SIG_FUNC_RET +deadpeer(int sig __unused) { setcommandmode(); longjmp(peerdied, -1); } - /* ARGSUSED */ - SIG_FUNC_RET -intr(sig) - int sig; +/* ARGSUSED */ +SIG_FUNC_RET +intr(int sig __unused) { if (localchars) { intp(); @@ -905,10 +834,9 @@ intr(sig) longjmp(toplevel, -1); } - /* ARGSUSED */ - SIG_FUNC_RET -intr2(sig) - int sig; +/* ARGSUSED */ +SIG_FUNC_RET +intr2(int sig __unused) { if (localchars) { #ifdef KLUDGELINEMODE @@ -922,10 +850,9 @@ intr2(sig) } #ifdef SIGTSTP - /* ARGSUSED */ - SIG_FUNC_RET -susp(sig) - int sig; +/* ARGSUSED */ +SIG_FUNC_RET +susp(int sig __unused) { if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) return; @@ -935,10 +862,9 @@ susp(sig) #endif #ifdef SIGWINCH - /* ARGSUSED */ - SIG_FUNC_RET -sendwin(sig) - int sig; +/* ARGSUSED */ +static SIG_FUNC_RET +sendwin(int sig __unused) { if (connected) { sendnaws(); @@ -947,10 +873,9 @@ sendwin(sig) #endif #ifdef SIGINFO - /* ARGSUSED */ - SIG_FUNC_RET -ayt(sig) - int sig; +/* ARGSUSED */ +SIG_FUNC_RET +ayt(int sig __unused) { if (connected) sendayt(); @@ -960,8 +885,8 @@ ayt(sig) #endif - void -sys_telnet_init() +void +sys_telnet_init(void) { (void) signal(SIGINT, intr); (void) signal(SIGQUIT, intr2); @@ -980,13 +905,6 @@ sys_telnet_init() NetNonblockingIO(net, 1); -#if defined(TN3270) - if (noasynchnet == 0) { /* DBX can't handle! */ - NetSigIO(net, 1); - NetSetPgrp(net); - } -#endif /* defined(TN3270) */ - #if defined(SO_OOBINLINE) if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { perror("SetSockOpt"); @@ -1005,48 +923,55 @@ sys_telnet_init() * The return value is 1 if something happened, 0 if not. */ - int -process_rings(netin, netout, netex, ttyin, ttyout, poll) - int poll; /* If 0, then block until something to do */ +int +process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll) { - register int c; - /* One wants to be a bit careful about setting returnValue - * to one, since a one implies we did some useful work, - * and therefore probably won't be called to block next - * time (TN3270 mode only). - */ + int c; int returnValue = 0; - static struct timeval TimeValue = { 0 }; - - if (netout) { - FD_SET(net, &obits); - } - if (ttyout) { - FD_SET(tout, &obits); - } -#if defined(TN3270) - if (ttyin) { - FD_SET(tin, &ibits); - } -#else /* defined(TN3270) */ - if (ttyin) { - FD_SET(tin, &ibits); - } -#endif /* defined(TN3270) */ -#if defined(TN3270) - if (netin) { - FD_SET(net, &ibits); + static struct timeval TimeValue = { 0, 0 }; + int maxfd = -1; + int tmp; + + if ((netout || netin || netex) && net > maxfd) + maxfd = net; + + if (ttyout && tout > maxfd) + maxfd = tout; + if (ttyin && tin > maxfd) + maxfd = tin; + tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); + if (tmp > fdsn) { + if (ibitsp) + free(ibitsp); + if (obitsp) + free(obitsp); + if (xbitsp) + free(xbitsp); + + fdsn = tmp; + if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL) + err(1, "malloc"); + if ((obitsp = (fd_set *)malloc(fdsn)) == NULL) + err(1, "malloc"); + if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL) + err(1, "malloc"); + memset(ibitsp, 0, fdsn); + memset(obitsp, 0, fdsn); + memset(xbitsp, 0, fdsn); } -# else /* !defined(TN3270) */ - if (netin) { - FD_SET(net, &ibits); - } -# endif /* !defined(TN3270) */ - if (netex) { - FD_SET(net, &xbits); - } - if ((c = select(16, &ibits, &obits, &xbits, - (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { + + if (netout) + FD_SET(net, obitsp); + if (ttyout) + FD_SET(tout, obitsp); + if (ttyin) + FD_SET(tin, ibitsp); + if (netin) + FD_SET(net, ibitsp); + if (netex) + FD_SET(net, xbitsp); + if ((c = select(maxfd + 1, ibitsp, obitsp, xbitsp, + (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) { if (c == -1) { /* * we can get EINTR if we are in line mode, @@ -1056,25 +981,8 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll) if (errno == EINTR) { return 0; } -# if defined(TN3270) - /* - * we can get EBADF if we were in transparent - * mode, and the transcom process died. - */ - if (errno == EBADF) { - /* - * zero the bits (even though kernel does it) - * to make sure we are selecting on the right - * ones. - */ - FD_ZERO(&ibits); - FD_ZERO(&obits); - FD_ZERO(&xbits); - return 0; - } -# endif /* defined(TN3270) */ /* I don't like this, does it ever happen? */ - printf("sleep(5) from telnet, after select\r\n"); + printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno)); sleep(5); } return 0; @@ -1083,8 +991,8 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll) /* * Any urgent data? */ - if (FD_ISSET(net, &xbits)) { - FD_CLR(net, &xbits); + if (FD_ISSET(net, xbitsp)) { + FD_CLR(net, xbitsp); SYNCHing = 1; (void) ttyflush(1); /* flush already enqueued data */ } @@ -1092,10 +1000,10 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll) /* * Something to read from the network... */ - if (FD_ISSET(net, &ibits)) { + if (FD_ISSET(net, ibitsp)) { int canread; - FD_CLR(net, &ibits); + FD_CLR(net, ibitsp); canread = ring_empty_consecutive(&netiring); #if !defined(SO_OOBINLINE) /* @@ -1159,7 +1067,7 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll) int i; i = recv(net, netiring.supply + c, canread - c, MSG_OOB); if (i == c && - memcmp(netiring.supply, netiring.supply + c, i) == 0) { + memcmp(netiring.supply, netiring.supply + c, i) == 0) { bogus_oob = 1; first = 0; } else if (i < 0) { @@ -1205,8 +1113,8 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll) /* * Something to read from the tty... */ - if (FD_ISSET(tin, &ibits)) { - FD_CLR(tin, &ibits); + if (FD_ISSET(tin, ibitsp)) { + FD_CLR(tin, ibitsp); c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); if (c < 0 && errno == EIO) c = 0; @@ -1230,12 +1138,12 @@ process_rings(netin, netout, netex, ttyin, ttyout, poll) returnValue = 1; /* did something useful */ } - if (FD_ISSET(net, &obits)) { - FD_CLR(net, &obits); + if (FD_ISSET(net, obitsp)) { + FD_CLR(net, obitsp); returnValue |= netflush(); } - if (FD_ISSET(tout, &obits)) { - FD_CLR(tout, &obits); + if (FD_ISSET(tout, obitsp)) { + FD_CLR(tout, obitsp); returnValue |= (ttyflush(SYNCHing|flushout) > 0); } diff --git a/telnet.tproj/telnet.1 b/telnet.tproj/telnet.1 index b996fea..1ac6c42 100644 --- a/telnet.tproj/telnet.1 +++ b/telnet.tproj/telnet.1 @@ -30,42 +30,44 @@ .\" SUCH DAMAGE. .\" .\" @(#)telnet.1 8.6 (Berkeley) 6/1/94 +.\" $FreeBSD: src/crypto/telnet/telnet/telnet.1,v 1.4.2.9 2002/04/13 10:59:08 markm Exp $ .\" -.Dd June 1, 1994 +.Dd January 27, 2000 .Dt TELNET 1 -.Os BSD 4.2 +.Os .Sh NAME .Nm telnet -.Nd user interface to the +.Nd user interface to the .Tn TELNET protocol .Sh SYNOPSIS -.Nm telnet -.Op Fl 8EFKLacdfrx +.Nm +.Op Fl 468EFKLNacdfruxy .Op Fl S Ar tos .Op Fl X Ar authtype .Op Fl e Ar escapechar .Op Fl k Ar realm .Op Fl l Ar user .Op Fl n Ar tracefile +.Op Fl s Ar src_addr .Oo .Ar host -.Op port +.Op Ar port .Oc .Sh DESCRIPTION The -.Nm telnet +.Nm command -is used to communicate with another host using the +is used to communicate with another host using the .Tn TELNET protocol. If -.Nm telnet +.Nm is invoked without the .Ar host argument, it enters command mode, indicated by its prompt -.Pq Nm telnet\&> . +.Pq Dq Li telnet\&> . In this mode, it accepts and executes the commands listed below. If it is invoked with arguments, it performs an .Ic open @@ -73,6 +75,14 @@ command with those arguments. .Pp Options: .Bl -tag -width indent +.It Fl 4 +Forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +Forces +.Nm +to use IPv6 addresses only. .It Fl 8 Specifies an 8-bit data path. This causes an attempt to negotiate the @@ -90,20 +100,27 @@ have already been forwarded into the local environment. Specifies no automatic login to the remote system. .It Fl L Specifies an 8-bit data path on output. This causes the -BINARY option to be negotiated on output. +.Dv BINARY +option to be negotiated on output. +.It Fl N +Prevents IP address to name lookup when destination host is given +as an IP address. .It Fl S Ar tos Sets the IP type-of-service (TOS) option for the telnet connection to the value -.Ar tos, +.Ar tos , which can be a numeric TOS value or, on systems that support it, a symbolic -TOS name found in the /etc/iptos file. -.It Fl X Ar atype +TOS name found in the +.Pa /etc/iptos +file. +.It Fl X Ar atype Disables the .Ar atype type of authentication. .It Fl a Attempt automatic login. +This is now the default, so this option is ignored. Currently, this sends the user name via the .Ev USER variable @@ -124,43 +141,45 @@ command on this man page.) Sets the initial value of the .Ic debug toggle to -.Dv TRUE -.It Fl e Ar escape char +.Dv TRUE . +.It Fl e Ar escapechar Sets the initial .Nm -.Nm telnet escape character to -.Ar escape char. +.Ar escapechar . If -.Ar escape char +.Ar escapechar is omitted, then there will be no escape character. .It Fl f If Kerberos V5 authentication is being used, the .Fl f option allows the local credentials to be forwarded to the remote system. -.ne 1i .It Fl k Ar realm If Kerberos authentication is being used, the .Fl k -option requests that telnet obtain tickets for the remote host in -realm realm instead of the remote host's realm, as determined -by +option requests that +.Nm +obtain tickets for the remote host in +realm +.Ar realm +instead of the remote host's realm, as determined by .Xr krb_realmofhost 3 . -.It Fl l Ar user +.It Fl l Ar user When connecting to the remote system, if the remote system understands the .Ev ENVIRON option, then .Ar user -will be sent to the remote system as the value for the variable USER. +will be sent to the remote system as the value for the variable +.Ev USER . This option implies the .Fl a option. This option may also be used with the .Ic open command. -.It Fl n Ar tracefile +.It Fl n Ar tracefile Opens .Ar tracefile for recording trace information. @@ -172,39 +191,68 @@ Specifies a user interface similar to .Xr rlogin 1 . In this mode, the escape character is set to the tilde (~) character, -unless modified by the -e option. +unless modified by the +.Fl e +option. +.It Fl s Ar src_addr +Set the source IP address for the +.Nm +connection to +.Ar src_addr , +which can be an IP address or a host name. +.It Fl u +Forces +.Nm +to use +.Dv AF_UNIX +addresses only (e.g., +.Ux +domain sockets, accessed with a file path). .It Fl x -Turns on encryption of the data stream if possible. This -option is not available outside of the United States and -Canada. +Turns on encryption of the data stream if possible. +This is now the default, so this option is ignored. +.It Fl y +Suppresses encryption of the data stream. .It Ar host Indicates the official name, an alias, or the Internet address of a remote host. +If +.Ar host +starts with a +.Ql / , +.Nm +establishes a connection to the corresponding named socket. .It Ar port Indicates a port number (address of an application). If a number is not specified, the default -.Nm telnet +.Nm port is used. .El .Pp When in rlogin mode, a line of the form ~. disconnects from the -remote host; ~ is the telnet escape character. -Similarly, the line ~^Z suspends the telnet session. -The line ~^] escapes to the normal telnet escape prompt. +remote host; ~ is the +.Nm +escape character. +Similarly, the line ~^Z suspends the +.Nm +session. +The line ~^] escapes to the normal +.Nm +escape prompt. .Pp Once a connection has been opened, -.Nm telnet +.Nm will attempt to enable the .Dv TELNET LINEMODE option. If this fails, then -.Nm telnet +.Nm will revert to one of two input modes: either \*(Lqcharacter at a time\*(Rq or \*(Lqold line by line\*(Rq depending on what the remote system supports. .Pp -When +When .Dv LINEMODE is enabled, character processing is done on the local system, under the control of the remote system. When input @@ -223,13 +271,13 @@ to turn off and on the local echo (this would mostly be used to enter passwords without the password being echoed). .Pp -If the +If the .Dv LINEMODE option is enabled, or if the .Ic localchars toggle is .Dv TRUE -(the default for \*(Lqold line by line\*(Lq; see below), +(the default for \*(Lqold line by line\*(Rq; see below), the user's .Ic quit , .Ic intr , @@ -238,7 +286,7 @@ and characters are trapped locally, and sent as .Tn TELNET protocol sequences to the remote side. -If +If .Dv LINEMODE has ever been enabled, then the user's .Ic susp @@ -249,10 +297,10 @@ are also sent as protocol sequences, and .Ic quit -is sent as a +is sent as a .Dv TELNET ABORT -instead of -.Dv BREAK +instead of +.Dv BREAK . There are options (see .Ic toggle .Ic autoflush @@ -270,14 +318,14 @@ and .Ic intr ) . .Pp While connected to a remote host, -.Nm telnet +.Nm command mode may be entered by typing the -.Nm telnet +.Nm \*(Lqescape character\*(Rq (initially \*(Lq^]\*(Rq). When in command mode, the normal terminal editing conventions are available. .Pp The following -.Nm telnet +.Nm commands are available. Only enough of each command to uniquely identify it need be typed (this is also true for arguments to the @@ -292,21 +340,22 @@ and commands). .Pp .Bl -tag -width "mode type" -.It Ic auth Ar argument ... +.It Ic auth Ar argument ... The auth command manipulates the information sent through the .Dv TELNET AUTHENTICATE option. Valid arguments for the -auth command are as follows: +.Ic auth +command are: .Bl -tag -width "disable type" .It Ic disable Ar type Disables the specified type of authentication. To obtain a list of available types, use the -.Ic auth disable \&? +.Ic auth disable ?\& command. .It Ic enable Ar type Enables the specified type of authentication. To obtain a list of available types, use the -.Ic auth enable \&? +.Ic auth enable ?\& command. .It Ic status Lists the current status of the various types of @@ -316,7 +365,7 @@ authentication. Close a .Tn TELNET session and return to command mode. -.It Ic display Ar argument ... +.It Ic display Ar argument ... Displays all, or some, of the .Ic set and @@ -327,24 +376,26 @@ The encrypt command manipulates the information sent through the .Dv TELNET ENCRYPT option. .Pp -Note: Because of export controls, the -.Dv TELNET ENCRYPT -option is not supported outside of the United States and Canada. -.Pp -Valid arguments for the encrypt command are as follows: +Valid arguments for the +.Ic encrypt +command are: .Bl -tag -width Ar -.It Ic disable Ar type Ic [input|output] +.It Ic disable Ar type Xo +.Op Cm input | output +.Xc Disables the specified type of encryption. If you omit the input and output, both input and output are disabled. To obtain a list of available types, use the -.Ic encrypt disable \&? +.Ic encrypt disable ?\& command. -.It Ic enable Ar type Ic [input|output] +.It Ic enable Ar type Xo +.Op Cm input | output +.Xc Enables the specified type of encryption. If you omit input and output, both input and output are enabled. To obtain a list of available types, use the -.Ic encrypt enable \&? +.Ic encrypt enable ?\& command. .It Ic input This is the same as the @@ -362,18 +413,18 @@ command. This is the same as the .Ic encrypt stop output command. -.It Ic start Ic [input|output] +.It Ic start Op Cm input | output Attempts to start encryption. If you omit .Ic input and -.Ic output, +.Ic output , both input and output are enabled. To obtain a list of available types, use the -.Ic encrypt enable \&? +.Ic encrypt enable ?\& command. .It Ic status Lists the current status of encryption. -.It Ic stop Ic [input|output] +.It Ic stop Op Cm input | output Stops encryption. If you omit input and output, encryption is on both input and output. .It Ic type Ar type @@ -384,11 +435,11 @@ or .Ic encrypt stop commands. .El -.It Ic environ Ar arguments... +.It Ic environ Ar arguments ... The .Ic environ command is used to manipulate the -the variables that my be sent through the +variables that may be sent through the .Dv TELNET ENVIRON option. The initial set of variables is taken from the users @@ -404,30 +455,30 @@ variable is also exported if the or .Fl l options are used. -.br +.Pp Valid arguments for the .Ic environ command are: .Bl -tag -width Fl -.It Ic define Ar variable value +.It Ic define Ar variable value Define the variable .Ar variable to have a value of -.Ar value. +.Ar value . Any variables defined by this command are automatically exported. The .Ar value may be enclosed in single or double quotes so that tabs and spaces may be included. -.It Ic undefine Ar variable +.It Ic undefine Ar variable Remove .Ar variable from the list of environment variables. -.It Ic export Ar variable +.It Ic export Ar variable Mark the variable .Ar variable to be exported to the remote side. -.It Ic unexport Ar variable +.It Ic unexport Ar variable Mark the variable .Ar variable to not be exported unless @@ -438,7 +489,7 @@ Those marked with a .Cm * will be sent automatically, other variables will only be sent if explicitly requested. -.It Ic \&? +.It Ic ?\& Prints out help information for the .Ic environ command. @@ -461,7 +512,7 @@ If the remote side also supports the concept of suspending a user's session for later reattachment, the logout argument indicates that you should terminate the session immediately. -.It Ic mode Ar type +.It Ic mode Ar type .Ar Type is one of several options, depending on the state of the .Tn TELNET @@ -475,81 +526,79 @@ Disable the .Dv TELNET LINEMODE option, or, if the remote side does not understand the .Dv LINEMODE -option, then enter \*(Lqcharacter at a time\*(Lq mode. +option, then enter \*(Lqcharacter at a time\*(Rq mode. .It Ic line Enable the .Dv TELNET LINEMODE option, or, if the remote side does not understand the .Dv LINEMODE -option, then attempt to enter \*(Lqold-line-by-line\*(Lq mode. -.It Ic isig Pq Ic \-isig -Attempt to enable (disable) the +option, then attempt to enter \*(Lqold-line-by-line\*(Rq mode. +.It Ic isig Pq Ic \-isig +Attempt to enable (disable) the .Dv TRAPSIG -mode of the +mode of the .Dv LINEMODE option. -This requires that the +This requires that the .Dv LINEMODE option be enabled. -.It Ic edit Pq Ic \-edit -Attempt to enable (disable) the +.It Ic edit Pq Ic \-edit +Attempt to enable (disable) the .Dv EDIT -mode of the +mode of the .Dv LINEMODE option. -This requires that the +This requires that the .Dv LINEMODE option be enabled. -.It Ic softtabs Pq Ic \-softtabs -Attempt to enable (disable) the +.It Ic softtabs Pq Ic \-softtabs +Attempt to enable (disable) the .Dv SOFT_TAB -mode of the +mode of the .Dv LINEMODE option. -This requires that the +This requires that the .Dv LINEMODE option be enabled. -.ne 1i -.It Ic litecho Pq Ic \-litecho -Attempt to enable (disable) the +.It Ic litecho Pq Ic \-litecho +Attempt to enable (disable) the .Dv LIT_ECHO -mode of the +mode of the .Dv LINEMODE option. -This requires that the +This requires that the .Dv LINEMODE option be enabled. -.It Ic \&? +.It Ic ?\& Prints out help information for the .Ic mode command. .El .It Xo .Ic open Ar host -.Oo Op Fl l -.Ar user -.Oc Ns Oo Fl -.Ar port Oc +.Op Fl l Ar user +.Op Oo Fl Oc Ns Ar port .Xc Open a connection to the named host. If no port number is specified, -.Nm telnet +.Nm will attempt to contact a .Tn TELNET server at the default port. The host specification may be either a host name (see -.Xr hosts 5 ) -or an Internet address specified in the \*(Lqdot notation\*(Rq (see -.Xr inet 3 ) . +.Xr hosts 5 ) , +an Internet address specified in the \*(Lqdot notation\*(Rq (see +.Xr inet 3 ) , +or IPv6 host name or IPv6 coloned-hexadecimal addreess. The -.Op Fl l +.Fl l option may be used to specify the user name to be passed to the remote system via the .Ev ENVIRON option. When connecting to a non-standard port, -.Nm telnet +.Nm omits any automatic initiation of .Tn TELNET options. When the port number is preceded by a minus sign, @@ -563,18 +612,18 @@ without white space are the start of a machine entry. The first thing on the line is the name of the machine that is being connected to. The rest of the line, and successive lines that begin with white space are assumed to be -.Nm telnet +.Nm commands and are processed as if they had been typed in manually to the -.Nm telnet +.Nm command prompt. .It Ic quit Close any open .Tn TELNET session and exit -.Nm telnet . +.Nm . An end of file (in command mode) will also close a session and exit. -.It Ic send Ar arguments +.It Ic send Ar arguments Sends one or more special character sequences to the remote host. The following are the arguments which may be specified (more than one argument may be specified at a time): @@ -629,7 +678,7 @@ Sends the sequence. .It Ic escape Sends the current -.Nm telnet +.Nm escape character (initially \*(Lq^\*(Rq). .It Ic ga Sends the @@ -643,7 +692,6 @@ command, .Ic getstatus will send the subnegotiation to request that the server send its current option status. -.ne 1i .It Ic ip Sends the .Dv TELNET IP @@ -689,20 +737,20 @@ command. can also be either .Ic help or -.Ic \&? +.Ic ?\& to print out help information, including a list of known symbolic names. -.It Ic \&? +.It Ic ?\& Prints out help information for the .Ic send command. .El -.It Ic set Ar argument value -.It Ic unset Ar argument value +.It Ic set Ar argument value +.It Ic unset Ar argument value The .Ic set command will set any one of a number of -.Nm telnet +.Nm variables to a specific value or to .Dv TRUE . The special value @@ -739,7 +787,7 @@ is enabled, and the status character is typed, a sequence (see .Ic send ayt preceding) is sent to the -remote host. The initial value for the "Are You There" +remote host. The initial value for the \*(LqAre You There\*(Rq character is the terminal's status character. .It Ic echo This is the value (initially \*(Lq^E\*(Rq) which, when in @@ -748,7 +796,7 @@ of entered characters (for normal processing), and suppressing echoing of entered characters (for entering, say, a password). .It Ic eof If -.Nm telnet +.Nm is operating in .Dv LINEMODE or \*(Lqold line by line\*(Rq mode, entering this character @@ -759,7 +807,7 @@ The initial value of the eof character is taken to be the terminal's character. .It Ic erase If -.Nm telnet +.Nm is in .Ic localchars mode (see @@ -768,7 +816,7 @@ mode (see below), .Sy and if -.Nm telnet +.Nm is operating in \*(Lqcharacter at a time\*(Rq mode, then when this character is typed, a .Dv TELNET EC @@ -783,14 +831,14 @@ the terminal's character. .It Ic escape This is the -.Nm telnet +.Nm escape character (initially \*(Lq^[\*(Rq) which causes entry into -.Nm telnet +.Nm command mode (when connected to a remote system). .It Ic flushoutput If -.Nm telnet +.Nm is in .Ic localchars mode (see @@ -813,7 +861,7 @@ character. .It Ic forw1 .It Ic forw2 If -.Tn TELNET +.Nm is operating in .Dv LINEMODE , these are the @@ -823,7 +871,7 @@ the forwarding characters are taken from the terminal's eol and eol2 characters. .It Ic interrupt If -.Nm telnet +.Nm is in .Ic localchars mode (see @@ -845,7 +893,7 @@ the terminal's character. .It Ic kill If -.Nm telnet +.Nm is in .Ic localchars mode (see @@ -854,7 +902,7 @@ mode (see below), .Ic and if -.Nm telnet +.Nm is operating in \*(Lqcharacter at a time\*(Rq mode, then when this character is typed, a .Dv TELNET EL @@ -869,10 +917,10 @@ the terminal's character. .It Ic lnext If -.Nm telnet +.Nm is operating in .Dv LINEMODE -or \*(Lqold line by line\*(Lq mode, then this character is taken to +or \*(Lqold line by line\*(Rq mode, then this character is taken to be the terminal's .Ic lnext character. @@ -882,7 +930,7 @@ the terminal's character. .It Ic quit If -.Nm telnet +.Nm is in .Ic localchars mode (see @@ -904,10 +952,10 @@ the terminal's character. .It Ic reprint If -.Nm telnet +.Nm is operating in .Dv LINEMODE -or \*(Lqold line by line\*(Lq mode, then this character is taken to +or \*(Lqold line by line\*(Rq mode, then this character is taken to be the terminal's .Ic reprint character. @@ -918,13 +966,17 @@ character. .It Ic rlogin This is the rlogin escape character. If set, the normal -.Tn TELNET +.Nm escape character is ignored unless it is preceded by this character at the beginning of a line. This character, at the beginning of a line followed by a "." closes the connection; when followed by a ^Z it -suspends the telnet command. The initial state is to -disable the rlogin escape character. +suspends the +.Nm +command. The initial state is to +disable the +.Nm rlogin +escape character. .It Ic start If the .Dv TELNET TOGGLE-FLOW-CONTROL @@ -933,7 +985,7 @@ then this character is taken to be the terminal's .Ic start character. -The initial value for the kill character is taken to be +The initial value for the start character is taken to be the terminal's .Ic start character. @@ -945,13 +997,13 @@ then this character is taken to be the terminal's .Ic stop character. -The initial value for the kill character is taken to be +The initial value for the stop character is taken to be the terminal's .Ic stop character. .It Ic susp If -.Nm telnet +.Nm is in .Ic localchars mode, or @@ -969,7 +1021,6 @@ The initial value for the suspend character is taken to be the terminal's .Ic suspend character. -.ne 1i .It Ic tracefile This is the file to which the output, caused by .Ic netdata @@ -982,10 +1033,10 @@ will be written. If it is set to then tracing information will be written to standard output (the default). .It Ic worderase If -.Nm telnet +.Nm is operating in .Dv LINEMODE -or \*(Lqold line by line\*(Lq mode, then this character is taken to +or \*(Lqold line by line\*(Rq mode, then this character is taken to be the terminal's .Ic worderase character. @@ -993,22 +1044,26 @@ The initial value for the worderase character is taken to be the terminal's .Ic worderase character. -.It Ic \&? +.It Ic ?\& Displays the legal .Ic set .Pq Ic unset commands. .El -.It Ic slc Ar state +.It Ic opie Ar sequence challenge +The +.Ic opie +command computes a response to the OPIE challenge. +.It Ic slc Ar state The .Ic slc command (Set Local Characters) is used to set -or change the state of the the special -characters when the +or change the state of the special +characters when the .Dv TELNET LINEMODE option has been enabled. Special characters are characters that get -mapped to +mapped to .Tn TELNET commands sequences (like .Ic ip @@ -1029,31 +1084,31 @@ the local side, the local side will switch to the remote value. Switch to the local defaults for the special characters. The local default characters are those of the local terminal at the time when -.Nm telnet +.Nm was started. .It Ic import Switch to the remote defaults for the special characters. The remote default characters are those of the remote system -at the time when the +at the time when the .Tn TELNET connection was established. -.It Ic \&? +.It Ic ?\& Prints out help information for the .Ic slc command. .El .It Ic status Show the current status of -.Nm telnet . +.Nm . This includes the peer one is connected to, as well as the current mode. -.It Ic toggle Ar arguments ... +.It Ic toggle Ar arguments ... Toggle (between .Dv TRUE and .Dv FALSE ) various flags that control how -.Nm telnet +.Nm responds to events. These flags may be set explicitly to .Dv TRUE @@ -1088,7 +1143,7 @@ characters are recognized (and transformed into sequences; see .Ic set above for details), -.Nm telnet +.Nm refuses to display any data on the user's terminal until the remote system acknowledges (via a .Dv TELNET TIMING MARK @@ -1112,16 +1167,11 @@ stream does not start automatically. The autoencrypt (autodecrypt) command states that encryption of the output (input) stream should be enabled as soon as possible. -.sp -.Pp -Note: Because of export controls, the -.Dv TELNET ENCRYPT -option is not supported outside the United States and Canada. .It Ic autologin If the remote side supports the .Dv TELNET AUTHENTICATION option -.Tn TELNET +.Nm attempts to use it to perform automatic authentication. If the .Dv AUTHENTICATION option is not supported, the user's login @@ -1129,7 +1179,7 @@ name are propagated through the .Dv TELNET ENVIRON option. This command is the same as specifying -.Ar a +.Fl a option on the .Ic open command. @@ -1248,12 +1298,14 @@ has ever been enabled, then is sent as .Ic abort , and -.Ic eof and -.B suspend +.Ic eof +and +.Ic suspend are sent as -.Ic eof and -.Ic susp , -see +.Ic eof +and +.Ic susp +(see .Ic send above). .It Ic netdata @@ -1262,13 +1314,12 @@ The initial value for this toggle is .Dv FALSE . .It Ic options Toggles the display of some internal -.Nm telnet +.Nm protocol processing (having to do with .Tn TELNET options). The initial value for this toggle is .Dv FALSE . -.ne 1i .It Ic prettydump When the .Ic netdata @@ -1279,18 +1330,18 @@ is enabled the output from the command will be formatted in a more user readable format. Spaces are put between each character in the output, and the beginning of any -.Tn TELNET +.Nm escape sequence is preceded by a '*' to aid in locating them. .It Ic skiprc When the skiprc toggle is .Dv TRUE , -.Tn TELNET +.Nm skips the reading of the .Pa \&.telnetrc file in the users home directory when connections are opened. The initial value for this toggle is -.Dv FALSE. +.Dv FALSE . .It Ic termdata Toggles the display of all terminal data (in hexadecimal format). The initial value for this toggle is @@ -1300,38 +1351,38 @@ When the .Ic verbose_encrypt toggle is .Dv TRUE , -.Tn TELNET +.Nm prints out a message each time encryption is enabled or disabled. The initial value for this toggle is -.Dv FALSE. -Note: Because of export controls, data encryption -is not supported outside of the United States and Canada. -.It Ic \&? +.Dv FALSE . +.It Ic ?\& Displays the legal .Ic toggle commands. .El .It Ic z Suspend -.Nm telnet . +.Nm . This command only works when the user is using the .Xr csh 1 . -.It Ic \&! Op Ar command +.It Ic \&! Op Ar command Execute a single command in a subshell on the local system. If -.Ic command +.Ar command is omitted, then an interactive subshell is invoked. -.It Ic \&? Op Ar command +.It Ic ?\& Op Ar command Get help. With no arguments, -.Nm telnet +.Nm prints a help summary. -If a command is specified, -.Nm telnet +If +.Ar command +is specified, +.Nm will print the help information for just that command. .El .Sh ENVIRONMENT -.Nm Telnet +.Nm uses at least the .Ev HOME , .Ev SHELL , @@ -1343,6 +1394,12 @@ Other environment variables may be propagated to the other side via the .Dv TELNET ENVIRON option. +.Sh SEE ALSO +.Xr rlogin 1 , +.Xr rsh 1 , +.Xr hosts 5 , +.Xr nologin 5 , +.Xr telnetd 8 .Sh FILES .Bl -tag -width ~/.telnetrc -compact .It Pa ~/.telnetrc @@ -1350,15 +1407,16 @@ user customized telnet startup values .El .Sh HISTORY The -.Nm Telnet +.Nm command appeared in .Bx 4.2 . -.Sh NOTES .Pp +IPv6 support was added by WIDE/KAME project. +.Sh NOTES On some remote systems, echo has to be turned off manually when in \*(Lqold line by line\*(Rq mode. .Pp -In \*(Lqold line by line\*(Rq mode or +In \*(Lqold line by line\*(Rq mode or .Dv LINEMODE the terminal's .Ic eof diff --git a/telnet.tproj/telnet.c b/telnet.tproj/telnet.c index e1a974f..3f4ccba 100644 --- a/telnet.tproj/telnet.c +++ b/telnet.tproj/telnet.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -54,23 +31,34 @@ * SUCH DAMAGE. */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/telnet.c,v 1.4.2.5 2002/04/13 10:59:08 markm Exp $"); +#endif + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif + #ifndef lint -static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; -#endif /* not lint */ +static const char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; +#endif #include -#if defined(unix) || defined(__APPLE__) -#include /* By the way, we need to include curses.h before telnet.h since, * among other things, telnet.h #defines 'DO', which is a variable * declared in curses.h. */ -#endif /* defined(unix) || defined(__APPLE__) */ - -#include #include +#include +#include +#include +#include +#include +#include #include "ring.h" @@ -79,6 +67,13 @@ static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; #include "types.h" #include "general.h" +#ifdef AUTHENTICATION +#include +#endif +#ifdef ENCRYPTION +#include +#endif +#include #define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x)) @@ -105,17 +100,11 @@ int skiprc = 0, connected, showoptions, - In3270, /* Are we in 3270 mode? */ ISend, /* trying to send network data in */ debug = 0, crmod, netdata, /* Print out network data flow */ crlf, /* Should '\r' be mapped to (or )? */ -#if defined(TN3270) - noasynchtty = 0,/* User specified "-noasynch" on command line */ - noasynchnet = 0,/* User specified "-noasynch" on command line */ - askedSGA = 0, /* We have talked about suppress go ahead */ -#endif /* defined(TN3270) */ telnetport, SYNCHing, /* we are in TELNET SYNCH mode */ flushout, /* flush output */ @@ -127,9 +116,14 @@ int donelclchars, /* the user has set "localchars" */ donebinarytoggle, /* the user has put us in binary */ dontlecho, /* do we suppress local echoing right now? */ - globalmode; + globalmode, + doaddrlookup = 1, /* do a reverse address lookup? */ + clienteof = 0; char *prompt = 0; +#ifdef ENCRYPTION +char *line; /* hack around breakage in sra.c :-( !! */ +#endif cc_t escape; cc_t rlogin; @@ -157,7 +151,7 @@ unsigned char telopt_environ = TELOPT_NEW_ENVIRON; # define telopt_environ TELOPT_NEW_ENVIRON #endif -jmp_buf toplevel = { 0 }; +jmp_buf toplevel; jmp_buf peerdied; int flushline; @@ -167,42 +161,33 @@ int linemode; int kludgelinemode = 1; #endif +static int is_unique(char *, char **, char **); + /* * The following are some clocks used to decide how to interpret * the relationship between various variables. */ Clocks clocks; - -#ifdef notdef -Modelist modelist[] = { - { "telnet command mode", COMMAND_LINE }, - { "character-at-a-time mode", 0 }, - { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, - { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, - { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, - { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, - { "3270 mode", 0 }, -}; -#endif - /* * Initialize telnet environment. */ - void -init_telnet() +void +init_telnet(void) { env_init(); SB_CLEAR(); ClearArray(options); - connected = In3270 = ISend = localflow = donebinarytoggle = 0; -#if defined(AUTHENTICATION) || defined(ENCRYPTION) + connected = ISend = localflow = donebinarytoggle = 0; +#ifdef AUTHENTICATION +#ifdef ENCRYPTION auth_encrypt_connect(connected); -#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ +#endif +#endif restartany = -1; SYNCHing = 0; @@ -220,56 +205,6 @@ init_telnet() } -#ifdef notdef -#include - - /*VARARGS*/ - static void -printring(va_alist) - va_dcl -{ - va_list ap; - char buffer[100]; /* where things go */ - char *ptr; - char *format; - char *string; - Ring *ring; - int i; - - va_start(ap); - - ring = va_arg(ap, Ring *); - format = va_arg(ap, char *); - ptr = buffer; - - while ((i = *format++) != 0) { - if (i == '%') { - i = *format++; - switch (i) { - case 'c': - *ptr++ = va_arg(ap, int); - break; - case 's': - string = va_arg(ap, char *); - ring_supply_data(ring, buffer, ptr-buffer); - ring_supply_data(ring, string, strlen(string)); - ptr = buffer; - break; - case 0: - ExitString("printring: trailing %%.\n", 1); - /*NOTREACHED*/ - default: - ExitString("printring: unknown format character.\n", 1); - /*NOTREACHED*/ - } - } else { - *ptr++ = i; - } - } - ring_supply_data(ring, buffer, ptr-buffer); -} -#endif - /* * These routines are in charge of sending option negotiations * to the other side. @@ -278,9 +213,8 @@ printring(va_alist) * is in disagreement as to what the current state should be. */ - void -send_do(c, init) - register int c, init; +void +send_do(int c, int init) { if (init) { if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || @@ -294,9 +228,8 @@ send_do(c, init) printoption("SENT", DO, c); } - void -send_dont(c, init) - register int c, init; +void +send_dont(int c, int init) { if (init) { if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || @@ -310,9 +243,8 @@ send_dont(c, init) printoption("SENT", DONT, c); } - void -send_will(c, init) - register int c, init; +void +send_will(int c, int init) { if (init) { if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || @@ -326,9 +258,8 @@ send_will(c, init) printoption("SENT", WILL, c); } - void -send_wont(c, init) - register int c, init; +void +send_wont(int c, int init) { if (init) { if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || @@ -342,10 +273,8 @@ send_wont(c, init) printoption("SENT", WONT, c); } - - void -willoption(option) - int option; +void +willoption(int option) { int new_state_ok = 0; @@ -360,36 +289,12 @@ willoption(option) switch (option) { case TELOPT_ECHO: -# if defined(TN3270) - /* - * The following is a pain in the rear-end. - * Various IBM servers (some versions of Wiscnet, - * possibly Fibronics/Spartacus, and who knows who - * else) will NOT allow us to send "DO SGA" too early - * in the setup proceedings. On the other hand, - * 4.2 servers (telnetd) won't set SGA correctly. - * So, we are stuck. Empirically (but, based on - * a VERY small sample), the IBM servers don't send - * out anything about ECHO, so we postpone our sending - * "DO SGA" until we see "WILL ECHO" (which 4.2 servers - * DO send). - */ - { - if (askedSGA == 0) { - askedSGA = 1; - if (my_want_state_is_dont(TELOPT_SGA)) - send_do(TELOPT_SGA, 1); - } - } - /* Fall through */ - case TELOPT_EOR: -#endif /* defined(TN3270) */ case TELOPT_BINARY: case TELOPT_SGA: settimer(modenegotiated); /* FALL THROUGH */ case TELOPT_STATUS: -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: #endif #ifdef ENCRYPTION @@ -430,9 +335,8 @@ willoption(option) #endif /* ENCRYPTION */ } - void -wontoption(option) - int option; +void +wontoption(int option) { if (do_dont_resp[option]) { --do_dont_resp[option]; @@ -479,9 +383,8 @@ wontoption(option) set_my_state_dont(option); } - static void -dooption(option) - int option; +static void +dooption(int option) { int new_state_ok = 0; @@ -506,9 +409,6 @@ dooption(option) set_my_state_wont(TELOPT_TM); return; -# if defined(TN3270) - case TELOPT_EOR: /* end of record */ -# endif /* defined(TN3270) */ case TELOPT_BINARY: /* binary mode */ case TELOPT_NAWS: /* window size */ case TELOPT_TSPEED: /* terminal speed */ @@ -535,7 +435,7 @@ dooption(option) new_state_ok = 1; break; -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: if (autologin) new_state_ok = 1; @@ -543,7 +443,7 @@ dooption(option) #endif case TELOPT_XDISPLOC: /* X Display location */ - if (env_getvalue((unsigned char *)"DISPLAY")) + if (env_getvalue("DISPLAY")) new_state_ok = 1; break; @@ -592,9 +492,8 @@ dooption(option) set_my_state_will(option); } - static void -dontoption(option) - int option; +static void +dontoption(int option) { if (will_wont_resp[option]) { @@ -630,23 +529,22 @@ dontoption(option) /* * Given a buffer returned by tgetent(), this routine will turn - * the pipe seperated list of names in the buffer into an array + * the pipe separated list of names in the buffer into an array * of pointers to null terminated names. We toss out any bad, * duplicate, or verbose names (names with spaces). */ -static char *name_unknown = "UNKNOWN"; -static char *unknown[] = { 0, 0 }; +static const char *name_unknown = "UNKNOWN"; +static const char *unknown[] = { NULL, NULL }; - char ** -mklist(buf, name) - char *buf, *name; +static const char ** +mklist(char *buf, char *name) { - register int n; - register char c, *cp, **argvp, *cp2, **argv, **avt; + int n; + char c, *cp, **argvp, *cp2, **argv, **avt; if (name) { - if ((int)strlen(name) > 40) { + if (strlen(name) > 40) { name = 0; unknown[0] = name_unknown; } else { @@ -744,17 +642,16 @@ mklist(buf, name) } } if (*argv) - return(argv); + return((const char **)argv); else return(unknown); } - int -is_unique(name, as, ae) - register char *name, **as, **ae; +static int +is_unique(char *name, char **as, char **ae) { - register char **ap; - register int n; + char **ap; + int n; n = strlen(name) + 1; for (ap = as; ap < ae; ap++) @@ -766,11 +663,9 @@ is_unique(name, as, ae) #ifdef TERMCAP char termbuf[1024]; - /*ARGSUSED*/ - int -setupterm(tname, fd, errp) - char *tname; - int fd, *errp; +/*ARGSUSED*/ +static int +setupterm(char *tname, int fd, int *errp) { if (tgetent(termbuf, tname) == 1) { termbuf[1023] = '\0'; @@ -789,23 +684,23 @@ extern char ttytype[]; int resettermname = 1; - char * -gettermname() +static const char * +gettermname(void) { char *tname; - static char **tnamep = 0; - static char **next; + static const char **tnamep = 0; + static const char **next; int err; if (resettermname) { resettermname = 0; if (tnamep && tnamep != unknown) free(tnamep); - if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) && + if ((tname = env_getvalue("TERM")) && (setupterm(tname, 1, &err) == 0)) { tnamep = mklist(termbuf, tname); } else { - if (tname && ((int)strlen(tname) <= 40)) { + if (tname && (strlen(tname) <= 40)) { unknown[0] = tname; upcase(tname); } else @@ -832,8 +727,8 @@ gettermname() * Linemode */ - static void -suboption() +static void +suboption(void) { unsigned char subchar; @@ -845,19 +740,14 @@ suboption() if (SB_EOF() || SB_GET() != TELQUAL_SEND) { return; } else { - char *name; + const char *name; unsigned char temp[50]; int len; -#if defined(TN3270) - if (tn3270_ttype()) { - return; - } -#endif /* defined(TN3270) */ name = gettermname(); len = strlen(name) + 4 + 2; if (len < NETROOM()) { - sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, + sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); ring_supply_data(&netoring, temp, len); printsub('>', &temp[2], len-2); @@ -879,7 +769,7 @@ suboption() TerminalSpeeds(&ispeed, &ospeed); - sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED, + sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ @@ -976,16 +866,17 @@ suboption() unsigned char temp[50], *dp; int len; - if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) { + if ((dp = env_getvalue("DISPLAY")) == NULL || + strlen(dp) > sizeof(temp) - 7) { /* * Something happened, we no longer have a DISPLAY - * variable. So, turn off the option. + * variable. Or it is too long. So, turn off the option. */ send_wont(TELOPT_XDISPLOC, 1); break; } - sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, - TELQUAL_IS, dp, IAC, SE); + snprintf(temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, + TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ if (len < NETROOM()) { @@ -996,7 +887,7 @@ suboption() } break; -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: { if (!autologin) break; @@ -1095,10 +986,8 @@ suboption() static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; - void -lm_will(cmd, len) - unsigned char *cmd; - int len; +void +lm_will(unsigned char *cmd, int len) { if (len < 1) { /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ @@ -1109,7 +998,7 @@ lm_will(cmd, len) default: str_lm[3] = DONT; str_lm[4] = cmd[0]; - if (NETROOM() > sizeof(str_lm)) { + if (NETROOM() > (int)sizeof(str_lm)) { ring_supply_data(&netoring, str_lm, sizeof(str_lm)); printsub('>', &str_lm[2], sizeof(str_lm)-2); } @@ -1118,10 +1007,8 @@ lm_will(cmd, len) } } - void -lm_wont(cmd, len) - unsigned char *cmd; - int len; +void +lm_wont(unsigned char *cmd, int len) { if (len < 1) { /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ @@ -1135,10 +1022,8 @@ lm_wont(cmd, len) } } - void -lm_do(cmd, len) - unsigned char *cmd; - int len; +void +lm_do(unsigned char *cmd, int len) { if (len < 1) { /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ @@ -1149,7 +1034,7 @@ lm_do(cmd, len) default: str_lm[3] = WONT; str_lm[4] = cmd[0]; - if (NETROOM() > sizeof(str_lm)) { + if (NETROOM() > (int)sizeof(str_lm)) { ring_supply_data(&netoring, str_lm, sizeof(str_lm)); printsub('>', &str_lm[2], sizeof(str_lm)-2); } @@ -1158,10 +1043,8 @@ lm_do(cmd, len) } } - void -lm_dont(cmd, len) - unsigned char *cmd; - int len; +void +lm_dont(unsigned char *cmd, int len) { if (len < 1) { /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ @@ -1179,10 +1062,8 @@ static unsigned char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE }; - void -lm_mode(cmd, len, init) - unsigned char *cmd; - int len, init; +void +lm_mode(unsigned char *cmd, int len, int init) { if (len != 1) return; @@ -1194,7 +1075,7 @@ lm_mode(cmd, len, init) str_lm_mode[4] = linemode; if (!init) str_lm_mode[4] |= MODE_ACK; - if (NETROOM() > sizeof(str_lm_mode)) { + if (NETROOM() > (int)sizeof(str_lm_mode)) { ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); } @@ -1221,10 +1102,10 @@ struct spc { #define SLC_RVALUE 2 static int slc_mode = SLC_EXPORT; - void -slc_init() +void +slc_init(void) { - register struct spc *spcp; + struct spc *spcp; localchars = 1; for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { @@ -1235,7 +1116,7 @@ slc_init() #define initfunc(func, flags) { \ spcp = &spc_data[func]; \ - if (spcp->valp = tcval(func)) { \ + if ((spcp->valp = tcval(func))) { \ spcp->val = *spcp->valp; \ spcp->mylevel = SLC_VARIABLE|flags; \ } else { \ @@ -1283,8 +1164,8 @@ slc_init() } - void -slcstate() +void +slcstate(void) { printf("Special characters are %s values\n", slc_mode == SLC_IMPORT ? "remote default" : @@ -1292,17 +1173,16 @@ slcstate() "remote"); } - void -slc_mode_export() +void +slc_mode_export(void) { slc_mode = SLC_EXPORT; if (my_state_is_will(TELOPT_LINEMODE)) slc_export(); } - void -slc_mode_import(def) - int def; +void +slc_mode_import(int def) { slc_mode = def ? SLC_IMPORT : SLC_RVALUE; if (my_state_is_will(TELOPT_LINEMODE)) @@ -1316,11 +1196,10 @@ unsigned char slc_import_def[] = { IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE }; - void -slc_import(def) - int def; +void +slc_import(int def) { - if (NETROOM() > sizeof(slc_import_val)) { + if (NETROOM() > (int)sizeof(slc_import_val)) { if (def) { ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); @@ -1332,10 +1211,10 @@ slc_import(def) /*@*/ else printf("slc_import: not enough room\n"); } - void -slc_export() +void +slc_export(void) { - register struct spc *spcp; + struct spc *spcp; TerminalDefaultChars(); @@ -1356,13 +1235,11 @@ slc_export() setconnmode(1); /* Make sure the character values are set */ } - void -slc(cp, len) - register unsigned char *cp; - int len; +void +slc(unsigned char *cp, int len) { - register struct spc *spcp; - register int func,level; + struct spc *spcp; + int func,level; slc_start_reply(); @@ -1426,10 +1303,10 @@ slc(cp, len) setconnmode(1); /* set the new character values */ } - void -slc_check() +void +slc_check(void) { - register struct spc *spcp; + struct spc *spcp; slc_start_reply(); for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { @@ -1446,12 +1323,11 @@ slc_check() setconnmode(1); } - unsigned char slc_reply[128]; unsigned char *slc_replyp; - void -slc_start_reply() +void +slc_start_reply(void) { slc_replyp = slc_reply; *slc_replyp++ = IAC; @@ -1460,11 +1336,8 @@ slc_start_reply() *slc_replyp++ = LM_SLC; } - void -slc_add_reply(func, flags, value) - unsigned char func; - unsigned char flags; - cc_t value; +void +slc_add_reply(unsigned char func, unsigned char flags, cc_t value) { if ((*slc_replyp++ = func) == IAC) *slc_replyp++ = IAC; @@ -1474,10 +1347,10 @@ slc_add_reply(func, flags, value) *slc_replyp++ = IAC; } - void -slc_end_reply() +void +slc_end_reply(void) { - register int len; + int len; *slc_replyp++ = IAC; *slc_replyp++ = SE; @@ -1491,10 +1364,10 @@ slc_end_reply() /*@*/else printf("slc_end_reply: not enough room\n"); } - int -slc_update() +int +slc_update(void) { - register struct spc *spcp; + struct spc *spcp; int need_update = 0; for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { @@ -1529,13 +1402,11 @@ int old_env_value = OLD_ENV_VALUE; # endif #endif - void -env_opt(buf, len) - register unsigned char *buf; - register int len; +void +env_opt(unsigned char *buf, int len) { - register unsigned char *ep = 0, *epc = 0; - register int i; + unsigned char *ep = 0, *epc = 0; + int i; switch(buf[0]&0xff) { case TELQUAL_SEND: @@ -1603,8 +1474,8 @@ unsigned char *opt_reply; unsigned char *opt_replyp; unsigned char *opt_replyend; - void -env_opt_start() +void +env_opt_start(void) { if (opt_reply) opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); @@ -1623,19 +1494,18 @@ env_opt_start() *opt_replyp++ = TELQUAL_IS; } - void -env_opt_start_info() +void +env_opt_start_info(void) { env_opt_start(); if (opt_replyp) opt_replyp[-1] = TELQUAL_INFO; } - void -env_opt_add(ep) - register unsigned char *ep; +void +env_opt_add(unsigned char *ep) { - register unsigned char *vp, c; + unsigned char *vp, c; if (opt_reply == NULL) /*XXX*/ return; /*XXX*/ @@ -1643,12 +1513,12 @@ env_opt_add(ep) if (ep == NULL || *ep == '\0') { /* Send user defined variables first. */ env_default(1, 0); - while (ep = env_default(0, 0)) + while ((ep = env_default(0, 0))) env_opt_add(ep); /* Now add the list of well know variables. */ env_default(1, 1); - while (ep = env_default(0, 1)) + while ((ep = env_default(0, 1))) env_opt_add(ep); return; } @@ -1656,7 +1526,7 @@ env_opt_add(ep) if (opt_replyp + (vp ? strlen((char *)vp) : 0) + strlen((char *)ep) + 6 > opt_replyend) { - register int len; + int len; opt_replyend += OPT_REPLY_SIZE; len = opt_replyend - opt_reply; opt_reply = (unsigned char *)realloc(opt_reply, len); @@ -1678,7 +1548,7 @@ env_opt_add(ep) else *opt_replyp++ = ENV_USERVAR; for (;;) { - while (c = *ep++) { + while ((c = *ep++)) { switch(c&0xff) { case IAC: *opt_replyp++ = IAC; @@ -1692,7 +1562,7 @@ env_opt_add(ep) } *opt_replyp++ = c; } - if (ep = vp) { + if ((ep = vp)) { #ifdef OLD_ENVIRON if (telopt_environ == TELOPT_OLD_ENVIRON) *opt_replyp++ = old_env_value; @@ -1705,9 +1575,8 @@ env_opt_add(ep) } } - int -opt_welldefined(ep) - char *ep; +int +opt_welldefined(const char *ep) { if ((strcmp(ep, "USER") == 0) || (strcmp(ep, "DISPLAY") == 0) || @@ -1718,11 +1587,11 @@ opt_welldefined(ep) return(1); return(0); } - void -env_opt_end(emptyok) - register int emptyok; + +void +env_opt_end(int emptyok) { - register int len; + int len; len = opt_replyp - opt_reply + 2; if (emptyok || len > 6) { @@ -1742,12 +1611,12 @@ env_opt_end(emptyok) - int -telrcv() +int +telrcv(void) { - register int c; - register int scc; - register unsigned char *sbp; + int c; + int scc; + unsigned char *sbp; int count; int returnValue = 0; @@ -1792,23 +1661,6 @@ telrcv() telrcv_state = TS_IAC; break; } -# if defined(TN3270) - if (In3270) { - *Ifrontp++ = c; - while (scc > 0) { - c = *sbp++ & 0377, scc--; count++; -#ifdef ENCRYPTION - if (decrypt_input) - c = (*decrypt_input)(c); -#endif /* ENCRYPTION */ - if (c == IAC) { - telrcv_state = TS_IAC; - break; - } - *Ifrontp++ = c; - } - } else -# endif /* defined(TN3270) */ /* * The 'crmod' hack (see following) is needed * since we can't * set CRMOD on output only. @@ -1892,31 +1744,8 @@ process_iac: telrcv_state = TS_SB; continue; -# if defined(TN3270) - case EOR: - if (In3270) { - if (Ibackp == Ifrontp) { - Ibackp = Ifrontp = Ibuf; - ISend = 0; /* should have been! */ - } else { - Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1); - ISend = 1; - } - } - printoption("RCVD", IAC, EOR); - break; -# endif /* defined(TN3270) */ - case IAC: -# if !defined(TN3270) TTYADD(IAC); -# else /* !defined(TN3270) */ - if (In3270) { - *Ifrontp++ = IAC; - } else { - TTYADD(IAC); - } -# endif /* !defined(TN3270) */ break; case NOP: @@ -1931,21 +1760,18 @@ process_iac: case TS_WILL: printoption("RCVD", WILL, c); willoption(c); - SetIn3270(); telrcv_state = TS_DATA; continue; case TS_WONT: printoption("RCVD", WONT, c); wontoption(c); - SetIn3270(); telrcv_state = TS_DATA; continue; case TS_DO: printoption("RCVD", DO, c); dooption(c); - SetIn3270(); if (c == TELOPT_NAWS) { sendnaws(); } else if (c == TELOPT_LFLOW) { @@ -1961,7 +1787,6 @@ process_iac: dontoption(c); flushline = 1; setconnmode(0); /* set new tty mode (maybe) */ - SetIn3270(); telrcv_state = TS_DATA; continue; @@ -1995,7 +1820,6 @@ process_iac: printoption("In SUBOPTION processing, RCVD", IAC, c); suboption(); /* handle sub-option */ - SetIn3270(); telrcv_state = TS_IAC; goto process_iac; } @@ -2007,7 +1831,6 @@ process_iac: subpointer -= 2; SB_TERM(); suboption(); /* handle sub-option */ - SetIn3270(); telrcv_state = TS_DATA; } } @@ -2019,8 +1842,8 @@ process_iac: static int bol = 1, local = 0; - int -rlogin_susp() +int +rlogin_susp(void) { if (local) { local = 0; @@ -2031,8 +1854,8 @@ rlogin_susp() return(0); } - static int -telsnd() +static int +telsnd(void) { int tcc; int count; @@ -2042,8 +1865,8 @@ telsnd() tcc = 0; count = 0; while (NETROOM() > 2) { - register int sc; - register int c; + int sc; + int c; if (tcc == 0) { if (count) { @@ -2078,7 +1901,7 @@ telsnd() continue; } if (sc == escape) { - command(0, (char *)tbp, tcc); + command(0, tbp, tcc); bol = 1; count += tcc; tcc = 0; @@ -2094,7 +1917,7 @@ telsnd() } if ((sc == '\n') || (sc == '\r')) bol = 1; - } else if (sc == escape) { + } else if (escape != _POSIX_VDISABLE && sc == escape) { /* * Double escape is a pass through of a single escape character. */ @@ -2181,15 +2004,12 @@ telsnd() * */ - - int -Scheduler(block) - int block; /* should we block in the select ? */ +static int +Scheduler(int block) { /* One wants to be a bit careful about setting returnValue * to one, since a one implies we did some useful work, * and therefore probably won't be called to block next - * time (TN3270 mode only). */ int returnValue; int netin, netout, netex, ttyin, ttyout; @@ -2206,28 +2026,12 @@ Scheduler(block) my_want_state_is_will(TELOPT_BINARY)); ttyout = ring_full_count(&ttyoring); -#if defined(TN3270) - ttyin = ring_empty_count(&ttyiring) && (shell_active == 0); -#else /* defined(TN3270) */ - ttyin = ring_empty_count(&ttyiring); -#endif /* defined(TN3270) */ + ttyin = ring_empty_count(&ttyiring) && (clienteof == 0); -#if defined(TN3270) - netin = ring_empty_count(&netiring); -# else /* !defined(TN3270) */ netin = !ISend && ring_empty_count(&netiring); -# endif /* !defined(TN3270) */ netex = !SYNCHing; - /* If we have seen a signal recently, reset things */ -# if defined(TN3270) && (defined(unix) || defined(__APPLE__)) - if (HaveInput) { - HaveInput = 0; - (void) signal(SIGIO, inputAvailable); - } -#endif /* defined(TN3270) && (defined(unix) || defined(__APPLE__)) */ - /* Call to system code to process rings */ returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); @@ -2235,44 +2039,30 @@ Scheduler(block) /* Now, look at the input rings, looking for work to do. */ if (ring_full_count(&ttyiring)) { -# if defined(TN3270) - if (In3270) { - int c; - - c = DataFromTerminal(ttyiring.consume, - ring_full_consecutive(&ttyiring)); - if (c) { - returnValue = 1; - ring_consumed(&ttyiring, c); - } - } else { -# endif /* defined(TN3270) */ returnValue |= telsnd(); -# if defined(TN3270) - } -# endif /* defined(TN3270) */ } if (ring_full_count(&netiring)) { -# if !defined(TN3270) returnValue |= telrcv(); -# else /* !defined(TN3270) */ - returnValue = Push3270(); -# endif /* !defined(TN3270) */ } return returnValue; } +#ifdef AUTHENTICATION +#define __unusedhere +#else +#define __unusedhere __unused +#endif /* * Select from tty and network... */ - void -telnet(user) - char *user; +void +telnet(char *user __unusedhere) { sys_telnet_init(); -#if defined(AUTHENTICATION) || defined(ENCRYPTION) +#ifdef AUTHENTICATION +#ifdef ENCRYPTION { static char local_host[256] = { 0 }; @@ -2283,10 +2073,10 @@ telnet(user) auth_encrypt_init(local_host, hostname, "TELNET", 0); auth_encrypt_user(user); } -#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ -# if !defined(TN3270) +#endif +#endif if (telnetport) { -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION if (autologin) send_will(TELOPT_AUTHENTICATION, 1); #endif @@ -2302,14 +2092,12 @@ telnet(user) send_will(TELOPT_LINEMODE, 1); send_will(TELOPT_NEW_ENVIRON, 1); send_do(TELOPT_STATUS, 1); - if (env_getvalue((unsigned char *)"DISPLAY")) + if (env_getvalue("DISPLAY")) send_will(TELOPT_XDISPLOC, 1); if (eight) tel_enter_binary(eight); } -# endif /* !defined(TN3270) */ -# if !defined(TN3270) for (;;) { int schedValue; @@ -2325,45 +2113,6 @@ telnet(user) return; } } -# else /* !defined(TN3270) */ - for (;;) { - int schedValue; - - while (!In3270 && !shell_active) { - if (Scheduler(1) == -1) { - setcommandmode(); - return; - } - } - - while ((schedValue = Scheduler(0)) != 0) { - if (schedValue == -1) { - setcommandmode(); - return; - } - } - /* If there is data waiting to go out to terminal, don't - * schedule any more data for the terminal. - */ - if (ring_full_count(&ttyoring)) { - schedValue = 1; - } else { - if (shell_active) { - if (shell_continue() == 0) { - ConnectScreen(); - } - } else if (In3270) { - schedValue = DoTerminalOutput(); - } - } - if (schedValue && (shell_active == 0)) { - if (Scheduler(1) == -1) { - setcommandmode(); - return; - } - } - } -# endif /* !defined(TN3270) */ } #if 0 /* XXX - this not being in is a bug */ @@ -2378,9 +2127,8 @@ telnet(user) * character. */ - static char * -nextitem(current) - char *current; +static char * +nextitem(char *current) { if ((*current&0xff) != IAC) { return current+1; @@ -2393,7 +2141,7 @@ nextitem(current) return current+3; case SB: /* loop forever looking for the SE */ { - register char *look = current+2; + char *look = current+2; for (;;) { if ((*look++&0xff) == IAC) { @@ -2426,51 +2174,18 @@ nextitem(current) * us in any case. */ - static void -netclear() +static void +netclear(void) { -#if 0 /* XXX */ - register char *thisitem, *next; - char *good; -#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ - ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) - - thisitem = netobuf; - - while ((next = nextitem(thisitem)) <= netobuf.send) { - thisitem = next; - } - - /* Now, thisitem is first before/at boundary. */ - - good = netobuf; /* where the good bytes go */ - - while (netoring.add > thisitem) { - if (wewant(thisitem)) { - int length; - - next = thisitem; - do { - next = nextitem(next); - } while (wewant(next) && (nfrontp > next)); - length = next-thisitem; - memmove(good, thisitem, length); - good += length; - thisitem = next; - } else { - thisitem = nextitem(thisitem); - } - } - -#endif /* 0 */ + /* Deleted */ } /* * These routines add various telnet commands to the data stream. */ - static void -doflush() +static void +doflush(void) { NET2ADD(IAC, DO); NETADD(TELOPT_TM); @@ -2481,8 +2196,8 @@ doflush() printoption("SENT", DO, TELOPT_TM); } - void -xmitAO() +void +xmitAO(void) { NET2ADD(IAC, AO); printoption("SENT", IAC, AO); @@ -2491,24 +2206,22 @@ xmitAO() } } - - void -xmitEL() +void +xmitEL(void) { NET2ADD(IAC, EL); printoption("SENT", IAC, EL); } - void -xmitEC() +void +xmitEC(void) { NET2ADD(IAC, EC); printoption("SENT", IAC, EC); } - - int -dosynch() +int +dosynch(char *ch __unused) { netclear(); /* clear the path to the network */ NETADD(IAC); @@ -2520,11 +2233,11 @@ dosynch() int want_status_response = 0; - int -get_status() +int +get_status(char *ch __unused) { unsigned char tmp[16]; - register unsigned char *cp; + unsigned char *cp; if (my_want_state_is_dont(TELOPT_STATUS)) { printf("Remote side does not support STATUS option\n"); @@ -2546,8 +2259,8 @@ get_status() return 1; } - void -intp() +void +intp(void) { NET2ADD(IAC, IP); printoption("SENT", IAC, IP); @@ -2556,12 +2269,12 @@ intp() doflush(); } if (autosynch) { - dosynch(); + dosynch(NULL); } } - void -sendbrk() +void +sendbrk(void) { NET2ADD(IAC, BREAK); printoption("SENT", IAC, BREAK); @@ -2570,12 +2283,12 @@ sendbrk() doflush(); } if (autosynch) { - dosynch(); + dosynch(NULL); } } - void -sendabort() +void +sendabort(void) { NET2ADD(IAC, ABORT); printoption("SENT", IAC, ABORT); @@ -2584,12 +2297,12 @@ sendabort() doflush(); } if (autosynch) { - dosynch(); + dosynch(NULL); } } - void -sendsusp() +void +sendsusp(void) { NET2ADD(IAC, SUSP); printoption("SENT", IAC, SUSP); @@ -2598,19 +2311,19 @@ sendsusp() doflush(); } if (autosynch) { - dosynch(); + dosynch(NULL); } } - void -sendeof() +void +sendeof(void) { NET2ADD(IAC, xEOF); printoption("SENT", IAC, xEOF); } - void -sendayt() +void +sendayt(void) { NET2ADD(IAC, AYT); printoption("SENT", IAC, AYT); @@ -2620,12 +2333,12 @@ sendayt() * Send a window size update to the remote system. */ - void -sendnaws() +void +sendnaws(void) { long rows, cols; unsigned char tmp[16]; - register unsigned char *cp; + unsigned char *cp; if (my_state_is_wont(TELOPT_NAWS)) return; @@ -2652,9 +2365,8 @@ sendnaws() } } - void -tel_enter_binary(rw) - int rw; +void +tel_enter_binary(int rw) { if (rw&1) send_do(TELOPT_BINARY, 1); @@ -2662,9 +2374,8 @@ tel_enter_binary(rw) send_will(TELOPT_BINARY, 1); } - void -tel_leave_binary(rw) - int rw; +void +tel_leave_binary(int rw) { if (rw&1) send_dont(TELOPT_BINARY, 1); diff --git a/telnet.tproj/terminal.c b/telnet.tproj/terminal.c index de75e4d..ab72f07 100644 --- a/telnet.tproj/terminal.c +++ b/telnet.tproj/terminal.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -54,9 +31,15 @@ * SUCH DAMAGE. */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/terminal.c,v 1.2.8.2 2002/04/13 10:59:08 markm Exp $"); +#endif + #ifndef lint -static char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95"; -#endif /* not lint */ +static const char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95"; +#endif #include #include @@ -66,6 +49,10 @@ static char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95"; #include "externs.h" #include "types.h" +#ifdef ENCRYPTION +#include +#endif + Ring ttyoring, ttyiring; unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ]; @@ -111,8 +98,8 @@ cc_t termAytChar; * initialize the terminal data structures. */ - void -init_terminal() +void +init_terminal(void) { if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) { exit(1); @@ -123,7 +110,6 @@ init_terminal() autoflush = TerminalAutoFlush(); } - /* * Send as much data as possible to the terminal. * @@ -134,12 +120,10 @@ init_terminal() * n: All data - n was written out. */ - - int -ttyflush(drop) - int drop; +int +ttyflush(int drop) { - register int n, n0, n1; + int n, n0, n1; n0 = ring_full_count(&ttyoring); if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) { @@ -185,8 +169,8 @@ ttyflush(drop) */ - int -getconnmode() +int +getconnmode(void) { extern int linemode; int mode = 0; @@ -194,9 +178,6 @@ getconnmode() extern int kludgelinemode; #endif - if (In3270) - return(MODE_FLOW); - if (my_want_state_is_dont(TELOPT_ECHO)) mode |= MODE_ECHO; @@ -225,14 +206,13 @@ getconnmode() return(mode); } - void -setconnmode(force) - int force; +void +setconnmode(int force) { #ifdef ENCRYPTION static int enc_passwd = 0; #endif /* ENCRYPTION */ - register int newmode; + int newmode; newmode = getconnmode()|(force?MODE_FORCE:0); @@ -255,9 +235,8 @@ setconnmode(force) } - - void -setcommandmode() +void +setcommandmode(void) { TerminalNewMode(-1); } diff --git a/telnet.tproj/types.h b/telnet.tproj/types.h index 42b1b8f..191d311 100644 --- a/telnet.tproj/types.h +++ b/telnet.tproj/types.h @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. diff --git a/telnet.tproj/utilities.c b/telnet.tproj/utilities.c index 2957297..9935da3 100644 --- a/telnet.tproj/utilities.c +++ b/telnet.tproj/utilities.c @@ -1,26 +1,3 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ /* * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -54,18 +31,25 @@ * SUCH DAMAGE. */ +#include + +#ifdef __FBSDID +__FBSDID("$FreeBSD: src/crypto/telnet/telnet/utilities.c,v 1.2.8.2 2002/04/13 10:59:08 markm Exp $"); +#endif + #ifndef lint -static char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; -#endif /* not lint */ +static const char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; +#endif #define TELOPTS #define TELCMDS #define SLC_NAMES #include #include +#include #include - #include +#include #include "general.h" @@ -77,6 +61,13 @@ static char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95"; #include "externs.h" +#ifdef AUTHENTICATION +#include +#endif +#ifdef ENCRYPTION +#include +#endif + FILE *NetTrace = 0; /* Not in bss, since needs to stay */ int prettydump; @@ -86,11 +77,10 @@ int prettydump; * Upcase (in place) the argument. */ - void -upcase(argument) - register char *argument; +void +upcase(char *argument) { - register int c; + int c; while ((c = *argument) != 0) { if (islower(c)) { @@ -106,21 +96,11 @@ upcase(argument) * Compensate for differences in 4.2 and 4.3 systems. */ - int -SetSockOpt(fd, level, option, yesno) - int fd, level, option, yesno; +int +SetSockOpt(int fd, int level, int option, int yesno) { -#ifndef NOT43 return setsockopt(fd, level, option, (char *)&yesno, sizeof yesno); -#else /* NOT43 */ - if (yesno == 0) { /* Can't do that in 4.2! */ - fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n", - option); - return -1; - } - return setsockopt(fd, level, option, 0, 0); -#endif /* NOT43 */ } /* @@ -129,9 +109,8 @@ SetSockOpt(fd, level, option, yesno) unsigned char NetTraceFile[256] = "(standard output)"; - void -SetNetTrace(file) - register char *file; +void +SetNetTrace(char *file) { if (NetTrace && NetTrace != stdout) fclose(NetTrace); @@ -147,17 +126,13 @@ SetNetTrace(file) strcpy((char *)NetTraceFile, "(standard output)"); } - void -Dump(direction, buffer, length) - char direction; - unsigned char *buffer; - int length; +void +Dump(char direction, unsigned char *buffer, int length) { # define BYTES_PER_LINE 32 # define min(x,y) ((x' */ - unsigned char *pointer; /* where suboption data sits */ - int length; /* length of suboption data */ +void +printsub(char direction, unsigned char *pointer, int length) { - register int i; + int i; +#ifdef AUTHENTICATION char buf[512]; +#endif extern int want_status_response; if (showoptions || direction == 0 || @@ -328,7 +300,7 @@ printsub(direction, pointer, length) fprintf(NetTrace, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); if (length >= 3) { - register int j; + int j; i = pointer[length-2]; j = pointer[length-1]; @@ -442,7 +414,7 @@ printsub(direction, pointer, length) fprintf(NetTrace, " ?%d?", pointer[i]); break; -#if defined(AUTHENTICATION) +#ifdef AUTHENTICATION case TELOPT_AUTHENTICATION: fprintf(NetTrace, "AUTHENTICATION"); if (length < 2) { @@ -679,8 +651,8 @@ printsub(direction, pointer, length) break; case TELOPT_STATUS: { - register char *cp; - register int j, k; + const char *cp; + int j, k; fprintf(NetTrace, "STATUS"); @@ -793,7 +765,7 @@ printsub(direction, pointer, length) fprintf(NetTrace, "INFO "); env_common: { - register int noquote = 2; + int noquote = 2; #if defined(ENV_HACK) && defined(OLD_ENVIRON) extern int old_env_var, old_env_value; #endif @@ -842,7 +814,6 @@ printsub(direction, pointer, length) break; default: - def_case: if (isprint(pointer[i]) && pointer[i] != '"') { if (noquote) { putc('"', NetTrace); @@ -889,72 +860,52 @@ printsub(direction, pointer, length) * way to the kernel (thus the select). */ - void -EmptyTerminal() +static void +EmptyTerminal(void) { -#if defined(unix) || defined(__APPLE__) fd_set o; FD_ZERO(&o); -#endif /* defined(unix) || defined(__APPLE__) */ if (TTYBYTES() == 0) { -#if defined(unix) || defined(__APPLE__) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); /* wait for TTLOWAT */ -#endif /* defined(unix) || defined(__APPLE__) */ } else { while (TTYBYTES()) { (void) ttyflush(0); -#if defined(unix) || defined(__APPLE__) FD_SET(tout, &o); (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0, (struct timeval *) 0); /* wait for TTLOWAT */ -#endif /* defined(unix) || defined(__APPLE__) */ } } } - void -SetForExit() +static void +SetForExit(void) { setconnmode(0); -#if defined(TN3270) - if (In3270) { - Finish3270(); - } -#else /* defined(TN3270) */ do { (void)telrcv(); /* Process any incoming data */ EmptyTerminal(); } while (ring_full_count(&netiring)); /* While there is any */ -#endif /* defined(TN3270) */ setcommandmode(); fflush(stdout); fflush(stderr); -#if defined(TN3270) - if (In3270) { - StopScreen(1); - } -#endif /* defined(TN3270) */ setconnmode(0); EmptyTerminal(); /* Flush the path to the tty */ setcommandmode(); } - void -Exit(returnCode) - int returnCode; +void +Exit(int returnCode) { SetForExit(); exit(returnCode); } - void -ExitString(string, returnCode) - char *string; - int returnCode; +void +ExitString(const char *string, int returnCode) { SetForExit(); fwrite(string, 1, strlen(string), stderr); diff --git a/telnetd.tproj/Makefile b/telnetd.tproj/Makefile index e825ded..15956b4 100644 --- a/telnetd.tproj/Makefile +++ b/telnetd.tproj/Makefile @@ -26,7 +26,7 @@ MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /usr/libexec WINDOWS_INSTALLDIR = /usr/libexec PDO_UNIX_INSTALLDIR = /usr/libexec -LIBS = +LIBS = -lcurses DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) diff --git a/timed.tproj/timed.tproj/Makefile.postamble b/timed.tproj/timed.tproj/Makefile.postamble index 36381d4..ff71833 100644 --- a/timed.tproj/timed.tproj/Makefile.postamble +++ b/timed.tproj/timed.tproj/Makefile.postamble @@ -120,3 +120,6 @@ # # Note: on MS Windows, executables, have an extension, so rules and dependencies # for generated tools should use $(EXECUTABLE_EXT) on the end. +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 timed.8 "$(DSTROOT)/usr/share/man/man8/timed.8" diff --git a/timed.tproj/timed.tproj/Makefile.preamble b/timed.tproj/timed.tproj/Makefile.preamble index 74ce95a..692cd82 100644 --- a/timed.tproj/timed.tproj/Makefile.preamble +++ b/timed.tproj/timed.tproj/Makefile.preamble @@ -128,3 +128,4 @@ OTHER_HELP_DIRS = # Don't add more rules here unless you want the first one to be the default # target for make! Put all your targets in Makefile.postamble. +AFTER_INSTALL = after_install diff --git a/traceroute.tproj/Makefile.postamble b/traceroute.tproj/Makefile.postamble index de54c24..71d55a8 100644 --- a/traceroute.tproj/Makefile.postamble +++ b/traceroute.tproj/Makefile.postamble @@ -108,3 +108,6 @@ STRIPFLAGS = # Makefile API), which are rules that get invoked before and after the install # target runs. Such rules should be specified with the '::' syntax rather than # a single colon. +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 traceroute.8 "$(DSTROOT)/usr/share/man/man8/traceroute.8" diff --git a/traceroute.tproj/Makefile.preamble b/traceroute.tproj/Makefile.preamble index 2c9003c..019c674 100644 --- a/traceroute.tproj/Makefile.preamble +++ b/traceroute.tproj/Makefile.preamble @@ -111,3 +111,4 @@ OTHER_HELP_DIRS = # $(NAME).%d[.%d][.%d] and the following line must be uncommented. OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include +AFTER_INSTALL = after_install diff --git a/trsp.tproj/Makefile b/traceroute6.tproj/Makefile similarity index 88% rename from trsp.tproj/Makefile rename to traceroute6.tproj/Makefile index 4291787..fab9600 100644 --- a/trsp.tproj/Makefile +++ b/traceroute6.tproj/Makefile @@ -7,14 +7,14 @@ # and Makefile.postamble (both optional), and Makefile will include them. # -NAME = trsp +NAME = traceroute6 PROJECTVERSION = 2.8 PROJECT_TYPE = Tool -CFILES = trsp.c +CFILES = traceroute6.c -OTHERSRCS = Makefile.preamble Makefile Makefile.postamble trsp.8 +OTHERSRCS = Makefile.preamble Makefile Makefile.postamble traceroute6.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles @@ -23,7 +23,7 @@ MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /usr/sbin WINDOWS_INSTALLDIR = /usr/sbin PDO_UNIX_INSTALLDIR = /usr/sbin -LIBS = +LIBS = -lipsec DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) diff --git a/sliplogin.tproj/Makefile.postamble b/traceroute6.tproj/Makefile.postamble similarity index 97% rename from sliplogin.tproj/Makefile.postamble rename to traceroute6.tproj/Makefile.postamble index de54c24..463ddb1 100644 --- a/sliplogin.tproj/Makefile.postamble +++ b/traceroute6.tproj/Makefile.postamble @@ -108,3 +108,6 @@ STRIPFLAGS = # Makefile API), which are rules that get invoked before and after the install # target runs. Such rules should be specified with the '::' syntax rather than # a single colon. +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 traceroute6.8 "$(DSTROOT)/usr/share/man/man8/traceroute6.8" diff --git a/trsp.tproj/Makefile.preamble b/traceroute6.tproj/Makefile.preamble similarity index 98% rename from trsp.tproj/Makefile.preamble rename to traceroute6.tproj/Makefile.preamble index 2c9003c..6a78d85 100644 --- a/trsp.tproj/Makefile.preamble +++ b/traceroute6.tproj/Makefile.preamble @@ -111,3 +111,5 @@ OTHER_HELP_DIRS = # $(NAME).%d[.%d][.%d] and the following line must be uncommented. OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include +LOCAL_CFLAGS= -DINET6 -DIPSEC +AFTER_INSTALL = after_install diff --git a/sliplogin.tproj/PB.project b/traceroute6.tproj/PB.project similarity index 88% rename from sliplogin.tproj/PB.project rename to traceroute6.tproj/PB.project index 04d7107..8c17978 100644 --- a/sliplogin.tproj/PB.project +++ b/traceroute6.tproj/PB.project @@ -2,16 +2,14 @@ DOCICONFILES = (); FILESTABLE = { C_FILES = (); - H_FILES = (pathnames.h); + H_FILES = (); OTHER_LIBS = (); - OTHER_LINKED = (sliplogin.c); + OTHER_LINKED = (traceroute6.c); OTHER_SOURCES = ( Makefile.preamble, Makefile, Makefile.postamble, - sliplogin.8, - slip.hosts, - slip.login + traceroute6.8 ); PRECOMPILED_HEADERS = (); PROJECT_HEADERS = (); @@ -35,7 +33,7 @@ PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; PDO_UNIX_LINKEROPTIONS = ""; PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = sliplogin; + PROJECTNAME = traceroute6; PROJECTTYPE = Tool; PROJECTVERSION = 2.8; WINDOWS_BUILDDIR = ""; diff --git a/traceroute6.tproj/traceroute6.8 b/traceroute6.tproj/traceroute6.8 new file mode 100644 index 0000000..46915fe --- /dev/null +++ b/traceroute6.tproj/traceroute6.8 @@ -0,0 +1,123 @@ +.\" $KAME: traceroute6.8,v 1.8 2000/06/12 16:29:18 itojun 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. 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. +.\" +.\" $FreeBSD: src/usr.sbin/traceroute6/traceroute6.8,v 1.1.2.7 2001/08/16 15:56:37 ru Exp $ +.\" +.Dd May 17, 1998 +.Dt TRACEROUTE6 8 +.Os +.\" +.Sh NAME +.Nm traceroute6 +.Nd "print the route IPv6 packets will take to the destination" +.\" +.Sh SYNOPSIS +.Nm +.Bk -words +.Op Fl dlnrv +.Ek +.Bk -words +.Op Fl f Ar firsthop +.Ek +.Bk -words +.Op Fl g Ar gateway +.Ek +.Bk -words +.Op Fl m Ar hoplimit +.Ek +.Bk -words +.Op Fl p Ar port +.Ek +.Bk -words +.Op Fl q Ar probes +.Ek +.Bk -words +.Op Fl s Ar src +.Ek +.Bk -words +.Op Fl w Ar waittime +.Ek +.Bk -words +.Ar target +.Op Ar datalen +.Ek +.\" +.Sh DESCRIPTION +.Bl -tag -width Ds +.It Fl d +Debug mode. +.It Fl f Ar firsthop +Specify how many hops to skip in trace. +.It Fl g Ar gateway +Specify intermediate gateway +.Nm ( +uses routing header). +.It Fl m Ar hoplimit +Specify maximum hoplimit. +.It Fl l +Print both host hostnames and numeric addresses. +Normally +.Nm +prints only hostnames if +.Fl n +is not specified, and only numeric addresses if +.Fl n +is specified. +.It Fl n +Do not resolve numeric address to hostname. +.It Fl p Ar port +Set UDP port number to +.Ar port . +.It Fl q Ar probes +Set the number of probe per hop count to +.Ar probes . +.It Fl r +.It Fl s Ar src +.Ar Src +specifies the source IPv6 address to be used. +.It Fl v +Be verbose. +.It Fl w Ar waittime +Specify the delay time between probes. +.El +.\" +.Sh RETURN VALUES +The +.Nm +command will exit with 0 on success, and non-zero on errors. +.\" +.Sh SEE ALSO +.Xr ping 8 , +.Xr ping6 8 , +.Xr traceroute 8 +.\" +.Sh HISTORY +The +.Nm +command first appeared in WIDE hydrangea IPv6 protocol stack kit. diff --git a/traceroute6.tproj/traceroute6.c b/traceroute6.tproj/traceroute6.c new file mode 100644 index 0000000..63aee65 --- /dev/null +++ b/traceroute6.tproj/traceroute6.c @@ -0,0 +1,1357 @@ +/* $KAME: traceroute6.c,v 1.42 2001/05/08 04:36:41 itojun 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. 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. + */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson. + * + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93"; +#endif +static const char rcsid[] = + "$FreeBSD: src/usr.sbin/traceroute6/traceroute6.c,v 1.4.2.4 2001/07/03 11:02:18 ume Exp $"; +#endif /* not lint */ + +/* + * traceroute host - trace the route ip packets follow going to "host". + * + * Attempt to trace the route an ip packet would follow to some + * internet host. We find out intermediate hops by launching probe + * packets with a small ttl (time to live) then listening for an + * icmp "time exceeded" reply from a gateway. We start our probes + * with a ttl of one and increase by one until we get an icmp "port + * unreachable" (which means we got to "host") or hit a max (which + * defaults to 30 hops & can be changed with the -m flag). Three + * probes (change with -q flag) are sent at each ttl setting and a + * line is printed showing the ttl, address of the gateway and + * round trip time of each probe. If the probe answers come from + * different gateways, the address of each responding system will + * be printed. If there is no response within a 5 sec. timeout + * interval (changed with the -w flag), a "*" is printed for that + * probe. + * + * Probe packets are UDP format. We don't want the destination + * host to process them so the destination port is set to an + * unlikely value (if some clod on the destination is using that + * value, it can be changed with the -p flag). + * + * A sample use might be: + * + * [yak 71]% traceroute nis.nsf.net. + * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet + * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms + * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms + * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms + * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms + * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms + * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms + * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms + * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms + * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms + * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms + * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms + * + * Note that lines 2 & 3 are the same. This is due to a buggy + * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards + * packets with a zero ttl. + * + * A more interesting example is: + * + * [yak 72]% traceroute allspice.lcs.mit.edu. + * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max + * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms + * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms + * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms + * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms + * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms + * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms + * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms + * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms + * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms + * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms + * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms + * 12 * * * + * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms + * 14 * * * + * 15 * * * + * 16 * * * + * 17 * * * + * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms + * + * (I start to see why I'm having so much trouble with mail to + * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away + * either don't send ICMP "time exceeded" messages or send them + * with a ttl too small to reach us. 14 - 17 are running the + * MIT C Gateway code that doesn't send "time exceeded"s. God + * only knows what's going on with 12. + * + * The silent gateway 12 in the above may be the result of a bug in + * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) + * sends an unreachable message using whatever ttl remains in the + * original datagram. Since, for gateways, the remaining ttl is + * zero, the icmp "time exceeded" is guaranteed to not make it back + * to us. The behavior of this bug is slightly more interesting + * when it appears on the destination system: + * + * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms + * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms + * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms + * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms + * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms + * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms + * 7 * * * + * 8 * * * + * 9 * * * + * 10 * * * + * 11 * * * + * 12 * * * + * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! + * + * Notice that there are 12 "gateways" (13 is the final + * destination) and exactly the last half of them are "missing". + * What's really happening is that rip (a Sun-3 running Sun OS3.5) + * is using the ttl from our arriving datagram as the ttl in its + * icmp reply. So, the reply will time out on the return path + * (with no notice sent to anyone since icmp's aren't sent for + * icmp's) until we probe with a ttl that's at least twice the path + * length. I.e., rip is really only 7 hops away. A reply that + * returns with a ttl of 1 is a clue this problem exists. + * Traceroute prints a "!" after the time if the ttl is <= 1. + * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or + * non-standard (HPUX) software, expect to see this problem + * frequently and/or take care picking the target host of your + * probes. + * + * Other possible annotations after the time are !H, !N, !P (got a host, + * network or protocol unreachable, respectively), !S or !F (source + * route failed or fragmentation needed -- neither of these should + * ever occur and the associated gateway is busted if you see one). If + * almost all the probes result in some kind of unreachable, traceroute + * will give up and exit. + * + * Notes + * ----- + * This program must be run by root or be setuid. (I suggest that + * you *don't* make it setuid -- casual use could result in a lot + * of unnecessary traffic on our poor, congested nets.) + * + * This program requires a kernel mod that does not appear in any + * system available from Berkeley: A raw ip socket using proto + * IPPROTO_RAW must interpret the data sent as an ip datagram (as + * opposed to data to be wrapped in a ip datagram). See the README + * file that came with the source to this program for a description + * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may + * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE + * MODIFIED TO RUN THIS PROGRAM. + * + * The udp port usage may appear bizarre (well, ok, it is bizarre). + * The problem is that an icmp message only contains 8 bytes of + * data from the original datagram. 8 bytes is the size of a udp + * header so, if we want to associate replies with the original + * datagram, the necessary information must be encoded into the + * udp header (the ip id could be used but there's no way to + * interlock with the kernel's assignment of ip id's and, anyway, + * it would have taken a lot more kernel hacking to allow this + * code to set the ip id). So, to allow two or more users to + * use traceroute simultaneously, we use this task's pid as the + * source port (the high bit is set to move the port number out + * of the "likely" range). To keep track of which probe is being + * replied to (so times and/or hop counts don't get confused by a + * reply that was delayed in transit), we increment the destination + * port number before each probe. + * + * Don't use this as a coding example. I was trying to find a + * routing problem and this code sort-of popped out after 48 hours + * without sleep. I was amazed it ever compiled, much less ran. + * + * I stole the idea for this program from Steve Deering. Since + * the first release, I've learned that had I attended the right + * IETF working group meetings, I also could have stolen it from Guy + * Almes or Matt Mathis. I don't know (or care) who came up with + * the idea first. I envy the originators' perspicacity and I'm + * glad they didn't keep the idea a secret. + * + * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or + * enhancements to the original distribution. + * + * I've hacked up a round-trip-route version of this that works by + * sending a loose-source-routed udp datagram through the destination + * back to yourself. Unfortunately, SO many gateways botch source + * routing, the thing is almost worthless. Maybe one day... + * + * -- Van Jacobson (van@helios.ee.lbl.gov) + * Tue Dec 20 03:50:13 PST 1988 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#ifdef HAVE_POLL +#include +#endif +#include +#include +#include +#include + +#include +#include +#include + +#ifdef IPSEC +#include +#include +#endif + +#define DUMMY_PORT 10010 + +#define MAXPACKET 65535 /* max ip packet size */ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#ifndef FD_SET +#define NFDBITS (8*sizeof(fd_set)) +#define FD_SETSIZE NFDBITS +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) +#endif + +#define Fprintf (void)fprintf +#define Sprintf (void)sprintf +#define Printf (void)printf + +#ifndef HAVE_GETIPNODEBYNAME +#define getipnodebyname(x, y, z, u) gethostbyname2((x), (y)) +#define freehostent(x) +#endif + +/* + * format of a (udp) probe packet. + */ +struct opacket { + u_char seq; /* sequence number of this packet */ + u_char hops; /* hop limit of the packet */ + struct timeval tv; /* time packet left */ +}; + +u_char packet[512]; /* last inbound (icmp) packet */ +struct opacket *outpacket; /* last output (udp) packet */ + +int main __P((int, char *[])); +int wait_for_reply __P((int, struct msghdr *)); +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC +int setpolicy __P((int so, char *policy)); +#endif +#endif +void send_probe __P((int, int)); +struct udphdr *get_udphdr __P((struct ip6_hdr *, u_char *)); +int get_hoplim __P((struct msghdr *)); +double deltaT __P((struct timeval *, struct timeval *)); +char *pr_type __P((int)); +int packet_ok __P((struct msghdr *, int, int)); +void print __P((struct msghdr *, int)); +void tvsub __P((struct timeval *, struct timeval *)); +const char *inetname __P((struct sockaddr *)); +void usage __P((void)); + +int rcvsock; /* receive (icmp) socket file descriptor */ +int sndsock; /* send (udp) socket file descriptor */ +struct timezone tz; /* leftover */ + +struct msghdr rcvmhdr; +struct iovec rcviov[2]; +int rcvhlim; +struct in6_pktinfo *rcvpktinfo; + +struct sockaddr_in6 Src, Dst, Rcv; +int datalen; /* How much data */ +/* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */ +char rtbuf[2064]; +#ifdef USE_RFC2292BIS +struct ip6_rthdr *rth; +#endif +struct cmsghdr *cmsg; + +char *source = 0; +char *hostname; + +int nprobes = 3; +int first_hop = 1; +int max_hops = 30; +u_short ident; +u_short port = 32768+666; /* start udp dest port # for probe packets */ +int options; /* socket options */ +int verbose; +int waittime = 5; /* time to wait for response (in seconds) */ +int nflag; /* print addresses numerically */ +int lflag; /* print both numerical address & hostname */ + +#ifdef KAME_SCOPEID +const int niflag = NI_WITHSCOPEID; +#else +const int niflag = 0; +#endif + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct hostent *hp; + int error; + struct addrinfo hints, *res; + int ch, i, on, probe, seq, hops, rcvcmsglen; + static u_char *rcvcmsgbuf; + char hbuf[NI_MAXHOST], src0[NI_MAXHOST]; + char *ep; + + /* + * Receive ICMP + */ + if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { + perror("socket(ICMPv6)"); + exit(5); + } + + /* revoke privs */ + seteuid(getuid()); + setuid(getuid()); + + /* set a minimum set of socket options */ + on = 1; + /* specify to tell receiving interface */ +#ifdef IPV6_RECVPKTINFO + if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, + sizeof(on)) < 0) + err(1, "setsockopt(IPV6_RECVPKTINFO)"); +#else /* old adv. API */ + if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on, + sizeof(on)) < 0) + err(1, "setsockopt(IPV6_PKTINFO)"); +#endif + + /* specify to tell value of hoplimit field of received IP6 hdr */ +#ifdef IPV6_RECVHOPLIMIT + if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, + sizeof(on)) < 0) + err(1, "setsockopt(IPV6_RECVHOPLIMIT)"); +#else /* old adv. API */ + if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, + sizeof(on)) < 0) + err(1, "setsockopt(IPV6_HOPLIMIT)"); +#endif + + seq = 0; + + while ((ch = getopt(argc, argv, "df:g:lm:np:q:rs:w:v")) != -1) + switch(ch) { + case 'd': + options |= SO_DEBUG; + break; + case 'f': + ep = NULL; + first_hop = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid min hoplimit.\n"); + exit(1); + } + if (first_hop > max_hops) { + Fprintf(stderr, + "traceroute6: min hoplimit must be <= %d.\n", max_hops); + exit(1); + } + break; + case 'g': + hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno); + if (hp == NULL) { + Fprintf(stderr, + "traceroute6: unknown host %s\n", optarg); + exit(1); + } +#ifdef USE_RFC2292BIS + if (rth == NULL) { + /* + * XXX: We can't detect the number of + * intermediate nodes yet. + */ + if ((rth = inet6_rth_init((void *)rtbuf, + sizeof(rtbuf), + IPV6_RTHDR_TYPE_0, + 0)) == NULL) { + Fprintf(stderr, + "inet6_rth_init failed.\n"); + exit(1); + } + } + if (inet6_rth_add((void *)rth, + (struct in6_addr *)hp->h_addr)) { + Fprintf(stderr, + "inet6_rth_add failed for %s\n", + optarg); + exit(1); + } +#else /* old advanced API */ + if (cmsg == NULL) + cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0); + inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr, IPV6_RTHDR_LOOSE); +#endif + freehostent(hp); + break; + case 'l': + lflag++; + break; + case 'm': + ep = NULL; + max_hops = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid max hoplimit.\n"); + exit(1); + } + if (max_hops < first_hop) { + Fprintf(stderr, + "traceroute6: max hoplimit must be >= %d.\n", first_hop); + exit(1); + } + break; + case 'n': + nflag++; + break; + case 'p': + ep = NULL; + port = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: port.\n"); + exit(1); + } + if (port < 1) { + Fprintf(stderr, + "traceroute6: port must be >0.\n"); + exit(1); + } + break; + case 'q': + ep = NULL; + nprobes = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid nprobes.\n"); + exit(1); + } + if (nprobes < 1) { + Fprintf(stderr, + "traceroute6: nprobes must be >0.\n"); + exit(1); + } + break; + case 'r': + options |= SO_DONTROUTE; + break; + case 's': + /* + * set the ip source address of the outbound + * probe (e.g., on a multi-homed host). + */ + source = optarg; + break; + case 'v': + verbose++; + break; + case 'w': + ep = NULL; + waittime = strtoul(optarg, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid wait time.\n"); + exit(1); + } + if (waittime <= 1) { + Fprintf(stderr, + "traceroute6: wait must be >1 sec.\n"); + exit(1); + } + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 1 || argc > 2) + usage(); + +#if 1 + setvbuf(stdout, NULL, _IOLBF, BUFSIZ); +#else + setlinebuf (stdout); +#endif + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_INET6; + hints.ai_socktype = SOCK_RAW; + hints.ai_protocol = IPPROTO_ICMPV6; + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(*argv, NULL, &hints, &res); + if (error) { + (void)fprintf(stderr, + "traceroute6: %s\n", gai_strerror(error)); + exit(1); + } + if (res->ai_addrlen != sizeof(Dst)) { + (void)fprintf(stderr, + "traceroute6: size of sockaddr mismatch\n"); + exit(1); + } + memcpy(&Dst, res->ai_addr, res->ai_addrlen); + hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv; + if (!hostname) { + (void)fprintf(stderr, "traceroute6: not enough core\n"); + exit(1); + } + + if (*++argv) { + ep = NULL; + datalen = strtoul(*argv, &ep, 0); + if (!*argv || *ep) { + Fprintf(stderr, + "traceroute6: invalid packet length.\n"); + exit(1); + } + } + if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { + Fprintf(stderr, + "traceroute6: packet size must be 0 <= s < %ld.\n", + (long)(MAXPACKET - sizeof(struct opacket))); + exit(1); + } + datalen += sizeof(struct opacket); + outpacket = (struct opacket *)malloc((unsigned)datalen); + if (! outpacket) { + perror("malloc"); + exit(1); + } + (void) bzero((char *)outpacket, datalen); + + /* initialize msghdr for receiving packets */ + rcviov[0].iov_base = (caddr_t)packet; + rcviov[0].iov_len = sizeof(packet); + rcvmhdr.msg_name = (caddr_t)&Rcv; + rcvmhdr.msg_namelen = sizeof(Rcv); + rcvmhdr.msg_iov = rcviov; + rcvmhdr.msg_iovlen = 1; + rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) + + CMSG_SPACE(sizeof(int)); + if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) { + Fprintf(stderr, "traceroute6: malloc failed\n"); + exit(1); + } + rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf; + rcvmhdr.msg_controllen = rcvcmsglen; + + if (options & SO_DEBUG) + (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, + (char *)&on, sizeof(on)); + if (options & SO_DONTROUTE) + (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, + (char *)&on, sizeof(on)); +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + /* + * do not raise error even if setsockopt fails, kernel may have ipsec + * turned off. + */ + if (setpolicy(rcvsock, "in bypass") < 0) + errx(1, "%s", ipsec_strerror()); + if (setpolicy(rcvsock, "out bypass") < 0) + errx(1, "%s", ipsec_strerror()); +#else + { + int level = IPSEC_LEVEL_NONE; + + (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, + sizeof(level)); + (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, + sizeof(level)); +#ifdef IP_AUTH_TRANS_LEVEL + (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, + sizeof(level)); +#else + (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, + sizeof(level)); +#endif +#ifdef IP_AUTH_NETWORK_LEVEL + (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, + sizeof(level)); +#endif + } +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ + + /* + * Send UDP + */ + if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("socket(SOCK_DGRAM)"); + exit(5); + } +#ifdef SO_SNDBUF + if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, + sizeof(datalen)) < 0) { + perror("setsockopt(SO_SNDBUF)"); + exit(6); + } +#endif /* SO_SNDBUF */ + if (options & SO_DEBUG) + (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, + (char *)&on, sizeof(on)); + if (options & SO_DONTROUTE) + (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, + (char *)&on, sizeof(on)); +#ifdef USE_RFC2292BIS + if (rth) {/* XXX: there is no library to finalize the header... */ + rth->ip6r_len = rth->ip6r_segleft * 2; + if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR, + (void *)rth, (rth->ip6r_len + 1) << 3)) { + Fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n", + strerror(errno)); + exit(1); + } + } +#else /* old advanced API */ + if (cmsg != NULL) { + inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); + if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS, + rtbuf, cmsg->cmsg_len) < 0) { + Fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n", + strerror(errno)); + exit(1); + } + } +#endif /* USE_RFC2292BIS */ +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC + /* + * do not raise error even if setsockopt fails, kernel may have ipsec + * turned off. + */ + if (setpolicy(sndsock, "in bypass") < 0) + errx(1, "%s", ipsec_strerror()); + if (setpolicy(sndsock, "out bypass") < 0) + errx(1, "%s", ipsec_strerror()); +#else + { + int level = IPSEC_LEVEL_BYPASS; + + (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level, + sizeof(level)); + (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level, + sizeof(level)); +#ifdef IP_AUTH_TRANS_LEVEL + (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level, + sizeof(level)); +#else + (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level, + sizeof(level)); +#endif +#ifdef IP_AUTH_NETWORK_LEVEL + (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level, + sizeof(level)); +#endif + } +#endif /*IPSEC_POLICY_IPSEC*/ +#endif /*IPSEC*/ + + /* + * Source selection + */ + bzero(&Src, sizeof(Src)); + if (source) { + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(source, "0", &hints, &res); + if (error) { + Printf("traceroute6: %s: %s\n", source, + gai_strerror(error)); + exit(1); + } + if (res->ai_addrlen > sizeof(Src)) { + Printf("traceroute6: %s: %s\n", source, + gai_strerror(error)); + exit(1); + } + memcpy(&Src, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + } else { + struct sockaddr_in6 Nxt; + int dummy, len; + + Nxt = Dst; + Nxt.sin6_port = htons(DUMMY_PORT); + if (cmsg != NULL) + bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr, + sizeof(Nxt.sin6_addr)); + if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + exit(1); + } + if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) { + perror("connect"); + exit(1); + } + len = sizeof(Src); + if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) { + perror("getsockname"); + exit(1); + } + if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len, + src0, sizeof(src0), NULL, 0, + NI_NUMERICHOST | niflag)) { + Fprintf(stderr, "getnameinfo failed for source\n"); + exit(1); + } + source = src0; + close(dummy); + } + +#if 1 + ident = (getpid() & 0xffff) | 0x8000; +#else + ident = 0; /*let the kernel pick one*/ +#endif + Src.sin6_port = htons(ident); + if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) { + perror("bind"); + exit(1); + } + + if (ident == 0) { + int len; + + len = sizeof(Src); + if (getsockname(sndsock, (struct sockaddr *)&Src, &i) < 0) { + perror("getsockname"); + exit(1); + } + ident = ntohs(Src.sin6_port); + } + + /* + * Message to users + */ + if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag)) + strlcpy(hbuf, "(invalid)", sizeof(hbuf)); + Fprintf(stderr, "traceroute6"); + Fprintf(stderr, " to %s (%s)", hostname, hbuf); + if (source) + Fprintf(stderr, " from %s", source); + Fprintf(stderr, + ", %d hops max, %d byte packets\n", + max_hops, datalen); + (void) fflush(stderr); + + if (first_hop > 1) + Printf("Skipping %d intermediate hops\n", first_hop - 1); + + /* + * Main loop + */ + for (hops = first_hop; hops <= max_hops; ++hops) { + struct in6_addr lastaddr; + int got_there = 0; + int unreachable = 0; + + Printf("%2d ", hops); + bzero(&lastaddr, sizeof(lastaddr)); + for (probe = 0; probe < nprobes; ++probe) { + int cc; + struct timeval t1, t2; + struct timezone tz; + + (void) gettimeofday(&t1, &tz); + send_probe(++seq, hops); + while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) { + (void) gettimeofday(&t2, &tz); + if ((i = packet_ok(&rcvmhdr, cc, seq))) { + if (! IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr, + &lastaddr)) { + print(&rcvmhdr, cc); + lastaddr = Rcv.sin6_addr; + } + Printf(" %g ms", deltaT(&t1, &t2)); + switch(i - 1) { + case ICMP6_DST_UNREACH_NOROUTE: + ++unreachable; + Printf(" !N"); + break; + case ICMP6_DST_UNREACH_ADMIN: + ++unreachable; + Printf(" !P"); + break; + case ICMP6_DST_UNREACH_NOTNEIGHBOR: + ++unreachable; + Printf(" !S"); + break; + case ICMP6_DST_UNREACH_ADDR: + ++unreachable; + Printf(" !A"); + break; + case ICMP6_DST_UNREACH_NOPORT: + if (rcvhlim >= 0 && + rcvhlim <= 1) + Printf(" !"); + ++got_there; + break; + } + break; + } + } + if (cc == 0) + Printf(" *"); + (void) fflush(stdout); + } + putchar('\n'); + if (got_there || + (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) { + exit(0); + } + } + + exit(0); +} + +int +wait_for_reply(sock, mhdr) + int sock; + struct msghdr *mhdr; +{ +#ifdef HAVE_POLL + struct pollfd pfd[1]; + int cc = 0; + + pfd[0].fd = sock; + pfd[0].events = POLLIN; + pfd[0].revents = 0; + + if (poll(pfd, 1, waittime * 1000) > 0) + cc = recvmsg(rcvsock, mhdr, 0); + + return(cc); +#else + fd_set *fdsp; + struct timeval wait; + int cc = 0, fdsn; + + fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask); + if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) + err(1, "malloc"); + memset(fdsp, 0, fdsn); + FD_SET(sock, fdsp); + wait.tv_sec = waittime; wait.tv_usec = 0; + + if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0) + cc = recvmsg(rcvsock, mhdr, 0); + + free(fdsp); + return(cc); +#endif +} + +#ifdef IPSEC +#ifdef IPSEC_POLICY_IPSEC +int +setpolicy(so, policy) + int so; + char *policy; +{ + char *buf; + + buf = ipsec_set_policy(policy, strlen(policy)); + if (buf == NULL) { + warnx("%s", ipsec_strerror()); + return -1; + } + (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY, + buf, ipsec_get_policylen(buf)); + + free(buf); + + return 0; +} +#endif +#endif + +void +send_probe(seq, hops) + int seq, hops; +{ + struct opacket *op = outpacket; + int i; + + if(setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + (char *)&hops, sizeof(hops)) < 0) { + perror("setsockopt IPV6_UNICAST_HOPS"); + } + + Dst.sin6_port = htons(port + seq); + + op->seq = seq; + op->hops = hops; + (void) gettimeofday(&op->tv, &tz); + + i = sendto(sndsock, (char *)outpacket, datalen , 0, + (struct sockaddr *)&Dst, Dst.sin6_len); + if (i < 0 || i != datalen) { + if (i<0) + perror("sendto"); + Printf("traceroute6: wrote %s %d chars, ret=%d\n", hostname, + datalen, i); + (void) fflush(stdout); + } +} + +int +get_hoplim(mhdr) + struct msghdr *mhdr; +{ + struct cmsghdr *cm; + + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_HOPLIMIT && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + return(*(int *)CMSG_DATA(cm)); + } + + return(-1); +} + +double +deltaT(t1p, t2p) + struct timeval *t1p, *t2p; +{ + register double dt; + + dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + + (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; + return (dt); +} + + +/* + * Convert an ICMP "type" field to a printable string. + */ +char * +pr_type(t0) + int t0; +{ + u_char t = t0 & 0xff; + char *cp; + + switch (t) { + case ICMP6_DST_UNREACH: + cp = "Destination Unreachable"; + break; + case ICMP6_PACKET_TOO_BIG: + cp = "Pakcet Too Big"; + break; + case ICMP6_TIME_EXCEEDED: + cp = "Time Exceeded"; + break; + case ICMP6_PARAM_PROB: + cp = "Parameter Problem"; + break; + case ICMP6_ECHO_REQUEST: + cp = "Echo Request"; + break; + case ICMP6_ECHO_REPLY: + cp = "Echo Reply"; + break; + case ICMP6_MEMBERSHIP_QUERY: + cp = "Group Membership Query"; + break; + case ICMP6_MEMBERSHIP_REPORT: + cp = "Group Membership Report"; + break; + case ICMP6_MEMBERSHIP_REDUCTION: + cp = "Group Membership Reduction"; + break; + case ND_ROUTER_SOLICIT: + cp = "Router Solicitation"; + break; + case ND_ROUTER_ADVERT: + cp = "Router Advertisement"; + break; + case ND_NEIGHBOR_SOLICIT: + cp = "Neighbor Solicitation"; + break; + case ND_NEIGHBOR_ADVERT: + cp = "Neighbor Advertisement"; + break; + case ND_REDIRECT: + cp = "Redirect"; + break; + default: + cp = "Unknown"; + break; + } + return cp; +} + + +int +packet_ok(mhdr, cc, seq) + struct msghdr *mhdr; + int cc; + int seq; +{ + register struct icmp6_hdr *icp; + struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; + u_char type, code; + char *buf = (char *)mhdr->msg_iov[0].iov_base; + struct cmsghdr *cm; + int *hlimp; + char hbuf[NI_MAXHOST]; + +#ifdef OLDRAWSOCKET + int hlen; + struct ip6_hdr *ip; +#endif + +#ifdef OLDRAWSOCKET + ip = (struct ip6_hdr *) buf; + hlen = sizeof(struct ip6_hdr); + if (cc < hlen + sizeof(struct icmp6_hdr)) { + if (verbose) { + if (getnameinfo((struct sockaddr *)from, from->sin6_len, + hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST | niflag) != 0) + strlcpy(hbuf, "invalid", sizeof(hbuf)); + Printf("packet too short (%d bytes) from %s\n", cc, + hbuf); + } + return (0); + } + cc -= hlen; + icp = (struct icmp6_hdr *)(buf + hlen); +#else + if (cc < sizeof(struct icmp6_hdr)) { + if (verbose) { + if (getnameinfo((struct sockaddr *)from, from->sin6_len, + hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST | niflag) != 0) + strlcpy(hbuf, "invalid", sizeof(hbuf)); + Printf("data too short (%d bytes) from %s\n", cc, hbuf); + } + return(0); + } + icp = (struct icmp6_hdr *)buf; +#endif + /* get optional information via advanced API */ + rcvpktinfo = NULL; + hlimp = NULL; + for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm; + cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) { + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_PKTINFO && + cm->cmsg_len == + CMSG_LEN(sizeof(struct in6_pktinfo))) + rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm)); + + if (cm->cmsg_level == IPPROTO_IPV6 && + cm->cmsg_type == IPV6_HOPLIMIT && + cm->cmsg_len == CMSG_LEN(sizeof(int))) + hlimp = (int *)CMSG_DATA(cm); + } + if (rcvpktinfo == NULL || hlimp == NULL) { + warnx("failed to get received hop limit or packet info"); +#if 0 + return(0); +#else + rcvhlim = 0; /*XXX*/ +#endif + } + else + rcvhlim = *hlimp; + + type = icp->icmp6_type; + code = icp->icmp6_code; + if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) + || type == ICMP6_DST_UNREACH) { + struct ip6_hdr *hip; + struct udphdr *up; + + hip = (struct ip6_hdr *)(icp + 1); + if ((up = get_udphdr(hip, (u_char *)(buf + cc))) == NULL) { + if (verbose) + warnx("failed to get upper layer header"); + return(0); + } + if (up->uh_sport == htons(ident) && + up->uh_dport == htons(port+seq)) + return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1); + } + if (verbose) { + int i; + u_int8_t *p; + char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN]; + + if (getnameinfo((struct sockaddr *)from, from->sin6_len, + sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) + strlcpy(sbuf, "invalid", sizeof(hbuf)); + Printf("\n%d bytes from %s to %s", cc, sbuf, + rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, + dbuf, sizeof(dbuf)) + : "?"); + Printf(": icmp type %d (%s) code %d\n", type, pr_type(type), + icp->icmp6_code); + p = (u_int8_t *)(icp + 1); +#define WIDTH 16 + for (i = 0; i < cc; i++) { + if (i % WIDTH == 0) + Printf("%04x:", i); + if (i % 4 == 0) + Printf(" "); + Printf("%02x", p[i]); + if (i % WIDTH == WIDTH - 1) + Printf("\n"); + } + if (cc % WIDTH != 0) + Printf("\n"); + } + return(0); +} + +/* + * Increment pointer until find the UDP header. + */ +struct udphdr * +get_udphdr(ip6, lim) + struct ip6_hdr *ip6; + u_char *lim; +{ + u_char *cp = (u_char *)ip6, nh; + int hlen; + + if (cp + sizeof(*ip6) >= lim) + return(NULL); + + nh = ip6->ip6_nxt; + cp += sizeof(struct ip6_hdr); + + while(lim - cp >= 8) { + switch(nh) { + case IPPROTO_ESP: + case IPPROTO_TCP: + case IPPROTO_ICMPV6: + return(NULL); + case IPPROTO_UDP: + return((struct udphdr *)cp); + case IPPROTO_FRAGMENT: + hlen = sizeof(struct ip6_frag); + nh = ((struct ip6_frag *)cp)->ip6f_nxt; + break; + case IPPROTO_AH: + hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2; + nh = ((struct ip6_ext *)cp)->ip6e_nxt; + break; + default: + hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3; + nh = ((struct ip6_ext *)cp)->ip6e_nxt; + break; + } + + cp += hlen; + } + + return(NULL); +} + +void +print(mhdr, cc) + struct msghdr *mhdr; + int cc; +{ + struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name; + char hbuf[NI_MAXHOST]; + + if (getnameinfo((struct sockaddr *)from, from->sin6_len, + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST | niflag) != 0) + strlcpy(hbuf, "invalid", sizeof(hbuf)); + if (nflag) + Printf(" %s", hbuf); + else if (lflag) + Printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf); + else + Printf(" %s", inetname((struct sockaddr *)from)); + + if (verbose) { +#ifdef OLDRAWSOCKET + Printf(" %d bytes to %s", cc, + rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, + hbuf, sizeof(hbuf)) + : "?"); +#else + Printf(" %d bytes of data to %s", cc, + rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr, + hbuf, sizeof(hbuf)) + : "?"); +#endif + } +} + +/* + * Subtract 2 timeval structs: out = out - in. + * Out is assumed to be >= in. + */ +void +tvsub(out, in) + register struct timeval *out, *in; +{ + if ((out->tv_usec -= in->tv_usec) < 0) { + out->tv_sec--; + out->tv_usec += 1000000; + } + out->tv_sec -= in->tv_sec; +} + + +/* + * Construct an Internet address representation. + * If the nflag has been supplied, give + * numeric value, otherwise try for symbolic name. + */ +const char * +inetname(sa) + struct sockaddr *sa; +{ + register char *cp; + static char line[NI_MAXHOST]; + static char domain[MAXHOSTNAMELEN + 1]; + static int first = 1; + + if (first && !nflag) { + first = 0; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = index(domain, '.'))) + (void) strlcpy(domain, cp + 1, sizeof(domain)); + else + domain[0] = 0; + } + cp = NULL; + if (!nflag) { + if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, + NI_NAMEREQD) == 0) { + if ((cp = index(line, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = line; + } + } + if (cp) + return cp; + + if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0, + NI_NUMERICHOST | niflag) != 0) + strlcpy(line, "invalid", sizeof(line)); + return line; +} + +void +usage() +{ + (void)fprintf(stderr, +"usage: traceroute6 [-dlnrv] [-f firsthop] [-g gateway] [-m hoplimit] [-p port]\n" +" [-q probes] [-s src] [-w waittime] target [datalen]\n"); + exit(1); +} diff --git a/trpt.tproj/Makefile b/trpt.tproj/Makefile index 3a0f3a7..5b58165 100644 --- a/trpt.tproj/Makefile +++ b/trpt.tproj/Makefile @@ -23,7 +23,7 @@ MAKEFILE = tool.make NEXTSTEP_INSTALLDIR = /usr/sbin WINDOWS_INSTALLDIR = /usr/sbin PDO_UNIX_INSTALLDIR = /usr/sbin -LIBS = +LIBS = -lcurses DEBUG_LIBS = $(LIBS) PROF_LIBS = $(LIBS) diff --git a/trpt.tproj/trpt.c b/trpt.tproj/trpt.c index 63ad900..0f1f66a 100644 --- a/trpt.tproj/trpt.c +++ b/trpt.tproj/trpt.c @@ -285,7 +285,7 @@ again: if (--tcp_debx < 0) continue; ntime = ntohl(td->td_time); tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, - &td->td_th, td->td_req); + &td->td_ti.ti_t, td->td_req); if (i == tcp_debx) goto done; } @@ -295,7 +295,7 @@ again: if (--tcp_debx < 0) continue; ntime = ntohl(td->td_time); tcp_trace(td->td_act, td->td_ostate, td->td_tcb, &td->td_cb, - &td->td_th, td->td_req); + &td->td_ti.ti_t, td->td_req); } done: if (follow) { prev_debx = tcp_debx + 1; diff --git a/trsp.tproj/Makefile.postamble b/trsp.tproj/Makefile.postamble deleted file mode 100644 index a38e0df..0000000 --- a/trsp.tproj/Makefile.postamble +++ /dev/null @@ -1,110 +0,0 @@ -############################################################################### -# NeXT Makefile.postamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. Additional -# rules (e.g., after_install) that are defined by the developer should be -# defined in this file. -# -############################################################################### -# -# Here are the variables exported by the common "app" makefiles that can be -# used in any customizations you make to the template below: -# -# PRODUCT_ROOT - Name of top-level app-wrapper (e.g., Webster.app) -# OFILE_DIR - Directory into which .o object files are generated. -# (Note that this name is calculated based on the target -# architectures specified in Project Builder). -# DERIVED_SRC_DIR - Directory used for all other derived files -# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations -# -# NAME - name of application, bundle, subproject, palette, etc. -# LANGUAGE - langage in which the project is written (default "English") -# ENGLISH - boolean flag set iff $(LANGUAGE) = "English" -# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese" -# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project -# GLOBAL_RESOURCES - non-localized resources of project -# PROJECTVERSION - version of ProjectBuilder that output Makefile -# APPICON - application icon file -# DOCICONS - dock icon files -# ICONSECTIONS - Specifies icon sections when linking executable -# -# CLASSES - Class implementation files in project. -# HFILES - Header files in project. -# MFILES - Other Objective-C source files in project. -# CFILES - Other C source files in project. -# PSWFILES - .psw files in the project -# PSWMFILES - .pswm files in the project -# SUBPROJECTS - Subprojects of this project -# BUNDLES - Bundle subprojects of this project -# OTHERSRCS - Other miscellaneous sources of this project -# OTHERLINKED - Source files not matching a standard source extention -# -# LIBS - Libraries to link with when making app target -# DEBUG_LIBS - Libraries to link with when making debug target -# PROF_LIBS - Libraries to link with when making profile target -# OTHERLINKEDOFILES - Other relocatable files to (always) link in. -# -# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles -# MAKEFILEDIR - Directory in which to find $(MAKEFILE) -# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make) -# INSTALLDIR - Directory app will be installed into by 'install' target - - -# Change defaults assumed by the standard app makefiles here. Edit the -# following default values as appropriate. (Note that if no Makefile.postamble -# exists, these values will have defaults set in common.make). - -# Add Makefile.preamble, Makefile.postamble, and Makefile.dependencies here if -# you would like changes to them to invalidate previous builds. The project -# depends on $(MAKEFILES) so that changes to Makefiles will trigger a re-build. -#MAKEFILES = Makefile - -# Optimization flag passed to compiler: -#OPTIMIZATION_CFLAG = -O - -# Flags always passed to compiler: -#COMMON_CFLAGS = $(PROJECT_SPECIFIC_CFLAGS) -g -Wall - -# Flags passed to compiler in normal 'app' compiles: -#NORMAL_CFLAGS = $(COMMON_CFLAGS) $(OPTIMIZATION_CFLAG) - -# Flags passed to compiler in 'debug' compiles: -#DEBUG_CFLAGS = $(COMMON_CFLAGS) -DDEBUG - -# Flags passed to compiler in 'profile' compiles -#PROFILE_CFLAGS = $(COMMON_CFLAGS) -pg $(OPTIMIZATION_CFLAG) -DPROFILE - -# Flags passed to yacc -#YFLAGS = -d - -# Ownership and permissions of files installed by 'install' target -#INSTALL_AS_USER = root # User to chown app to -INSTALL_AS_GROUP = kmem # Group to chgrp app to -INSTALL_PERMISSIONS = 2555 # If set, 'install' chmod's executable to this - -# Options to strip for bundles, apps with bundles, and apps without bundles, -# respectively. -#RELOCATABLE_STRIP_OPTS = -x -u -#DYLD_APP_STRIP_OPTS = -A -n -#APP_STRIP_OPTS = -#TOOL_STRIP_OPTS = -#LIBRARY_STRIP_OPTS = -x -S # Note: -S strips debugging symbols -# (Note: APP_STRIP_OPTS and TOOL_STRIP_OPTS default to empty, but -# developers doing their own dynamic loading should set this to -# $(DYLD_APP_STRIP_OPTS)). -STRIPFLAGS = - - -######################################################################### -# Put rules to extend the behavior of the standard Makefiles here. Typical -# user-defined rules are before_install and after_install (please don't -# redefine things like install or app, as they are owned by the top-level -# Makefile API), which are rules that get invoked before and after the install -# target runs. Such rules should be specified with the '::' syntax rather than -# a single colon. diff --git a/trsp.tproj/trsp.8 b/trsp.tproj/trsp.8 deleted file mode 100644 index 19c23b4..0000000 --- a/trsp.tproj/trsp.8 +++ /dev/null @@ -1,141 +0,0 @@ -.\" Copyright (c) 1985, 1991, 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. -.\" -.\" @(#)trsp.8 8.1 (Berkeley) 6/6/93 -.\" -.Dd June 6, 1993 -.Dt TRSP 8 -.Os BSD 4.2 -.Sh NAME -.Nm trsp -.Nd transliterate sequenced packet protocol trace -.Sh SYNOPSIS -.Nm trsp -.Op Fl a -.Op Fl s -.Op Fl t -.Op Fl j -.Op Fl p Ar hex-address -.Oo -.Ar system Op Ar core -.Oc -.Sh DESCRIPTION -.Xr Trpt -interrogates the buffer of -.Tn SPP -trace records created -when a socket is marked for -.Dq debugging -(see -.Xr setsockopt 2 ) , -and prints a readable description of these records. -When no options are supplied, -.Nm trsp -prints all the trace records found in the system -grouped according to -.Tn SPP -connection protocol control -block -.Pq Tn PCB . -The following options may be used to -alter this behavior. -.Bl -tag -width Ds -.It Fl a -In addition to the normal output, -print the values of the source and destination -addresses for each packet recorded. -.It Fl j -Just give a list of the protocol control block -addresses for which there are trace records. -.It Fl p -Show only trace records associated with the protocol -control block at the given address, -.Ar hex-address . -.It Fl s -in addition to the normal output, -print a detailed description of the packet -sequencing information. -.It Fl t -in addition to the normal output, -print the values for all timers at each -point in the trace, -.El -.Pp -The recommended use of -.Nm trsp -is as follows. -Isolate the problem and enable debugging on the -socket(s) involved in the connection. -Find the address of the protocol control blocks -associated with the sockets using the -.Fl A -option to -.Xr netstat 1 . -Then run -.Nm trsp -with the -.Fl p -option, supplying the associated -protocol control block addresses. If there are -many sockets using the debugging option, the -.Fl j -option may be useful in checking to see if -any trace records are present for the socket in -question. -.Pp -If debugging is being performed on a system or -core file other than the default, the last two -arguments may be used to supplant the defaults. -.Sh FILES -.Bl -tag -width /dev/kmem -compact -.It Pa /vmunix -.It Pa /dev/kmem -.El -.Sh SEE ALSO -.Xr netstat 1 , -.Xr setsockopt 2 -.Sh DIAGNOSTICS -.Bl -tag -width Ds -.It Sy no namelist -When the system image doesn't -contain the proper symbols to find the trace buffer; -others which should be self explanatory. -.Sh BUGS -Should also print the data for each input or output, -but this is not saved in the race record. -.Pp -The output format is inscrutable and should be described -here. -.Sh HISTORY -The -.Nm -command appeared in -.Bx 4.3 . diff --git a/trsp.tproj/trsp.c b/trsp.tproj/trsp.c deleted file mode 100644 index 6895ff9..0000000 --- a/trsp.tproj/trsp.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 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. - */ - -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1985, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)trsp.c 8.1 (Berkeley) 6/6/93"; -#endif /* not lint */ - -#include -#include -#include -#include -#include -#include -#define PRUREQUESTS -#include - -#include -#include - -#define TCPSTATES -#include -#define TCPTIMERS -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#define SANAMES -#include - -#include -#include -#include -#include - -unsigned long ntime; -int sflag; -int tflag; -int jflag; -int aflag; -int zflag; -int numeric(); -struct nlist nl[] = { - { "_spp_debug" }, - { "_spp_debx" }, - 0 -}; -struct spp_debug spp_debug[SPP_NDEBUG]; -caddr_t spp_pcbs[SPP_NDEBUG]; -int spp_debx; - -main(argc, argv) - int argc; - char **argv; -{ - int i, mask = 0, npcbs = 0; - char *system, *core; - - system = _PATH_UNIX; - core = _PATH_KMEM; - - argc--, argv++; -again: - if (argc > 0 && !strcmp(*argv, "-a")) { - aflag++, argc--, argv++; - goto again; - } - if (argc > 0 && !strcmp(*argv, "-z")) { - zflag++, argc--, argv++; - goto again; - } - if (argc > 0 && !strcmp(*argv, "-s")) { - sflag++, argc--, argv++; - goto again; - } - if (argc > 0 && !strcmp(*argv, "-t")) { - tflag++, argc--, argv++; - goto again; - } - if (argc > 0 && !strcmp(*argv, "-j")) { - jflag++, argc--, argv++; - goto again; - } - if (argc > 0 && !strcmp(*argv, "-p")) { - argc--, argv++; - if (argc < 1) { - fprintf(stderr, "-p: missing sppcb address\n"); - exit(1); - } - if (npcbs >= SPP_NDEBUG) { - fprintf(stderr, "-p: too many pcb's specified\n"); - exit(1); - } - sscanf(*argv, "%x", &spp_pcbs[npcbs++]); - argc--, argv++; - goto again; - } - if (argc > 0) { - system = *argv; - argc--, argv++; - mask++; - /* - * Discard setgid privileges if not the running kernel so that - * bad guys can't print interesting stuff from kernel memory. - */ - setgid(getgid()); - } - if (argc > 0) { - core = *argv; - argc--, argv++; - mask++; - setgid(getgid()); - } - (void) nlist(system, nl); - if (nl[0].n_value == 0) { - fprintf(stderr, "trsp: %s: no namelist\n", system); - exit(1); - } - (void) close(0); - if (open(core, 0) < 0) { - fprintf(stderr, "trsp: "); perror(core); - exit(2); - } - if (mask) { - nl[0].n_value &= 0x7fffffff; - nl[1].n_value &= 0x7fffffff; - } - (void) lseek(0, nl[1].n_value, 0); - if (read(0, &spp_debx, sizeof (spp_debx)) != sizeof (spp_debx)) { - fprintf(stderr, "trsp: "); perror("spp_debx"); - exit(3); - } - printf("spp_debx=%d\n", spp_debx); - (void) lseek(0, nl[0].n_value, 0); - if (read(0, spp_debug, sizeof (spp_debug)) != sizeof (spp_debug)) { - fprintf(stderr, "trsp: "); perror("spp_debug"); - exit(3); - } - /* - * Here, we just want to clear out the old trace data and start over. - */ - if (zflag) { - char *cp = (char *) spp_debug, - *cplim = cp + sizeof(spp_debug); - (void) close(0); - if (open(core, 2) < 0) { - fprintf(stderr, "trsp: "); perror(core); - exit(2); - } - while(cp < cplim) *cp++ = 0; - (void) lseek(0, nl[0].n_value, 0); - if (write(0, spp_debug, sizeof (spp_debug)) != sizeof (spp_debug)) { - fprintf(stderr, "trsp: "); perror("spp_debug"); - exit(3); - } - (void) lseek(0, nl[1].n_value, 0); - spp_debx = 0; - if (write(0, &spp_debx, sizeof (spp_debx)) != sizeof (spp_debx)) { - fprintf(stderr, "trsp: "); perror("spp_debx"); - exit(3); - } - exit(0); - } - /* - * If no control blocks have been specified, figure - * out how many distinct one we have and summarize - * them in spp_pcbs for sorting the trace records - * below. - */ - if (npcbs == 0) { - for (i = 0; i < SPP_NDEBUG; i++) { - register int j; - register struct spp_debug *sd = &spp_debug[i]; - - if (sd->sd_cb == 0) - continue; - for (j = 0; j < npcbs; j++) - if (spp_pcbs[j] == sd->sd_cb) - break; - if (j >= npcbs) - spp_pcbs[npcbs++] = sd->sd_cb; - } - } - qsort(spp_pcbs, npcbs, sizeof (caddr_t), numeric); - if (jflag) { - char *cp = ""; - - for (i = 0; i < npcbs; i++) { - printf("%s%x", cp, spp_pcbs[i]); - cp = ", "; - } - if (*cp) - putchar('\n'); - exit(0); - } - for (i = 0; i < npcbs; i++) { - printf("\n%x:\n", spp_pcbs[i]); - dotrace(spp_pcbs[i]); - } - exit(0); -} - -dotrace(sppcb) - register caddr_t sppcb; -{ - register int i; - register struct spp_debug *sd; - - for (i = spp_debx % SPP_NDEBUG; i < SPP_NDEBUG; i++) { - sd = &spp_debug[i]; - if (sppcb && sd->sd_cb != sppcb) - continue; - ntime = ntohl(sd->sd_time); - spp_trace(sd->sd_act, sd->sd_ostate, sd->sd_cb, &sd->sd_sp, - &sd->sd_si, sd->sd_req); - } - for (i = 0; i < spp_debx % SPP_NDEBUG; i++) { - sd = &spp_debug[i]; - if (sppcb && sd->sd_cb != sppcb) - continue; - ntime = ntohl(sd->sd_time); - spp_trace(sd->sd_act, sd->sd_ostate, sd->sd_cb, &sd->sd_sp, - &sd->sd_si, sd->sd_req); - } -} - -ptime(ms) - int ms; -{ - - printf("%03d ", (ms/10) % 1000); -} - -numeric(c1, c2) - caddr_t *c1, *c2; -{ - - return (*c1 - *c2); -} - -spp_trace(act, ostate, asp, sp, si, req) - short act, ostate; - struct sppcb *asp, *sp; - struct spidp *si; - int req; -{ - u_short seq, ack, len, alo; - int flags, timer; - char *cp; - - if(ostate >= TCP_NSTATES) ostate = 0; - if(act > SA_DROP) act = SA_DROP; - printf("\n"); - ptime(ntime); - printf("%s:%s", tcpstates[ostate], sanames[act]); - - if (si != 0) { - seq = si->si_seq; - ack = si->si_ack; - alo = si->si_alo; - len = si->si_len; - switch (act) { - case SA_RESPOND: - case SA_OUTPUT: - seq = ntohs(seq); - ack = ntohs(ack); - alo = ntohs(alo); - len = ntohs(len); - case SA_INPUT: - case SA_DROP: - if (aflag) { - printf("\n\tsna="); - ns_printhost(&si->si_sna); - printf("\tdna="); - ns_printhost(&si->si_dna); - } - printf("\n\t"); -#define p1(name, f) { \ - printf("%s = %x, ", name, f); \ - } - p1("seq", seq); - p1("ack", ack); - p1("alo", alo); - p1("len", len); - flags = si->si_cc; - printf("flags=%x", flags); -#define pf(name, f) { \ - if (flags & f) { \ - printf("%s%s", cp, name); \ - cp = ","; \ - } \ -} - if (flags) { - char *cp = "<"; - pf("SP_SP", SP_SP); - pf("SP_SA", SP_SA); - pf("SP_OB", SP_OB); - pf("SP_EM", SP_EM); - printf(">"); - } - printf(", "); -#define p2(name, f) { \ - printf("%s = %x, ", name, f); \ -} - p2("sid", si->si_sid); - p2("did", si->si_did); - p2("dt", si->si_dt); - printf("\n\tsna="); - ns_printhost(&si->si_sna); - printf("\tdna="); - ns_printhost(&si->si_dna); - } - } - if(act == SA_USER) { - printf("\treq=%s", prurequests[req&0xff]); - if ((req & 0xff) == PRU_SLOWTIMO) - printf("<%s>", tcptimers[req>>8]); - } - printf(" -> %s", tcpstates[sp->s_state]); - - /* print out internal state of sp !?! */ - printf("\n"); - if (sp == 0) - return; -#define p3(name, f) { \ - printf("%s = %x, ", name, f); \ -} - if (sflag) { - printf("\t"); - p3("rack", sp->s_rack); - p3("ralo", sp->s_ralo); - p3("smax", sp->s_smax); - p3("snxt", sp->s_snxt); - p3("flags", sp->s_flags); -#undef pf -#define pf(name, f) { \ - if (flags & f) { \ - printf("%s%s", cp, name); \ - cp = ","; \ - } \ -} - flags = sp->s_flags; - if (flags || sp->s_oobflags) { - char *cp = "<"; - pf("ACKNOW", SF_ACKNOW); - pf("DELACK", SF_DELACK); - pf("HI", SF_HI); - pf("HO", SF_HO); - pf("PI", SF_PI); - pf("WIN", SF_WIN); - pf("RXT", SF_RXT); - pf("RVD", SF_RVD); - flags = sp->s_oobflags; - pf("SOOB", SF_SOOB); - pf("IOOB", SF_IOOB); - printf(">"); - } - } - /* print out timers? */ - if (tflag) { - char *cp = "\t"; - register int i; - - printf("\n\tTIMERS: "); - p3("idle", sp->s_idle); - p3("force", sp->s_force); - p3("rtseq", sp->s_rtseq); - for (i = 0; i < TCPT_NTIMERS; i++) { - if (sp->s_timer[i] == 0) - continue; - printf("%s%s=%d", cp, tcptimers[i], sp->s_timer[i]); - if (i == TCPT_REXMT) - printf(" (s_rxtshft=%d)", sp->s_rxtshift); - cp = ", "; - } - if (*cp != '\t') - putchar('\n'); - } -} - -ns_printhost(p) -register struct ns_addr *p; -{ - - printf("", - p->x_net.s_net[0], - p->x_net.s_net[1], - p->x_host.s_host[0], - p->x_host.s_host[1], - p->x_host.s_host[2], - p->x_port); - -} - diff --git a/uucpd.tproj/Makefile.postamble b/uucpd.tproj/Makefile.postamble deleted file mode 100644 index 7ede358..0000000 --- a/uucpd.tproj/Makefile.postamble +++ /dev/null @@ -1,111 +0,0 @@ -############################################################################### -# NeXT Makefile.postamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project, sub-project, bundle, or -# palette. Each node in the project's tree of sub-projects and bundles -# should have it's own Makefile.preamble and Makefile.postamble. Additional -# rules (e.g., after_install) that are defined by the developer should be -# defined in this file. -# -############################################################################### -# -# Here are the variables exported by the common "app" makefiles that can be -# used in any customizations you make to the template below: -# -# PRODUCT_ROOT - Name of the directory to which resources are copied. -# OFILE_DIR - Directory into which .o object files are generated. -# (Note that this name is calculated based on the target -# architectures specified in Project Builder). -# DERIVED_SRC_DIR - Directory used for all other derived files -# ALL_CFLAGS - All the flags passed to the cc(1) driver for compilations -# -# NAME - name of application, bundle, subproject, palette, etc. -# LANGUAGE - langage in which the project is written (default "English") -# ENGLISH - boolean flag set iff $(LANGUAGE) = "English" -# JAPANESE - boolean flag set iff $(LANGUAGE) = "Japanese" -# LOCAL_RESOURCES - localized resources (e.g. nib's, images) of project -# GLOBAL_RESOURCES - non-localized resources of project -# PROJECTVERSION - version of ProjectBuilder that output Makefile -# APPICON - application icon file -# DOCICONS - dock icon files -# ICONSECTIONS - Specifies icon sections when linking executable -# -# CLASSES - Class implementation files in project. -# HFILES - Header files in project. -# MFILES - Other Objective-C source files in project. -# CFILES - Other C source files in project. -# PSWFILES - .psw files in the project -# PSWMFILES - .pswm files in the project -# SUBPROJECTS - Subprojects of this project -# BUNDLES - Bundle subprojects of this project -# OTHERSRCS - Other miscellaneous sources of this project -# OTHERLINKED - Source files not matching a standard source extention -# -# LIBS - Libraries to link with when making app target -# DEBUG_LIBS - Libraries to link with when making debug target -# PROF_LIBS - Libraries to link with when making profile target -# OTHERLINKEDOFILES - Other relocatable files to (always) link in. -# -# APP_MAKEFILE_DIR - Directory in which to find generic set of Makefiles -# MAKEFILEDIR - Directory in which to find $(MAKEFILE) -# MAKEFILE - Top level mechanism Makefile (e.g., app.make, bundle.make) -# INSTALLDIR - Directory app will be installed into by 'install' target -# -############################################################################### - - -# Change defaults assumed by the standard makefiles here. Edit the -# following default values as appropriate. (Note that if no Makefile.postamble -# exists, these values will have defaults set in common.make). - -# Versioning of frameworks, libraries, bundles, and palettes: -#CURRENTLY_ACTIVE_VERSION = YES # Set to "NO" to produce a compatibility binary -#DEPLOY_WITH_VERSION_NAME = A -#COMPATIBILITY_PROJECT_VERSION = 1 - -# Some compiler flags can be easily overridden here, but onlytake effect at -# the top-level: -#OPTIMIZATION_CFLAG = -O -#DEBUG_SYMBOLS_CFLAG = -g -#WARNING_CFLAGS = -Wall -#DEBUG_BUILD_CFLAGS = -DDEBUG -#PROFILE_BUILD_CFLAGS = -pg -DPROFILE - -# Flags passed to yacc -#YFLAGS = -d - -# Library and Framework projects only: -# 1. If you want something other than the default .dylib name, override it here -#DYLIB_INSTALL_NAME = lib$(NAME).dylib - -# 2. If you want to change the -install_name flag from the absolute path to the development area, change it here. One good choice is the installation directory. Another one might be none at all. -#DYLIB_INSTALL_DIR = $(INSTALLDIR) - -# Ownership and permissions of files installed by 'install' target -#INSTALL_AS_USER = root # User/group ownership -#INSTALL_AS_GROUP = wheel # (probably want to set both of these) -#INSTALL_PERMISSIONS = # If set, 'install' chmod's executable to this - -# Options to strip for various project types. Note: -S strips debugging symbols -# (executables can be stripped down further with -x or, if they load no bundles, with no -# options at all). -#APP_STRIP_OPTS = -S -#TOOL_STRIP_OPTS = -S -#LIBRARY_STRIP_OPTS = -S # for .a archives -#DYNAMIC_STRIP_OPTS = -S # for bundles and shared libraries -STRIPFLAGS = - -######################################################################### -# Put rules to extend the behavior of the standard Makefiles here. "Official" -# user-defined rules are: -# * before_install -# * after_install -# * after_installhdrs -# You should avoid redefining things like "install" or "app", as they are -# owned by the top-level Makefile API and no context has been set up for where -# derived files should go. - diff --git a/uucpd.tproj/Makefile.preamble b/uucpd.tproj/Makefile.preamble deleted file mode 100644 index dcbd1c8..0000000 --- a/uucpd.tproj/Makefile.preamble +++ /dev/null @@ -1,119 +0,0 @@ -############################################################################### -# NeXT Makefile.preamble Template -# Copyright 1993, NeXT Computer, Inc. -# -# This Makefile is used for configuring the standard app makefiles associated -# with ProjectBuilder. -# -# Use this template to set attributes for a project. Each node in a project -# tree of sub-projects, tools, etc. should have its own Makefile.preamble and -# Makefile.postamble. -# -############################################################################### -## Configure the flags passed to $(CC) here. These flags will also be -## inherited by all nested sub-projects and bundles. Put your -I, -D, -U, and -## -L flags in ProjectBuilder's Build Options inspector if at all possible. -## To change the default flags that get passed to ${CC} -## (e.g. change -O to -O2), see Makefile.postamble. - -# Flags passed to compiler (in addition to -g, -O, etc) -OTHER_CFLAGS = -# Flags passed to ld (in addition to -ObjC, etc.) -OTHER_LDFLAGS = -# Flags passed to libtool when building libraries -OTHER_LIBTOOL_FLAGS = -# For ordering named sections on NEXTSTEP (see ld(1)) -SECTORDER_FLAGS = - -# Stuff related to exporting headers from this project that isn't already -# handled by PB. -OTHER_PUBLIC_HEADERS = -OTHER_PROJECT_HEADERS = -OTHER_PRIVATE_HEADERS = - -# Set all three of these if you want a precomp to be built as part of -# installation. The cc -precomp will be run in the specified dir on the -# specified public header files with the specified additional flags. Don't put -# $(DSTROOT) in PUBLIC_HEADER_DIR; this is done for you. -PUBLIC_HEADER_DIR = -PUBLIC_PRECOMPILED_HEADERS = -PUBLIC_PRECOMPILED_HEADERS_CFLAGS = - -PRIVATE_HEADER_DIR = - -# If, in a subproject, you want to append to the parent's PUBLIC_HEADER_DIR# -# (say, to add a subdirectory like "/sys"), you can use: -PUBLIC_HEADER_DIR_SUFFIX = -PRIVATE_HEADER_DIR_SUFFIX = - -# Additional (non-localized) resources for this project, which can be generated -OTHER_RESOURCES = - -# Set this to YES if you don't want a final libtool call for a library/framework. -BUILD_OFILES_LIST_ONLY = - -# Additional relocatables to be linked into this project -OTHER_OFILES = -# Additional libraries to link against -OTHER_LIBS = -# To include a version string, project source must exist in a directory named -# $(NAME).%d[.%d][.%d] and the following line must be uncommented. -OTHER_GENERATED_OFILES = $(VERS_OFILE) - -## Configure how things get built here. Additional dependencies, source files, -## derived files, and build order should be specified here. - -# Other dependencies of this project -OTHER_PRODUCT_DEPENDS = -# Built *before* building subprojects/bundles -OTHER_INITIAL_TARGETS = -# Other source files maintained by .pre/postamble -OTHER_SOURCEFILES = -# Additional files to be removed by `make clean' -OTHER_GARBAGE = - -# Targets to build before installation -OTHER_INSTALL_DEPENDS = - -# A virtual root directory (other than /) to be prepended to the $(INSTALLDIR) -# passed from ProjectBuilder. -DSTROOT = - -# More obscure flags you might want to set for pswrap, yacc, lex, etc. -PSWFLAGS = -YFLAGS = -LFLAGS = - -## Delete this line if you want fast and loose cleans that will not remove -## things like precomps and user-defined OTHER_GARBAGE in subprojects. -CLEAN_ALL_SUBPROJECTS = YES - -## Add more obscure source files here to cause them to be automatically -## processed by the appropriate tool. Note that these files should also be -## added to "Supporting Files" in ProjectBuilder. The desired .o files that -## result from these files should also be added to OTHER_OFILES above so they -## will be linked in. - -# .msg files that should have msgwrap run on them -MSGFILES = -# .defs files that should have mig run on them -DEFSFILES = -# .mig files (no .defs files) that should have mig run on them -MIGFILES = - -## Add additional Help directories here (add them to the project as "Other -## Resources" in Project Builder) so that they will be compressed into .store -## files and copied into the app wrapper. If the help directories themselves -## need to also be in the app wrapper, then a cp command will need to be added -## in an after_install target. -OTHER_HELP_DIRS = - -# After you have saved your project using the 4.0 PB, you will automatically -# start using the makefiles in $(SYSTEM_DEVELOPER_DIR)/Makefiles/project. If you should -# need to revert back to the old 3.3 Makefile behavior, override MAKEFILEDIR to -# be $(SYSTEM_DEVELOPER_DIR)/Makefiles/app. - -# Don't add more rules here unless you want the first one to be the default -# target for make! Put all your targets in Makefile.postamble. - --include ../Makefile.include diff --git a/uucpd.tproj/PB.project b/uucpd.tproj/PB.project deleted file mode 100644 index ba6c171..0000000 --- a/uucpd.tproj/PB.project +++ /dev/null @@ -1,42 +0,0 @@ -{ - FILESTABLE = { - C_FILES = (); - H_FILES = (pathnames.h); - M_FILES = (); - OTHER_LIBS = (); - OTHER_LINKED = (uucpd.c); - OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble); - PRECOMPILED_HEADERS = (); - PROJECT_HEADERS = (); - PUBLIC_HEADERS = (); - SUBPROJECTS = (); - }; - GENERATEMAIN = YES; - LANGUAGE = English; - LOCALIZABLE_FILES = {}; - NEXTSTEP_BUILDDIR = ""; - NEXTSTEP_BUILDTOOL = /bin/make; - NEXTSTEP_COMPILEROPTIONS = ""; - NEXTSTEP_DOCUMENTEXTENSIONS = (); - NEXTSTEP_INSTALLDIR = /usr/libexec; - NEXTSTEP_JAVA_COMPILER = /usr/bin/javac; - NEXTSTEP_LINKEROPTIONS = ""; - NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc; - PDO_UNIX_BUILDDIR = ""; - PDO_UNIX_BUILDTOOL = /bin/make; - PDO_UNIX_COMPILEROPTIONS = ""; - PDO_UNIX_INSTALLDIR = /usr/libexec; - PDO_UNIX_JAVA_COMPILER = "$(NEXTDEV_BIN)/javac"; - PDO_UNIX_LINKEROPTIONS = ""; - PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc"; - PROJECTNAME = uucpd; - PROJECTTYPE = Tool; - PROJECTVERSION = 2.8; - WINDOWS_BUILDDIR = ""; - WINDOWS_BUILDTOOL = /bin/make; - WINDOWS_COMPILEROPTIONS = ""; - WINDOWS_INSTALLDIR = /usr/libexec; - WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe"; - WINDOWS_LINKEROPTIONS = ""; - WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc"; -} diff --git a/uucpd.tproj/pathnames.h b/uucpd.tproj/pathnames.h deleted file mode 100644 index 0383391..0000000 --- a/uucpd.tproj/pathnames.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 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. - * - * @(#)pathnames.h 8.1 (Berkeley) 6/4/93 - */ - -#include - -#define _PATH_UUCICO "/usr/lib/uucp/uucico" diff --git a/uucpd.tproj/uucpd.c b/uucpd.tproj/uucpd.c deleted file mode 100644 index 4a5445c..0000000 --- a/uucpd.tproj/uucpd.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights - * Reserved. This file contains Original Code and/or Modifications of - * Original Code as defined in and that are subject to the Apple Public - * Source License Version 1.0 (the 'License'). You may not use this file - * except in compliance with the License. Please obtain a copy of the - * License at http://www.apple.com/publicsource and read it before using - * this file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License." - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* - * Copyright (c) 1985, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Rick Adams. - * - * 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. - */ - -#ifndef lint -static char copyright[] = -"@(#) Copyright (c) 1985, 1993\n\ - The Regents of the University of California. All rights reserved.\n"; -#endif /* not lint */ - -#ifndef lint -static char sccsid[] = "@(#)uucpd.c 8.1 (Berkeley) 6/4/93"; -#endif /* not lint */ - -/* - * 4.2BSD TCP/IP server for uucico - * uucico's TCP channel causes this server to be run at the remote end. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pathnames.h" - -struct sockaddr_in hisctladdr; -int hisaddrlen = sizeof hisctladdr; -struct sockaddr_in myctladdr; -int mypid; - -char Username[64]; -char *nenv[] = { - Username, - NULL, -}; -extern char **environ; - -main(argc, argv) -int argc; -char **argv; -{ -#ifndef BSDINETD - register int s, tcp_socket; - struct servent *sp; -#endif !BSDINETD - extern int errno; - int dologout(); - - environ = nenv; -#ifdef BSDINETD - close(1); close(2); - dup(0); dup(0); - hisaddrlen = sizeof (hisctladdr); - if (getpeername(0, &hisctladdr, &hisaddrlen) < 0) { - fprintf(stderr, "%s: ", argv[0]); - perror("getpeername"); - _exit(1); - } - if (fork() == 0) - doit(&hisctladdr); - dologout(); - exit(1); -#else !BSDINETD - sp = getservbyname("uucp", "tcp"); - if (sp == NULL){ - perror("uucpd: getservbyname"); - exit(1); - } - if (fork()) - exit(0); - if ((s=open(_PATH_TTY, 2)) >= 0){ - ioctl(s, TIOCNOTTY, (char *)0); - close(s); - } - - bzero((char *)&myctladdr, sizeof (myctladdr)); - myctladdr.sin_family = AF_INET; - myctladdr.sin_port = sp->s_port; -#ifdef BSD4_2 - tcp_socket = socket(AF_INET, SOCK_STREAM, 0); - if (tcp_socket < 0) { - perror("uucpd: socket"); - exit(1); - } - if (bind(tcp_socket, (char *)&myctladdr, sizeof (myctladdr)) < 0) { - perror("uucpd: bind"); - exit(1); - } - listen(tcp_socket, 3); /* at most 3 simultaneuos uucp connections */ - signal(SIGCHLD, dologout); - - for(;;) { - s = accept(tcp_socket, &hisctladdr, &hisaddrlen); - if (s < 0){ - if (errno == EINTR) - continue; - perror("uucpd: accept"); - exit(1); - } - if (fork() == 0) { - close(0); close(1); close(2); - dup(s); dup(s); dup(s); - close(tcp_socket); close(s); - doit(&hisctladdr); - exit(1); - } - close(s); - } -#endif BSD4_2 - -#endif !BSDINETD -} - -doit(sinp) -struct sockaddr_in *sinp; -{ - char user[64], passwd[64]; - char *xpasswd, *crypt(); - struct passwd *pw, *getpwnam(); - - alarm(60); - printf("login: "); fflush(stdout); - if (readline(user, sizeof user) < 0) { - fprintf(stderr, "user read\n"); - return; - } - /* truncate username to 8 characters */ - user[8] = '\0'; - pw = getpwnam(user); - if (pw == NULL) { - fprintf(stderr, "user unknown\n"); - return; - } - if (strcmp(pw->pw_shell, _PATH_UUCICO)) { - fprintf(stderr, "Login incorrect."); - return; - } - if (pw->pw_passwd && *pw->pw_passwd != '\0') { - printf("Password: "); fflush(stdout); - if (readline(passwd, sizeof passwd) < 0) { - fprintf(stderr, "passwd read\n"); - return; - } - xpasswd = crypt(passwd, pw->pw_passwd); - if (strcmp(xpasswd, pw->pw_passwd)) { - fprintf(stderr, "Login incorrect."); - return; - } - } - alarm(0); - sprintf(Username, "USER=%s", user); - dologin(pw, sinp); - setgid(pw->pw_gid); -#ifdef BSD4_2 - initgroups(pw->pw_name, pw->pw_gid); -#endif BSD4_2 - chdir(pw->pw_dir); - setuid(pw->pw_uid); -#ifdef BSD4_2 - execl(UUCICO, "uucico", (char *)0); -#endif BSD4_2 - perror("uucico server: execl"); -} - -readline(p, n) -register char *p; -register int n; -{ - char c; - - while (n-- > 0) { - if (read(0, &c, 1) <= 0) - return(-1); - c &= 0177; - if (c == '\n' || c == '\r') { - *p = '\0'; - return(0); - } - *p++ = c; - } - return(-1); -} - -#include -#ifdef BSD4_2 -#include -#endif BSD4_2 - -#define SCPYN(a, b) strncpy(a, b, sizeof (a)) - -struct utmp utmp; - -dologout() -{ - union wait status; - int pid, wtmp; - -#ifdef BSDINETD - while ((pid=wait((int *)&status)) > 0) { -#else !BSDINETD - while ((pid=wait3((int *)&status,WNOHANG,0)) > 0) { -#endif !BSDINETD - wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND); - if (wtmp >= 0) { - sprintf(utmp.ut_line, "uucp%.4d", pid); - SCPYN(utmp.ut_name, ""); - SCPYN(utmp.ut_host, ""); - (void) time(&utmp.ut_time); - (void) write(wtmp, (char *)&utmp, sizeof (utmp)); - (void) close(wtmp); - } - } -} - -/* - * Record login in wtmp file. - */ -dologin(pw, sin) -struct passwd *pw; -struct sockaddr_in *sin; -{ - char line[32]; - char remotehost[32]; - int wtmp, f; - struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, - sizeof (struct in_addr), AF_INET); - - if (hp) { - strncpy(remotehost, hp->h_name, sizeof (remotehost)); - endhostent(); - } else - strncpy(remotehost, inet_ntoa(sin->sin_addr), - sizeof (remotehost)); - wtmp = open(_PATH_WTMP, O_WRONLY|O_APPEND); - if (wtmp >= 0) { - /* hack, but must be unique and no tty line */ - sprintf(line, "uucp%.4d", getpid()); - SCPYN(utmp.ut_line, line); - SCPYN(utmp.ut_name, pw->pw_name); - SCPYN(utmp.ut_host, remotehost); - time(&utmp.ut_time); - (void) write(wtmp, (char *)&utmp, sizeof (utmp)); - (void) close(wtmp); - } - if ((f = open(_PATH_LASTLOG, O_RDWR)) >= 0) { - struct lastlog ll; - - time(&ll.ll_time); - lseek(f, (long)pw->pw_uid * sizeof(struct lastlog), 0); - strcpy(line, remotehost); - SCPYN(ll.ll_line, line); - SCPYN(ll.ll_host, remotehost); - (void) write(f, (char *) &ll, sizeof ll); - (void) close(f); - } -} diff --git a/ypbind.tproj/Makefile b/ypbind.tproj/Makefile index 548fccf..77b3fee 100644 --- a/ypbind.tproj/Makefile +++ b/ypbind.tproj/Makefile @@ -15,7 +15,7 @@ PROJECT_TYPE = Tool CFILES = ypbind.c OTHERSRCS = Makefile Makefile.dist Makefile.postamble Makefile.preamble\ - yp.x + yp.x ypbind.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/ypbind.tproj/Makefile.postamble b/ypbind.tproj/Makefile.postamble index cc6d6ab..7762d72 100644 --- a/ypbind.tproj/Makefile.postamble +++ b/ypbind.tproj/Makefile.postamble @@ -106,3 +106,6 @@ STRIPFLAGS = # owned by the top-level Makefile API and no context has been set up for where # derived files should go. +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 ypbind.8 "$(DSTROOT)/usr/share/man/man8/ypbind.8" diff --git a/ypbind.tproj/Makefile.preamble b/ypbind.tproj/Makefile.preamble index 5ca4df3..961ca71 100644 --- a/ypbind.tproj/Makefile.preamble +++ b/ypbind.tproj/Makefile.preamble @@ -127,3 +127,4 @@ OTHER_HELP_DIRS = # Don't add more rules here unless you want the first one to be the default # target for make! Put all your targets in Makefile.postamble. +AFTER_INSTALL = after_install diff --git a/ypbind.tproj/PB.project b/ypbind.tproj/PB.project index dba6980..5fa6c73 100644 --- a/ypbind.tproj/PB.project +++ b/ypbind.tproj/PB.project @@ -4,7 +4,7 @@ H_FILES = (); M_FILES = (); OTHER_LINKED = (ypbind.c); - OTHER_SOURCES = (Makefile, Makefile.dist, Makefile.postamble, Makefile.preamble, yp.x); + OTHER_SOURCES = (Makefile, Makefile.dist, Makefile.postamble, Makefile.preamble, yp.x, ypbind.8); SUBPROJECTS = (); }; LANGUAGE = English; diff --git a/ypbind.tproj/ypbind.8 b/ypbind.tproj/ypbind.8 new file mode 100644 index 0000000..9794293 --- /dev/null +++ b/ypbind.tproj/ypbind.8 @@ -0,0 +1,134 @@ +.\" $OpenBSD: ypbind.8,v 1.8 1997/06/18 23:50:12 deraadt Exp $ +.\" $NetBSD: ypbind.8,v 1.2 1996/02/28 01:21:00 thorpej Exp $ +.\" +.\" Copyright (c) 1996 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" 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 NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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. +.\" +.Dd October 25, 1994 +.Dt YPBIND 8 +.Os +.Sh NAME +.Nm ypbind +.Nd create and maintain a binding to a YP server +.Sh SYNOPSIS +.Nm +.Op Fl ypset +.Op Fl ypsetme +.Op Fl insecure +.Sh DESCRIPTION +.Nm +finds the server for a particular YP domain and stores information about it +in a +.Pa binding file. +This binding information includes the IP address of the server associated with +that particular domain and which port the server is using. This information +is stored in the directory +.Pa /var/yp/binding +in a file named with the convention +.Pa DOMAINNAME.version. +(The YP system only supplies information on version 2.) +.Pp +When +.Nm +starts the primary domain (or gets the first request for a new domain), +it checks if a file for the domain in question exists in the directory +.Pa /etc/yp/ +(ie. /etc/yp/DOMAINNAME). +If such a file exists, it will list the hosts which +.Nm +should restrict it's server search to. +Otherwise, +.Nm +assumes it will need to use broadcasts to find a valid server. +Using either of these techniques, +.Nm +will search for a server willing to serve maps for the +client's domain. Once a binding is established, +.Nm +maintains this binding by periodically communicating with the server to which +it is bound. If the binding is somehow lost, e.g by server reboot, +.Nm +marks the domain as unbound and attempts to re-establish the binding. +When the binding is once again successful, +.Nm +marks the domain as bound and resumes its periodic check. +.Pp +The options are as follows: +.Bl -tag -width indentxx +.It Fl ypset +.Xr ypset 8 +may be used to change the server to which a domain is bound. +.It Fl ypsetme +.Xr ypset 8 +may be used only from this machine to change the server +to which a domain is bound. +.It Fl insecure +permit binding to a +.Xr ypserv 8 +on a non-reserved port. This is needed if receiving maps from +SunOS 3.x or Ultrix. +.El +.Pp +The +.Fl ypset +and +.Fl ypsetme +options are dangerous and should be avoided. +For greatest security, the use of a server list in +.Pa /etc/yp/DOMAINNAME +is recommended. +The file should contain a list of valid YP server hostnames, +with one hostname per line. +The comment character is #. +.Pp +If the directory +.Pa /var/yp/binding +exists, YP is started automatically at boot time by +.Pa /etc/rc . +.Sh FILES +.Pa /var/yp/binding/DOMAINNAME.version +- binding file for domainname +.Pa /etc/yp/DOMAINNNAME +- server list for this particular domain +.Sh SEE ALSO +.Xr domainname 1 , +.Xr ypcat 1 , +.Xr ypmatch 1 , +.Xr yppoll 8 , +.Xr ypset 8 , +.Xr ypwhich 1 , +.Xr ypserv 8 , +.Xr yp 8 +.Sh AUTHOR +Theo de Raadt diff --git a/ypcat.tproj/Makefile b/ypcat.tproj/Makefile index e3a8242..5d9dd30 100644 --- a/ypcat.tproj/Makefile +++ b/ypcat.tproj/Makefile @@ -14,7 +14,7 @@ PROJECT_TYPE = Tool CFILES = ypcat.c -OTHERSRCS = Makefile.dist Makefile.preamble ypcat.1 +OTHERSRCS = Makefile.dist Makefile.preamble ypcat.1 Makefile.postamble MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/ypcat.tproj/Makefile.postamble b/ypcat.tproj/Makefile.postamble new file mode 100644 index 0000000..989c8ce --- /dev/null +++ b/ypcat.tproj/Makefile.postamble @@ -0,0 +1,103 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGE: langage in which the project is written (default "English") +# LOCAL_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man1" + install -c -m 644 ypcat.1 "$(DSTROOT)/usr/share/man/man1/ypcat.1" diff --git a/ypcat.tproj/Makefile.preamble b/ypcat.tproj/Makefile.preamble index dc05194..cdcdf89 100644 --- a/ypcat.tproj/Makefile.preamble +++ b/ypcat.tproj/Makefile.preamble @@ -1,2 +1,3 @@ OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include +AFTER_INSTALL = after_install diff --git a/ypcat.tproj/PB.project b/ypcat.tproj/PB.project index fc90efc..dce9a43 100644 --- a/ypcat.tproj/PB.project +++ b/ypcat.tproj/PB.project @@ -4,7 +4,7 @@ H_FILES = (); M_FILES = (); OTHER_LINKED = (ypcat.c); - OTHER_SOURCES = (Makefile.dist, Makefile.preamble, ypcat.1); + OTHER_SOURCES = (Makefile.dist, Makefile.preamble, ypcat.1, Makefile.postamble); SUBPROJECTS = (); }; LANGUAGE = English; diff --git a/ypinit.tproj/Makefile b/ypinit.tproj/Makefile index 4720077..037dd35 100644 --- a/ypinit.tproj/Makefile +++ b/ypinit.tproj/Makefile @@ -1,7 +1,7 @@ # # RC Makefile for ypinit scripts on Rhapsody. # -# $Id: Makefile,v 1.1.1.1 1999/05/02 03:59:01 wsanchez Exp $ +# $Id: Makefile,v 1.2 2002/03/13 02:08:08 bbraun Exp $ # VARYP=$(DSTROOT)/private/var/yp @@ -24,7 +24,7 @@ build_init: installsrc: -mkdir -p $(SRCROOT)$(SRCPATH) - cp Makefile Makefile.yp Makefile.main ypinit.sh $(SRCROOT)$(SRCPATH) + cp Makefile Makefile.yp Makefile.main ypinit.sh ypinit.8 $(SRCROOT)$(SRCPATH) installhdrs: @@ -43,4 +43,6 @@ install_binaries: -mkdir -p $(USRSBIN) install -c -m 755 ypinit.sh $(USRSBIN) -chown root.wheel $(USRSBIN)/ypinit + -mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 ypinit.8 "$(DSTROOT)/usr/share/man/man8/ypinit.sh.8" diff --git a/ypinit.tproj/ypinit.8 b/ypinit.tproj/ypinit.8 new file mode 100644 index 0000000..b369db3 --- /dev/null +++ b/ypinit.tproj/ypinit.8 @@ -0,0 +1,69 @@ +.\" $OpenBSD: ypinit.8,v 1.1 1997/04/20 10:00:25 maja Exp $ +.\" Copyright (c) 1997 Mats O Jansson +.\" 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 Mats O Jansson +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +.\" +.Dd April 19, 1997 +.Dt YPINIT 8 +.Os +.Sh NAME +.Nm ypinit +.Nd create an YP server (master or slave) +.Sh SYNOPSIS +.Nm ypinit +.Fl m Op Ar domainname +.Nm ypinit +.Fl s Ar master_server Op Ar domainname +.Nm ypinit +.Fl u Op Ar domainname +.Sh DESCRIPTION +.Nm Ypinit +is the utiliy to setup an YP server, or changing the ypserver map. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl m +Setup a master YP server. If +.Ar domainname +is not given the default domainname will be used. +.It Fl s +Setup a slave YP server. +.Ar domainname +is not given the default domainname will be used. +.Ar master_server +must be a running YP master server. +.It Fl u +Update the ypserver map on a YP master server. If +.Ar domainname +is not given the default domainname will be used. +.El +.Sh SEE ALSO +.Xr yp 8 , +.Xr ypserv 8 +.Sh AUTHOR +Mats O Jansson diff --git a/ypinit.tproj/ypinit.sh b/ypinit.tproj/ypinit.sh index 8c21e36..854895e 100644 --- a/ypinit.tproj/ypinit.sh +++ b/ypinit.tproj/ypinit.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $Id: ypinit.sh,v 1.1.1.1 1999/05/02 03:59:02 wsanchez Exp $ +# $Id: ypinit.sh,v 1.2 2002/03/26 14:38:48 epeyton Exp $ # # ypinit.sh - setup an master or slave server. # @@ -10,7 +10,7 @@ YPXFR=/usr/sbin/ypxfr YP_DIR=/var/yp MAKEDBM=/usr/sbin/makedbm ERROR_EXISTS="NO" -MAKE=make +MAKE=bsdmake umask 077 #set -xv diff --git a/yppoll.tproj/Makefile b/yppoll.tproj/Makefile index 38f2ae4..1b591b0 100644 --- a/yppoll.tproj/Makefile +++ b/yppoll.tproj/Makefile @@ -14,7 +14,7 @@ PROJECT_TYPE = Tool CFILES = yppoll.c -OTHERSRCS = Makefile.dist Makefile.preamble yppoll.8 +OTHERSRCS = Makefile.dist Makefile.preamble yppoll.8 Makefile.postamble MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/yppoll.tproj/Makefile.postamble b/yppoll.tproj/Makefile.postamble new file mode 100644 index 0000000..4ab14c9 --- /dev/null +++ b/yppoll.tproj/Makefile.postamble @@ -0,0 +1,103 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGE: langage in which the project is written (default "English") +# LOCAL_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 yppoll.8 "$(DSTROOT)/usr/share/man/man8/yppoll.8" diff --git a/yppoll.tproj/Makefile.preamble b/yppoll.tproj/Makefile.preamble index dc05194..cdcdf89 100644 --- a/yppoll.tproj/Makefile.preamble +++ b/yppoll.tproj/Makefile.preamble @@ -1,2 +1,3 @@ OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include +AFTER_INSTALL = after_install diff --git a/yppoll.tproj/PB.project b/yppoll.tproj/PB.project index d763e38..3605f58 100644 --- a/yppoll.tproj/PB.project +++ b/yppoll.tproj/PB.project @@ -4,7 +4,7 @@ H_FILES = (); M_FILES = (); OTHER_LINKED = (yppoll.c); - OTHER_SOURCES = (Makefile.dist, Makefile.preamble, yppoll.8); + OTHER_SOURCES = (Makefile.dist, Makefile.preamble, yppoll.8, Makefile.postamble); SUBPROJECTS = (); }; LANGUAGE = English; diff --git a/yppush.tproj/Makefile.postamble b/yppush.tproj/Makefile.postamble index 509e7f5..9cff531 100644 --- a/yppush.tproj/Makefile.postamble +++ b/yppush.tproj/Makefile.postamble @@ -99,3 +99,6 @@ STRIPFLAGS = # owned by the top-level Makefile API and no context has been set up for where # derived files should go. # +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 yppush.8 "$(DSTROOT)/usr/share/man/man8/yppush.8" diff --git a/yppush.tproj/Makefile.preamble b/yppush.tproj/Makefile.preamble index 83f25c7..3d12277 100644 --- a/yppush.tproj/Makefile.preamble +++ b/yppush.tproj/Makefile.preamble @@ -121,3 +121,4 @@ # This definition will suppress stripping of debug symbols when an executable # is installed. By default it is YES. # STRIP_ON_INSTALL = NO +AFTER_INSTALL = after_install diff --git a/yppush.tproj/ypdb.h b/yppush.tproj/ypdb.h index 9afbad5..45b0a7f 100644 --- a/yppush.tproj/ypdb.h +++ b/yppush.tproj/ypdb.h @@ -67,7 +67,7 @@ #define _YPDB_H_ #ifndef _DB_H_ -#include +#include #endif #define YPDB_SUFFIX ".db" diff --git a/ypserv.tproj/Makefile b/ypserv.tproj/Makefile index 626fbef..3da1f94 100644 --- a/ypserv.tproj/Makefile +++ b/ypserv.tproj/Makefile @@ -18,7 +18,7 @@ CFILES = acl.c ypdb.c yplog.c ypserv.c ypserv_db.c ypserv_proc.c\ ypserv_xdr.c ypserv_xdr_v1.c OTHERSRCS = Makefile.preamble Makefile Makefile.postamble securenet\ - securenet.5 ypserv.acl ypserv.acl.5 + securenet.5 ypserv.acl ypserv.acl.5 ypserv.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/ypserv.tproj/Makefile.postamble b/ypserv.tproj/Makefile.postamble index 509e7f5..e2ee9e9 100644 --- a/ypserv.tproj/Makefile.postamble +++ b/ypserv.tproj/Makefile.postamble @@ -99,3 +99,9 @@ STRIPFLAGS = # owned by the top-level Makefile API and no context has been set up for where # derived files should go. # +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + mkdir -p "$(DSTROOT)/usr/share/man/man5" + install -c -m 644 ypserv.8 "$(DSTROOT)/usr/share/man/man8/ypserv.8" + install -c -m 644 securenet.5 "$(DSTROOT)/usr/share/man/man5/securenet.5" + install -c -m 644 ypserv.acl.5 "$(DSTROOT)/usr/share/man/man5/ypserv.acl.5" diff --git a/ypserv.tproj/Makefile.preamble b/ypserv.tproj/Makefile.preamble index 83f25c7..3d12277 100644 --- a/ypserv.tproj/Makefile.preamble +++ b/ypserv.tproj/Makefile.preamble @@ -121,3 +121,4 @@ # This definition will suppress stripping of debug symbols when an executable # is installed. By default it is YES. # STRIP_ON_INSTALL = NO +AFTER_INSTALL = after_install diff --git a/ypserv.tproj/ypserv.8 b/ypserv.tproj/ypserv.8 new file mode 100644 index 0000000..9cb9a0d --- /dev/null +++ b/ypserv.tproj/ypserv.8 @@ -0,0 +1,134 @@ +.\" $OpenBSD: ypserv.8,v 1.9 1997/09/04 00:43:19 deraadt Exp $ +.\" Copyright (c) 1994 Mats O Jansson +.\" 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 Mats O Jansson +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. +.\" +.Dd June 27, 1994 +.Dt YPSERV 8 +.Os +.Sh NAME +.Nm ypserv +.Nd YP server daemon +.Sh SYNOPSIS +.Nm ypserv +.Op Fl 1 +.Op Fl a Ar aclfile +.Op Fl d +.Op Fl x +.Sh DESCRIPTION +.Nm Ypserv +is a fundamental part of the network information system called YP. +This server provides information from YP maps to the YP clients +on the network. +.Pp +A YP map is stored on the server as a +.Xr db 3 +database. A number of YP maps is grouped together in a domain. +.Ar Ypserv +determines the domains it serves by looking for a directory with +the domain name in +.Ar /var/yp . +.Pp +YP hasn't been known for high security through the years. In recent years +security has improved by restricting access to the server. In SunOS 4.1 +has a new file occured named +.Ar /var/yp/securenet . +It contains networks the server can assume is secure. For information about +file format see +.Xr securenet 5 . +.Pp +Before the author of this server had seen +.Xr securenet 5 +another format was implemented +.Xr ypserv.acl 5 . +This file format makes it possible to allow and deny hosts and networks +access to the server. This file can have any name since it's given by +the argument to +.Fl a +(use full path). +.Pp +The file used can be reread by sending a SIGHUP to ypserv. The process pid +can be found in the file +.Nm /var/run/ypserv.pid +. +.Pp +If a host isn't secure all queries to the server will result in a YP_NODOM +result. +.Pp +If the file +.Nm /var/yp/ypserv.log +exists then messages will be written to the file. +.Pp +If a directory named the same as the system domainname exists in +.Nm /var/yp/ +(ie. the domainname is +.Nm foo +and directory +.Nm /var/yp/foo +exists), then ypserv will be automatically started at boot time. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl 1 +Allow ypserv to answer old YP version 1 requests. +.It Fl a Ar aclfile +Don't use +.Ar /var/yp/securenet . +Use another file with another file format. For futher information see +man page for +.Ar ypserv.acl . +.It Fl d +Use Internet Domain Name System. If a query to map +.Ar hosts.byname +or +.Ar hosts.byaddr +fails, make a DNS query and return the result if successful. +Alternately, if these maps were built on the YP master using +.Nm makedbm +.Fl b +then DNS queries will be done without needing to specify +.Fl d . +.It Fl x +Terminate the server after processing +.Ar aclfile +or +.Ar /var/yp/securenet . +.El +.Sh FILES +.Bl -tag -width /var/yp/ypserv.log -compact +.It Pa /var/yp/ypserv.log +.It Pa /var/yp/securenet +.It Pa /var/run/ypserv.pid +.El +.Sh SEE ALSO +.Xr yp 8 , +.Xr ypserv.acl 5 , +.Xr securenet 5 , +.Xr ypbind 1 +.Sh AUTHOR +Mats O Jansson diff --git a/ypset.tproj/Makefile b/ypset.tproj/Makefile index 7abe695..f419aa0 100644 --- a/ypset.tproj/Makefile +++ b/ypset.tproj/Makefile @@ -14,7 +14,7 @@ PROJECT_TYPE = Tool CFILES = ypset.c -OTHERSRCS = Makefile.dist Makefile.preamble +OTHERSRCS = Makefile.dist Makefile.preamble Makefile.postamble ypset.8 MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles diff --git a/ypset.tproj/Makefile.postamble b/ypset.tproj/Makefile.postamble new file mode 100644 index 0000000..772f79e --- /dev/null +++ b/ypset.tproj/Makefile.postamble @@ -0,0 +1,103 @@ +############################################################################### +# Makefile.postamble +# Copyright 1997, Apple Computer, Inc. +# +# Use this makefile, which is imported after all other makefiles, to +# override attributes for a project's Makefile environment. This allows you +# to take advantage of the environment set up by the other Makefiles. +# You can also define custom rules at the end of this file. +# +############################################################################### +# +# These variables are exported by the standard makefiles and can be +# used in any customizations you make. They are *outputs* of +# the Makefiles and should be used, not set. +# +# PRODUCTS: products to install. All of these products will be placed in +# the directory $(DSTROOT)$(INSTALLDIR) +# GLOBAL_RESOURCE_DIR: The directory to which resources are copied. +# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied. +# OFILE_DIR: Directory into which .o object files are generated. +# DERIVED_SRC_DIR: Directory used for all other derived files +# +# ALL_CFLAGS: flags to pass when compiling .c files +# ALL_MFLAGS: flags to pass when compiling .m files +# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files +# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files +# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files +# ALL_LDFLAGS: flags to pass when linking object files +# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files +# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files +# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files +# ALL_YFLAGS: flags to pass when processing .y (yacc) files +# ALL_LFLAGS: flags to pass when processing .l (lex) files +# +# NAME: name of application, bundle, subproject, palette, etc. +# LANGUAGE: langage in which the project is written (default "English") +# LOCAL_RESOURCES: localized resources (e.g. nib's, images) of project +# GLOBAL_RESOURCES: non-localized resources of project +# +# SRCROOT: base directory in which to place the new source files +# SRCPATH: relative path from SRCROOT to present subdirectory +# +# INSTALLDIR: Directory the product will be installed into by 'install' target +# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget +# to prefix this with DSTROOT when you use it. +# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget +# to prefix this with DSTROOT when you use it. +# +# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows) +# +############################################################################### + +# Some compiler flags can be overridden here for certain build situations. +# +# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost) +# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults +# to -g) +# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG) +# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults +# to -O) +# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults +# to -pg -DPROFILE) +# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to +# the include path (defaults to -I.) +# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags +# passed to ld/libtool (defaults to nothing) + + +# Library and Framework projects only: +# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked +# against the framework will run against the correct version even if +# the current version of the framework changes. You may override this +# to "" as an alternative to using the DYLD_LIBRARY_PATH during your +# development cycle, but be sure to restore it before installing. + + +# Ownership and permissions of files installed by 'install' target + +#INSTALL_AS_USER = root + # User/group ownership +#INSTALL_AS_GROUP = wheel + # (probably want to set both of these) +#INSTALL_PERMISSIONS = + # If set, 'install' chmod's executable to this + + +# Options to strip. Note: -S strips debugging symbols (executables can be stripped +# down further with -x or, if they load no bundles, with no options at all). + +#STRIPFLAGS = -S + + +######################################################################### +# Put rules to extend the behavior of the standard Makefiles here. Include them in +# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble. +# +# You should avoid redefining things like "install" or "app", as they are +# owned by the top-level Makefile API and no context has been set up for where +# derived files should go. +# +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 ypset.8 "$(DSTROOT)/usr/share/man/man8/ypset.8" diff --git a/ypset.tproj/Makefile.preamble b/ypset.tproj/Makefile.preamble index dc05194..cdcdf89 100644 --- a/ypset.tproj/Makefile.preamble +++ b/ypset.tproj/Makefile.preamble @@ -1,2 +1,3 @@ OTHER_GENERATED_OFILES = $(VERS_OFILE) -include ../Makefile.include +AFTER_INSTALL = after_install diff --git a/ypset.tproj/PB.project b/ypset.tproj/PB.project index bbc1e0f..2a2ccfa 100644 --- a/ypset.tproj/PB.project +++ b/ypset.tproj/PB.project @@ -4,7 +4,7 @@ H_FILES = (); M_FILES = (); OTHER_LINKED = (ypset.c); - OTHER_SOURCES = (Makefile.dist, Makefile.preamble); + OTHER_SOURCES = (Makefile.dist, Makefile.preamble, Makefile.postamble, ypset.8); SUBPROJECTS = (); }; LANGUAGE = English; diff --git a/ypset.tproj/ypset.8 b/ypset.tproj/ypset.8 new file mode 100644 index 0000000..09c0c23 --- /dev/null +++ b/ypset.tproj/ypset.8 @@ -0,0 +1,91 @@ +.\" $OpenBSD: ypset.8,v 1.3 1996/04/24 21:39:27 deraadt Exp $ +.\" $NetBSD: ypset.8,v 1.2 1996/02/28 01:25:08 thorpej Exp $ +.\" +.\" Copyright (c) 1996 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Jason R. Thorpe. +.\" +.\" 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 NetBSD +.\" Foundation, Inc. and its contributors. +.\" 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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. +.\" +.Dd October 25, 1994 +.Dt YPSET 8 +.Os +.Sh NAME +.Nm ypset +.Nd tell +.Xr ypbind 8 +which YP server process to use +.Sh SYNOPSIS +.Nm ypset +.Op Fl h Ar host +.Op Fl d Ar domain +.Ar server +.Sh DESCRIPTION +.Nm Ypset +tells the +.Xr ypbind 8 +process on the current machine which YP server process to communicate with. +If +.Ar server +is down or is not running a YP server process, it is not discovered until +a YP client process attempts to access a YP map, at which time +.Xr ypbind 8 +tests the binding and takes appropriate action. +.Pp +.Nm Ypset +is most useful for binding a YP client that is not on the same broadcast +network as the closest YP server, but can also be used for debugging +a local network's YP configuration, testing specific YP client +programs, or binding to a specific server when there are many servers on +the local network supplying YP maps. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl h Ar host +Set the YP binding on +.Ar host +instead of the local machine. +.It Fl d Ar domain +Use the YP domain +.Ar domain +instead of the default domain as returned by +.Xr domainname 1 . +.El +.Sh SEE ALSO +.Xr domainname 1 , +.Xr ypbind 8 , +.Xr ypcat 1 , +.Xr ypmatch 1 , +.Xr yppoll 8 , +.Xr ypwhich 1 , +.Xr yp 8 +.Sh AUTHOR +Theo de Raadt diff --git a/ypxfr.tproj/Makefile.postamble b/ypxfr.tproj/Makefile.postamble index 509e7f5..e19d34d 100644 --- a/ypxfr.tproj/Makefile.postamble +++ b/ypxfr.tproj/Makefile.postamble @@ -99,3 +99,6 @@ STRIPFLAGS = # owned by the top-level Makefile API and no context has been set up for where # derived files should go. # +after_install: + mkdir -p "$(DSTROOT)/usr/share/man/man8" + install -c -m 644 ypxfr.8 "$(DSTROOT)/usr/share/man/man8/ypxfr.8" diff --git a/ypxfr.tproj/Makefile.preamble b/ypxfr.tproj/Makefile.preamble index 83f25c7..3d12277 100644 --- a/ypxfr.tproj/Makefile.preamble +++ b/ypxfr.tproj/Makefile.preamble @@ -121,3 +121,4 @@ # This definition will suppress stripping of debug symbols when an executable # is installed. By default it is YES. # STRIP_ON_INSTALL = NO +AFTER_INSTALL = after_install diff --git a/ypxfr.tproj/ypdb.h b/ypxfr.tproj/ypdb.h index 9afbad5..45b0a7f 100644 --- a/ypxfr.tproj/ypdb.h +++ b/ypxfr.tproj/ypdb.h @@ -67,7 +67,7 @@ #define _YPDB_H_ #ifndef _DB_H_ -#include +#include #endif #define YPDB_SUFFIX ".db" -- 2.45.2