Index: releng/9.3/UPDATING =================================================================== --- releng/9.3/UPDATING (revision 308204) +++ releng/9.3/UPDATING (revision 308205) @@ -1,2003 +1,2010 @@ Updating Information for FreeBSD current users This file is maintained and copyrighted by M. Warner Losh . See end of file for further details. For commonly done items, please see the COMMON ITEMS: section later in the file. These instructions assume that you basically know what you are doing. If not, then please consult the FreeBSD handbook: http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. +20161102 p50 FreeBSD-SA-16:34.bind + FreeBSD-SA-16:35.openssl + + Fix BIND remote Denial of Service vulnerability. [SA-16:34] + + Fix OpenSSL remote DoS vulnerability. [SA-16:35] + 20161025 p49 FreeBSD-SA-16:15.sysarch [revised] Fix incorrect argument validation in sysarch(2). [SA-16:15] 20161010 p48 FreeBSD-SA-16:28.bind FreeBSD-SA-16:29.bspatch FreeBSD-SA-16:30.portsnap Fix BIND remote Denial of Service vulnerability. [SA-16:28] Fix bspatch heap overflow vulnerability. [SA-16:29] Fix multiple portsnap vulnerabilities. [SA-16:30] 20160926 p47 FreeBSD-SA-16:26.openssl [revised] Fix OpenSSL regression introduced in SA-16:26. 20160923 p46 FreeBSD-SA-16:26.openssl Fix multiple OpenSSL vulnerabilitites. 20160725 p45 FreeBSD-SA-16:25.bspatch FreeBSD-EN-16:09.freebsd-update Fix bspatch heap overflow vulnerability. [SA-16:25] Fix freebsd-update(8) support of FreeBSD 11.0 release distribution. [EN-16:09] 20160604 p44 FreeBSD-SA-16:24.ntp Fix multiple vulnerabilities of ntp. 20160531 p43 FreeBSD-SA-16:20.linux FreeBSD-SA-16:21.43bsd FreeBSD-SA-16:22.libarchive FreeBSD-SA-16:23.libarchive Fix kernel stack disclosure in Linux compatibility layer. [SA-16:20] Fix kernel stack disclosure in 4.3BSD compatibility layer. [SA-16:21] Fix directory traversal in cpio(1). [SA-16:22] Fix buffer overflow in libarchive(3). [SA-16:23] 20160517 p42 FreeBSD-SA-16:18.atkbd Fix buffer overflow in keyboard driver. [SA-16:18] 20160504 p41 FreeBSD-SA-16:17.openssl FreeBSD-EN-16:08.zfs Fix multiple OpenSSL vulnerabilitites. [SA-16:17] Fix memory leak in ZFS. [EN-16:08] 20160429 p40 FreeBSD-SA-16:16.ntp Fix multiple vulnerabilities of ntp. 20160316 p39 FreeBSD-SA-16:14.openssh-xauth FreeBSD-SA-16:15.sysarch Fix OpenSSH xauth(1) command injection. [SA-16:14] Fix incorrect argument validation in sysarch(2). [SA-16:15] 20160310 p38 FreeBSD-SA-16:13.bind FreeBSD-SA-16:12.openssl [revised] Fix multiple vulnerabilities of BIND. [SA-16:13] Fix a regression with OpenSSL patch. [SA-16:12] 20160303 p37 FreeBSD-SA-16:12.openssl Fix multiple vulnerabilities of OpenSSL. 20160130 p36 FreeBSD-SA-16:11.openssl Fix OpenSSL SSLv2 ciphersuite downgrade vulnerability. [SA-16:11] 20160127 p35 FreeBSD-SA-16:08.bind FreeBSD-SA-16:09.ntp FreeBSD-SA-16:10.linux Fix BIND remote denial of service vulnerability. [SA-16:08] Fix multiple vulnerabilities of ntp. [SA-16:09] Fix Linux compatibility layer issetugid(2) system call vulnerability. [SA-16:10] 20160114 p34 FreeBSD-SA-16:07.openssh Fix OpenSSH client information leak. [SA-16:07] 20160114 p33 FreeBSD-EN-16:02.pf FreeBSD-EN-16:03.yplib FreeBSD-SA-16:01.sctp FreeBSD-SA-16:02.ntp FreeBSD-SA-16:03.linux FreeBSD-SA-16:04.linux FreeBSD-SA-16:05.tcp FreeBSD-SA-16:06.bsnmpd Fix pf(4) generating bad TCP checksums. [EN-16:02] Fix infinite loop in YP/NIS client library. [EN-16:03] Fix remote denial of service in SCTP. [SA-16:01] Update NTP to 4.2.8p5. [SA-16:02] Fix kernel memory diclosure in Linux compatibility layer. [SA-16:03] Fix kernel memory overwrite in Linux compatibility layer. [SA-16:04] Fix crash in TCP MD5 signatures. [SA-16:05] Fix insecure default permissions for snmpd.config. [SA-16:06] 20151216 p32 FreeBSD-SA-15:27.bind Fix BIND remote denial of service vulnerability. [SA-15:27] 20151205 p31 FreeBSD-SA-15:26.openssl Fix OpenSSL X509_ATTRIBUTE memory leak. [SA-15:26] 20151104 p30 FreeBSD-SA-15:25.ntp [revised] FreeBSD-EN-15:19.kqueue FreeBSD-EN-15:20.vm Fix regression of ntpq(8) utility exiting due to trap 6 in 9.3-RELEASE-p29. [SA-15:25] Fix regression in ntpd(8) lacking support for RAWDCF reference clock in 9.3-RELEASE-p29. [SA-15:25] Fix kqueue write events never fired for files greater 2GB. [EN-15:19] Fix applications exiting due to segmentation violation on a correct memory address. [EN-15:20] 20151026: p29 FreeBSD-SA-15:25.ntp Fix multiple NTP vulnerabilities. New NTP version is 4.2.8p4. The configuration file syntax has been changed, thus mergemaster run is recommended. Now the "kod" parameter requires "limited" parameter. If the ntp.conf is not updated, the ntpd will run successfully, but with KoD disabled. 20151002: p28 FreeBSD-SA-15:24.rpcbind [revised] Revised patch to address a regression that prevents NIS from working. 20150929: p27 FreeBSD-SA-15:24.rpcbind Fix rpcbind(8) remote denial of service. [SA-15:24] 20150916: p26 FreeBSD-EN-15:18.pkg Implement pubkey support for pkg(7) bootstrap. [EN-15:18] 20150902: p25 FreeBSD-SA-15:23.bind Fix BIND remote denial of service vulnerability. [SA-15:23] 20150825: p24 FreeBSD-SA-15:21.amd64 FreeBSD-SA-15:22.openssh FreeBSD-EN-15:15.pkg Fix local privilege escalation in IRET handler. [SA-15:21] Fix OpenSSH multiple vulnerabilities. [SA-15:22] Fix insufficient check of unsupported pkg(7) signature methods. [EN-15:15] 20150818: p23 FreeBSD-SA-15:20.expat Fix multiple integer overflows in expat (libbsdxml) XML parser. [SA-15:20] 20150805: p22 FreeBSD-SA-15:19.routed Fix routed remote denial of service vulnerability. 20150728: p21 FreeBSD-SA-15:15.tcp FreeBSD-SA-15:16.openssh FreeBSD-SA-15:17.bind Fix resource exhaustion in TCP reassembly. [SA-15:15] Fix OpenSSH multiple vulnerabilities. [SA-15:16] Fix BIND remote denial of service vulnerability. [SA-15:17] 20150721: p20 FreeBSD-SA-15:13.tcp Fix resource exhaustion due to sessions stuck in LAST_ACK state. [SA-15:13] 20150707: p19 FreeBSD-SA-15:11.bind Fix BIND resolver remote denial of service when validating. 20150630: p18 FreeBSD-EN-15:08.sendmail [revised] FreeBSD-EN-15:09.xlocale Improvements to sendmail TLS/DH interoperability. [EN-15:08] Fix inconsistency between locale and rune locale states. [EN-15:09] 20150618: p17 FreeBSD-EN-15:08.sendmail Improvements to sendmail TLS/DH interoperability. [EN-15:08] 20150612: p16 FreeBSD-SA-15:10.openssl Fix multiple vulnerabilities in OpenSSL. [SA-15:10] 20150609: p15 FreeBSD-EN-15:06.file Updated base system file(1) to 5.22 to address multiple denial of service issues. 20150513: p14 FreeBSD-EN-15:04.freebsd-update Fix bug with freebsd-update(8) that does not ensure the previous upgrade was completed. [EN-15:04] 20150407: p13 FreeBSD-SA-15:04.igmp [revised] FreeBSD-SA-15:07.ntp FreeBSD-SA-15:09.ipv6 Improved patch for SA-15:04.igmp. Fix multiple vulnerabilities of ntp. [SA-15:07] Fix Denial of Service with IPv6 Router Advertisements. [SA-15:09] 20150320: p12 Fix patch for SA-15:06.openssl. 20150319: p11 FreeBSD-SA-15:06.openssl Fix multiple vulnerabilities in OpenSSL. [SA-15:06] 20150225: p10 FreeBSD-SA-15:04.igmp FreeBSD-SA-15:05.bind FreeBSD-EN-15:01.vt FreeBSD-EN-15:02.openssl FreeBSD-EN-15:03.freebsd-update Fix integer overflow in IGMP protocol. [SA-15:04] Fix BIND remote denial of service vulnerability. [SA-15:05] Fix vt(4) crash with improper ioctl parameters. [EN-15:01] Updated base system OpenSSL to 0.9.8zd. [EN-15:02] Fix freebsd-update libraries update ordering issue. [EN-15:03] 20150127: p9 FreeBSD-SA-15:02.kmem FreeBSD-SA-15:03.sctp Fix SCTP SCTP_SS_VALUE kernel memory corruption and disclosure vulnerability. [SA-15:02] Fix SCTP stream reset vulnerability. [SA-15:03] 20150114: p8 FreeBSD-SA-15:01.openssl Fix multiple vulnerabilities in OpenSSL. [SA-15:01] 20141223: p7 FreeBSD-SA-14:31.ntp FreeBSD-EN-14:13.freebsd-update Fix multiple vulnerabilities in NTP suite. [SA-14:31] Fix directory deletion issue in freebsd-update. [EN-14:13] 20141210: p6 FreeBSD-SA-14:28.file FreeBSD-SA-14:29.bind Fix multiple vulnerabilities in file(1) and libmagic(3). [SA-14:28] Fix BIND remote denial of service vulnerability. [SA-14:29] 20141104: p5 FreeBSD-SA-14:25.setlogin FreeBSD-SA-14:26.ftp FreeBSD-EN-14:12.zfs Fix kernel stack disclosure in setlogin(2) / getlogin(2). [SA-14:25] Fix remote command execution in ftp(1). [SA-14:26] Fix NFSv4 and ZFS cache consistency issue. [EN-14:12] 20141022: p4 FreeBSD-EN-14:10.tzdata FreeBSD-EN-14:11.crypt Time zone data file update. [EN-14:10] Change crypt(3) default hashing algorithm back to DES. [EN-14:11] 20141021: p3 FreeBSD-SA-14:20.rtsold FreeBSD-SA-14:21.routed FreeBSD-SA-14:22.namei FreeBSD-SA-14:23.openssl Fix rtsold(8) remote buffer overflow vulnerability. [SA-14:20] Fix routed(8) remote denial of service vulnerability. [SA-14:21] Fix memory leak in sandboxed namei lookup. [SA-14:22] Fix OpenSSL multiple vulnerabilities. [SA-14:23] 20140916: p2 FreeBSD-SA-14:19.tcp Fix Denial of Service in TCP packet processing. [SA-14:19] 20140909: p1 FreeBSD-SA-14:18.openssl Fix OpenSSL multiple vulnerabilities. [SA-14:18] 20140716: 9.3-RELEASE. 20140608: On i386 and amd64 systems, the onifconsole flag is now set by default in /etc/ttys for ttyu0. This causes ttyu0 to be automatically enabled as a login TTY if it is set in the bootloader as an active kernel console. No changes in behavior should result otherwise. To revert to the previous behavior, set ttyu0 to "off" in /etc/ttys. 20140512: Clang and llvm have been upgraded to 3.4.1 release. 20140321: Clang and llvm have been upgraded to 3.4 release. 20140216: The nve(4) driver for NVIDIA nForce MCP Ethernet adapters has been deprecated and will not be part of FreeBSD 11.0 and later releases. If you use this driver, please consider switching to the nfe(4) driver instead. 20131216: The behavior of gss_pseudo_random() for the krb5 mechanism has changed, for applications requesting a longer random string than produced by the underlying enctype's pseudo-random() function. In particular, the random string produced from a session key of enctype aes256-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 will be different at the 17th octet and later, after this change. The counter used in the PRF+ construction is now encoded as a big-endian integer in accordance with RFC 4402. __FreeBSD_version is bumped to 902505. 20130930: 9.2-RELEASE. 20130823: Behavior of devfs rules path matching has been changed. Pattern is now always matched against fully qualified devfs path and slash characters must be explicitly matched by slashes in pattern (FNM_PATHNAME). Rulesets involving devfs subdirectories must be reviewed. 20130705: hastctl(8)'s `status' command output changed to terse one-liner format. Scripts using this should switch to `list' command or be rewritten. 20130618: Fix a bug that allowed a tracing process (e.g. gdb) to write to a memory-mapped file in the traced process's address space even if neither the traced process nor the tracing process had write access to that file. 20130605: Added ZFS TRIM support which is enabled by default. To disable ZFS TRIM support set vfs.zfs.trim.enabled=0 in loader.conf. Creating new ZFS pools and adding new devices to existing pools first performs a full device level TRIM which can take a significant amount of time. The sysctl vfs.zfs.vdev.trim_on_init can be set to 0 to disable this behaviour. ZFS TRIM requires the underlying device support BIO_DELETE which is currently provided by methods such as ATA TRIM and SCSI UNMAP via CAM, which are typically supported by SSD's. Stats for ZFS TRIM can be monitored by looking at the sysctl's under kstat.zfs.misc.zio_trim. 20130524: `list' command has been added to hastctl(8). For now, it is full equivalent of `status' command. WARNING: in the near future the output of hastctl's status command will change to more terse format. If you use `hastctl status' for parsing in your scripts, switch to `hastctl list'. 20130430: The mergemaster command now uses the default MAKEOBJDIRPREFIX rather than creating it's own in the temporary directory in order allow access to bootstrapped versions of tools such as install and mtree. When upgrading from version of FreeBSD where the install command does not support -l, you will need to install a new mergemaster command if mergemaster -p is required. This can be accomplished with the command (cd src/usr.sbin/mergemaster && make install). Due to the use of the new -l option to install(1) during build and install, you must take care not to directly set the INSTALL make variable in your /etc/make.conf, /etc/src.conf, or on the command line. If you wish to use the -C flag for all installs you may be able to add INSTALL+=-C to /etc/make.conf or /etc/src.conf. 20130429: Fix a bug that allows NFS clients to issue READDIR on files. 20130315: The install(1) option -M has changed meaning and now takes an argument that is a file or path to append logs to. In the unlikely event that -M was the last option on the command line and the command line contained at least two files and a target directory the first file will have logs appended to it. The -M option served little practical purpose in the last decade so it's used expected to be extremely rare. 20130225: A new compression method (lz4) has been merged to. Please refer to zpool-features(7) for more information. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20121224: The VFS KBI was changed with the merge of several nullfs optimizations and fixes. All filesystem modules must be recompiled. 20121218: With the addition of auditdistd(8), a new auditdistd user is now depended on during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20121205: 9.1-RELEASE. 20121129: A new version of ZFS (pool version 5000) has been merged to 9-STABLE. Starting with this version the old system of ZFS pool versioning is superseded by "feature flags". This concept enables forward compatibility against certain future changes in functionality of ZFS pools. The first two read-only compatible "feature flags" for ZFS pools are "com.delphix:async_destroy" and "com.delphix:empty_bpobj". For more information read the new zpool-features(7) manual page. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20121114: The commit introducing bsd.compiler.mk breaks the traditional building of kernels before this point. Add -m ${SRC}/share/mk (for the right value of SRC) to your command lines to work around; update your useland to a point after this; or use the buildkernel/installkernel top-level targets. See also 20120829. 20121102: The IPFIREWALL_FORWARD kernel option has been removed. Its functionality now turned on by default. 20120913: The random(4) support for the VIA hardware random number generator (`PADLOCK') is no longer enabled unconditionally. Add the PADLOCK_RNG option in the custom kernel config if needed. The GENERIC kernels on i386 and amd64 do include the option, so the change only affects the custom kernel configurations. 20120829: The amd64 kernel now uses xsetbv, xrstor instructions. To compile with the traditional method, you must update your system with an installworld before the kernel will build. The documented make buildkernel/installkernel interfaces (coupled with fresh make kernel-toolchain) continue to work. 20120727: The sparc64 ZFS loader has been changed to no longer try to auto- detect ZFS providers based on diskN aliases but now requires these to be explicitly listed in the OFW boot-device environment variable. 20120422: Now unix domain sockets behave "as expected" on nullfs(5). Previously nullfs(5) did not pass through all behaviours to the underlying layer, as a result if we bound to a socket on the lower layer we could connect only to the lower path; if we bound to the upper layer we could connect only to the upper path. The new behavior is one can connect to both the lower and the upper paths regardless what layer path one binds to. 20120109: The acpi_wmi(4) status device /dev/wmistat has been renamed to /dev/wmistat0. 20120106: A new VOP_ADVISE() was added to support posix_fadvise(2). All filesystem modules must be recompiled. 20120106: The interface of the VOP_VPTOCNP(9) changed, now the returned vnode shall be referenced, previously it was required to be only held. All in-tree filesystems are converted. 20120106: 9.0-RELEASE. 20111101: The broken amd(4) driver has been replaced with esp(4) in the amd64, i386 and pc98 GENERIC kernel configuration files. 20110913: This commit modifies vfs_register() so that it uses a hash calculation to set vfc_typenum, which is enabled by default. The first time a system is booted after this change, the vfc_typenum values will change for all file systems. The main effect of this is a change to the NFS server file handles for file systems that use vfc_typenum in their fsid, such as ZFS. It will, however, prevent vfc_typenum from changing when file systems are loaded in a different order for subsequent reboots. To disable this, you can set vfs.typenumhash=0 in /boot/loader.conf until you are ready to remount all NFS clients after a reboot. 20110828: Bump the shared library version numbers for libraries that do not use symbol versioning, have changed the ABI compared to stable/8 and which shared library version was not bumped. Done as part of 9.0-RELEASE cycle. 20110815: During the merge of Capsicum features, the fget(9) KPI was modified. This may require the rebuilding of out-of-tree device drivers -- issues have been reported specifically with the nVidia device driver. __FreeBSD_version is bumped to 900041. Also, there is a period between 20110811 and 20110814 where the special devices /dev/{stdin,stdout,stderr} did not work correctly. Building world from a kernel during that window may not work. 20110628: The packet filter (pf) code has been updated to OpenBSD 4.5. You need to update userland tools to be in sync with kernel. This update breaks backward compatibility with earlier pfsync(4) versions. Care must be taken when updating redundant firewall setups. 20110608: The following sysctls and tunables are retired on x86 platforms: machdep.hlt_cpus machdep.hlt_logical_cpus The following sysctl is retired: machdep.hyperthreading_allowed The sysctls were supposed to provide a way to dynamically offline and online selected CPUs on x86 platforms, but the implementation has not been reliable especially with SCHED_ULE scheduler. machdep.hyperthreading_allowed tunable is still available to ignore hyperthreading CPUs at OS level. Individual CPUs can be disabled using hint.lapic.X.disabled tunable, where X is an APIC ID of a CPU. Be advised, though, that disabling CPUs in non-uniform fashion will result in non-uniform topology and may lead to sub-optimal system performance with SCHED_ULE, which is a default scheduler. 20110607: cpumask_t type is retired and cpuset_t is used in order to describe a mask of CPUs. 20110531: Changes to ifconfig(8) for dynamic address family detection mandate that you are running a kernel of 20110525 or later. Make sure to follow the update procedure to boot a new kernel before installing world. 20110513: Support for sun4v architecture is officially dropped 20110503: Several KPI breaking changes have been committed to the mii(4) layer, the PHY drivers and consequently some Ethernet drivers using mii(4). This means that miibus.ko and the modules of the affected Ethernet drivers need to be recompiled. Note to kernel developers: Given that the OUI bit reversion problem was fixed as part of these changes all mii(4) commits related to OUIs, i.e. to sys/dev/mii/miidevs, PHY driver probing and vendor specific handling, no longer can be merged verbatim to stable/8 and previous branches. 20110430: Users of the Atheros AR71xx SoC code now need to add 'device ar71xx_pci' into their kernel configurations along with 'device pci'. 20110427: The default NFS client is now the new NFS client, so fstype "newnfs" is now "nfs" and the regular/old NFS client is now fstype "oldnfs". Although mounts via fstype "nfs" will usually work without userland changes, it is recommended that the mount(8) and mount_nfs(8) commands be rebuilt from sources and that a link to mount_nfs called mount_oldnfs be created. The new client is compiled into the kernel with "options NFSCL" and this is needed for diskless root file systems. The GENERIC kernel configs have been changed to use NFSCL and NFSD (the new server) instead of NFSCLIENT and NFSSERVER. To use the regular/old client, you can "mount -t oldnfs ...". For a diskless root file system, you must also include a line like: vfs.root.mountfrom="oldnfs:" in the boot/loader.conf on the root fs on the NFS server to make a diskless root fs use the old client. 20110424: The GENERIC kernels for all architectures now default to the new CAM-based ATA stack. It means that all legacy ATA drivers were removed and replaced by respective CAM drivers. If you are using ATA device names in /etc/fstab or other places, make sure to update them respectively (adX -> adaY, acdX -> cdY, afdX -> daY, astX -> saY, where 'Y's are the sequential numbers starting from zero for each type in order of detection, unless configured otherwise with tunables, see cam(4)). There will be symbolic links created in /dev/ to map old adX devices to the respective adaY. They should provide basic compatibility for file systems mounting in most cases, but they do not support old user-level APIs and do not have respective providers in GEOM. Consider using updated management tools with new device names. It is possible to load devices ahci, ata, siis and mvs as modules, but option ATA_CAM should remain in kernel configuration to make ata module work as CAM driver supporting legacy ATA controllers. Device ata still can be used in modular fashion (atacore + ...). Modules atadisk and atapi* are not used and won't affect operation in ATA_CAM mode. Note that to use CAM-based ATA kernel should include CAM devices scbus, pass, da (or explicitly ada), cd and optionally others. All of them are parts of the cam module. ataraid(4) functionality is now supported by the RAID GEOM class. To use it you can load geom_raid kernel module and use graid(8) tool for management. Instead of /dev/arX device names, use /dev/raid/rX. No kernel config options or code have been removed, so if a problem arises, please report it and optionally revert to the old ATA stack. In order to do it you can remove from the kernel config: options ATA_CAM device ahci device mvs device siis , and instead add back: device atadisk # ATA disk drives device ataraid # ATA RAID drives device atapicd # ATAPI CDROM drives device atapifd # ATAPI floppy drives device atapist # ATAPI tape drives 20110423: The default NFS server has been changed to the new server, which was referred to as the experimental server. If you need to switch back to the old NFS server, you must now put the "-o" option on both the mountd and nfsd commands. This can be done using the mountd_flags and nfs_server_flags rc.conf variables until an update to the rc scripts is committed, which is coming soon. 20110418: The GNU Objective-C runtime library (libobjc), and other Objective-C related components have been removed from the base system. If you require an Objective-C library, please use one of the available ports. 20110331: ath(4) has been split into bus- and device- modules. if_ath contains the HAL, the TX rate control and the network device code. if_ath_pci contains the PCI bus glue. For Atheros MIPS embedded systems, if_ath_ahb contains the AHB glue. Users need to load both if_ath_pci and if_ath in order to use ath on everything else. TO REPEAT: if_ath_ahb is not needed for normal users. Normal users only need to load if_ath and if_ath_pci for ath(4) operation. 20110314: As part of the replacement of sysinstall, the process of building release media has changed significantly. For details, please re-read release(7), which has been updated to reflect the new build process. 20110218: GNU binutils 2.17.50 (as of 2007-07-03) has been merged to -HEAD. This is the last available version under GPLv2. It brings a number of new features, such as support for newer x86 CPU's (with SSE-3, SSSE-3, SSE 4.1 and SSE 4.2), better support for powerpc64, a number of new directives, and lots of other small improvements. See the ChangeLog file in contrib/binutils for the full details. 20110218: IPsec's HMAC_SHA256-512 support has been fixed to be RFC4868 compliant, and will now use half of hash for authentication. This will break interoperability with all stacks (including all actual FreeBSD versions) who implement draft-ietf-ipsec-ciph-sha-256-00 (they use 96 bits of hash for authentication). The only workaround with such peers is to use another HMAC algorithm for IPsec ("phase 2") authentication. 20110207: Remove the uio_yield prototype and symbol. This function has been misnamed since it was introduced and should not be globally exposed with this name. The equivalent functionality is now available using kern_yield(curthread->td_user_pri). The function remains undocumented. 20110112: A SYSCTL_[ADD_]UQUAD was added for unsigned uint64_t pointers, symmetric with the existing SYSCTL_[ADD_]QUAD. Type checking for scalar sysctls is defined but disabled. Code that needs UQUAD to pass the type checking that must compile on older systems where the define is not present can check against __FreeBSD_version >= 900030. The system dialog(1) has been replaced with a new version previously in ports as devel/cdialog. dialog(1) is mostly command-line compatible with the previous version, but the libdialog associated with it has a largely incompatible API. As such, the original version of libdialog will be kept temporarily as libodialog, until its base system consumers are replaced or updated. Bump __FreeBSD_version to 900030. 20110103: If you are trying to run make universe on a -stable system, and you get the following warning: "Makefile", line 356: "Target architecture for i386/conf/GENERIC unknown. config(8) likely too old." or something similar to it, then you must upgrade your -stable system to 8.2-Release or newer (really, any time after r210146 7/15/2010 in stable/8) or build the config from the latest stable/8 branch and install it on your system. Prior to this date, building a current universe on 8-stable system from between 7/15/2010 and 1/2/2011 would result in a weird shell parsing error in the first kernel build phase. A new config on those old systems will fix that problem for older versions of -current. 20101228: The TCP stack has been modified to allow Khelp modules to interact with it via helper hook points and store per-connection data in the TCP control block. Bump __FreeBSD_version to 900029. User space tools that rely on the size of struct tcpcb in tcp_var.h (e.g. sockstat) need to be recompiled. 20101114: Generic IEEE 802.3 annex 31B full duplex flow control support has been added to mii(4) and bge(4), bce(4), msk(4), nfe(4) and stge(4) along with brgphy(4), e1000phy(4) as well as ip1000phy() have been converted to take advantage of it instead of using custom implementations. This means that these drivers now no longer unconditionally advertise support for flow control but only do so if flow control is a selected media option. This was implemented in the generic support that way in order to allow flow control to be switched on and off via ifconfig(8) with the PHY specific default to typically off in order to protect from unwanted effects. Consequently, if you used flow control with one of the above mentioned drivers you now need to explicitly enable it, for example via: ifconfig bge0 media auto mediaopt flowcontrol Along with the above mentioned changes generic support for setting 1000baseT master mode also has been added and brgphy(4), ciphy(4), e1000phy(4) as well as ip1000phy(4) have been converted to take advantage of it. This means that these drivers now no longer take the link0 parameter for selecting master mode but the master media option has to be used instead, for example like in the following: ifconfig bge0 media 1000baseT mediaopt full-duplex,master Selection of master mode now is also available with all other PHY drivers supporting 1000baseT. 20101111: The TCP stack has received a significant update to add support for modularised congestion control and generally improve the clarity of congestion control decisions. Bump __FreeBSD_version to 900025. User space tools that rely on the size of struct tcpcb in tcp_var.h (e.g. sockstat) need to be recompiled. 20101002: The man(1) utility has been replaced by a new version that no longer uses /etc/manpath.config. Please consult man.conf(5) for how to migrate local entries to the new format. 20100928: The copyright strings printed by login(1) and sshd(8) at the time of a new connection have been removed to follow other operating systems and upstream sshd. 20100915: A workaround for a fixed ld bug has been removed in kernel code, so make sure that your system ld is built from sources after revision 210245 from 2010-07-19 (r211583 if building head kernel on stable/8, r211584 for stable/7; both from 2010-08-21). A symptom of incorrect ld version is different addresses for set_pcpu section and __start_set_pcpu symbol in kernel and/or modules. 20100913: The $ipv6_prefer variable in rc.conf(5) has been split into $ip6addrctl_policy and $ipv6_activate_all_interfaces. The $ip6addrctl_policy is a variable to choose a pre-defined address selection policy set by ip6addrctl(8). A value "ipv4_prefer", "ipv6_prefer" or "AUTO" can be specified. The default is "AUTO". The $ipv6_activate_all_interfaces specifies whether IFDISABLED flag (see an entry of 20090926) is set on an interface with no corresponding $ifconfig_IF_ipv6 line. The default is "NO" for security reason. If you want IPv6 link-local address on all interfaces by default, set this to "YES". The old ipv6_prefer="YES" is equivalent to ipv6_activate_all_interfaces="YES" and ip6addrctl_policy="ipv6_prefer". 20100913: DTrace has grown support for userland tracing. Due to this, DTrace is now i386 and amd64 only. dtruss(1) is now installed by default on those systems and a new kernel module is needed for userland tracing: fasttrap. No changes to your kernel config file are necessary to enable userland tracing, but you might consider adding 'STRIP=' and 'CFLAGS+=-fno-omit-frame-pointer' to your make.conf if you want to have informative userland stack traces in DTrace (ustack). 20100725: The acpi_aiboost(4) driver has been removed in favor of the new aibs(4) driver. You should update your kernel configuration file. 20100722: BSD grep has been imported to the base system and it is built by default. It is completely BSD licensed, highly GNU-compatible, uses less memory than its GNU counterpart and has a small codebase. However, it is slower than its GNU counterpart, which is mostly noticeable for larger searches, for smaller ones it is measurable but not significant. The reason is complex, the most important factor is that we lack a modern and efficient regex library and GNU overcomes this by optimizing the searches internally. Future work on improving the regex performance is planned, for the meantime, users that need better performance, can build GNU grep instead by setting the WITH_GNU_GREP knob. 20100713: Due to the import of powerpc64 support, all existing powerpc kernel configuration files must be updated with a machine directive like this: machine powerpc powerpc In addition, an updated config(8) is required to build powerpc kernels after this change. 20100713: A new version of ZFS (version 15) has been merged to -HEAD. This version uses a python library for the following subcommands: zfs allow, zfs unallow, zfs groupspace, zfs userspace. For full functionality of these commands the following port must be installed: sysutils/py-zfs 20100429: 'vm_page's are now hashed by physical address to an array of mutexes. Currently this is only used to serialize access to hold_count. Over time the page queue mutex will be peeled away. This changes the size of pmap on every architecture. And requires all callers of vm_page_hold and vm_page_unhold to be updated. 20100402: WITH_CTF can now be specified in src.conf (not recommended, there are some problems with static executables), make.conf (would also affect ports which do not use GNU make and do not override the compile targets) or in the kernel config (via "makeoptions WITH_CTF=yes"). When WITH_CTF was specified there before this was silently ignored, so make sure that WITH_CTF is not used in places which could lead to unwanted behavior. 20100311: The kernel option COMPAT_IA32 has been replaced with COMPAT_FREEBSD32 to allow 32-bit compatibility on non-x86 platforms. All kernel configurations on amd64 and ia64 platforms using these options must be modified accordingly. 20100113: The utmp user accounting database has been replaced with utmpx, the user accounting interface standardized by POSIX. Unfortunately the semantics of utmp and utmpx don't match, making it practically impossible to support both interfaces. The user accounting database is used by tools like finger(1), last(1), talk(1), w(1) and ac(8). All applications in the base system use utmpx. This means only local binaries (e.g. from the ports tree) may still use these utmp database files. These applications must be rebuilt to make use of utmpx. After the system has been upgraded, it is safe to remove the old log files (/var/run/utmp, /var/log/lastlog and /var/log/wtmp*), assuming their contents is of no importance anymore. Old wtmp databases can only be used by last(1) and ac(8) after they have been converted to the new format using wtmpcvt(1). 20100108: Introduce the kernel thread "deadlock resolver" (which can be enabled via the DEADLKRES option, see NOTES for more details) and the sleepq_type() function for sleepqueues. 20091202: The rc.firewall and rc.firewall6 were unified, and rc.firewall6 and rc.d/ip6fw were removed. According to the removal of rc.d/ip6fw, ipv6_firewall_* rc variables are obsoleted. Instead, the following new rc variables are added to rc.d/ipfw: firewall_client_net_ipv6, firewall_simple_iif_ipv6, firewall_simple_inet_ipv6, firewall_simple_oif_ipv6, firewall_simple_onet_ipv6, firewall_trusted_ipv6 The meanings correspond to the relevant IPv4 variables. 20091125: 8.0-RELEASE. 20091113: The default terminal emulation for syscons(4) has been changed from cons25 to xterm on all platforms except pc98. This means that the /etc/ttys file needs to be updated to ensure correct operation of applications on the console. The terminal emulation style can be toggled per window by using vidcontrol(1)'s -T flag. The TEKEN_CONS25 kernel configuration options can be used to change the compile-time default back to cons25. To prevent graphical artifacts, make sure the TERM environment variable is set to match the terminal emulation that is being performed by syscons(4). 20091109: The layout of the structure ieee80211req_scan_result has changed. Applications that require wireless scan results (e.g. ifconfig(8)) from net80211 need to be recompiled. Applications such as wpa_supplicant(8) may require a full world build without using NO_CLEAN in order to get synchronized with the new structure. 20091025: The iwn(4) driver has been updated to support the 5000 and 5150 series. There's one kernel module for each firmware. Adding "device iwnfw" to the kernel configuration file means including all three firmware images inside the kernel. If you want to include just the one for your wireless card, use the devices iwn4965fw, iwn5000fw or iwn5150fw. 20090926: The rc.d/network_ipv6, IPv6 configuration script has been integrated into rc.d/netif. The changes are the following: 1. To use IPv6, simply define $ifconfig_IF_ipv6 like $ifconfig_IF for IPv4. For aliases, $ifconfig_IF_aliasN should be used. Note that both variables need the "inet6" keyword at the head. Do not set $ipv6_network_interfaces manually if you do not understand what you are doing. It is not needed in most cases. $ipv6_ifconfig_IF and $ipv6_ifconfig_IF_aliasN still work, but they are obsolete. 2. $ipv6_enable is obsolete. Use $ipv6_prefer and "inet6 accept_rtadv" keyword in ifconfig(8) instead. If you define $ipv6_enable=YES, it means $ipv6_prefer=YES and all configured interfaces have "inet6 accept_rtadv" in the $ifconfig_IF_ipv6. These are for backward compatibility. 3. A new variable $ipv6_prefer has been added. If NO, IPv6 functionality of interfaces with no corresponding $ifconfig_IF_ipv6 is disabled by using "inet6 ifdisabled" flag, and the default address selection policy of ip6addrctl(8) is the IPv4-preferred one (see rc.d/ip6addrctl for more details). Note that if you want to configure IPv6 functionality on the disabled interfaces after boot, first you need to clear the flag by using ifconfig(8) like: ifconfig em0 inet6 -ifdisabled If YES, the default address selection policy is set as IPv6-preferred. The default value of $ipv6_prefer is NO. 4. If your system need to receive Router Advertisement messages, define "inet6 accept_rtadv" in $ifconfig_IF_ipv6. The rc(8) scripts automatically invoke rtsol(8) when the interface becomes UP. The Router Advertisement messages are used for SLAAC (State-Less Address AutoConfiguration). 20090922: 802.11s D3.03 support was committed. This is incompatible with the previous code, which was based on D3.0. 20090912: A sysctl variable net.inet6.ip6.accept_rtadv now sets the default value of a per-interface flag ND6_IFF_ACCEPT_RTADV, not a global knob to control whether accepting Router Advertisement messages or not. Also, a per-interface flag ND6_IFF_AUTO_LINKLOCAL has been added and a sysctl variable net.inet6.ip6.auto_linklocal is its default value. The ifconfig(8) utility now supports these flags. 20090910: ZFS snapshots are now mounted with MNT_IGNORE flag. Use -v option for mount(8) and -a option for df(1) to see them. 20090825: The old tunable hw.bus.devctl_disable has been superseded by hw.bus.devctl_queue. hw.bus.devctl_disable=1 in loader.conf should be replaced by hw.bus.devctl_queue=0. The default for this new tunable is 1000. 20090813: Remove the option STOP_NMI. The default action is now to use NMI only for KDB via the newly introduced function stop_cpus_hard() and maintain stop_cpus() to just use a normal IPI_STOP on ia32 and amd64. 20090803: The stable/8 branch created in subversion. This corresponds to the RELENG_8 branch in CVS. 20090719: Bump the shared library version numbers for all libraries that do not use symbol versioning as part of the 8.0-RELEASE cycle. Bump __FreeBSD_version to 800105. 20090714: Due to changes in the implementation of virtual network stack support, all network-related kernel modules must be recompiled. As this change breaks the ABI, bump __FreeBSD_version to 800104. 20090713: The TOE interface to the TCP syncache has been modified to remove struct tcpopt () from the ABI of the network stack. The cxgb driver is the only TOE consumer affected by this change, and needs to be recompiled along with the kernel. As this change breaks the ABI, bump __FreeBSD_version to 800103. 20090712: Padding has been added to struct tcpcb, sackhint and tcpstat in to facilitate future MFCs and bug fixes whilst maintaining the ABI. However, this change breaks the ABI, so bump __FreeBSD_version to 800102. User space tools that rely on the size of any of these structs (e.g. sockstat) need to be recompiled. 20090630: The NFS_LEGACYRPC option has been removed along with the old kernel RPC implementation that this option selected. Kernel configurations may need to be adjusted. 20090629: The network interface device nodes at /dev/net/ have been removed. All ioctl operations can be performed the normal way using routing sockets. The kqueue functionality can generally be replaced with routing sockets. 20090628: The documentation from the FreeBSD Documentation Project (Handbook, FAQ, etc.) is now installed via packages by sysinstall(8) and under the /usr/local/share/doc/freebsd directory instead of /usr/share/doc. 20090624: The ABI of various structures related to the SYSV IPC API have been changed. As a result, the COMPAT_FREEBSD[456] and COMPAT_43 kernel options now all require COMPAT_FREEBSD7. Bump __FreeBSD_version to 800100. 20090622: Layout of struct vnet has changed as routing related variables were moved to their own Vimage module. Modules need to be recompiled. Bump __FreeBSD_version to 800099. 20090619: NGROUPS_MAX and NGROUPS have been increased from 16 to 1023 and 1024 respectively. As long as no more than 16 groups per process are used, no changes should be visible. When more than 16 groups are used, old binaries may fail if they call getgroups() or getgrouplist() with statically sized storage. Recompiling will work around this, but applications should be modified to use dynamically allocated storage for group arrays as POSIX.1-2008 does not cap an implementation's number of supported groups at NGROUPS_MAX+1 as previous versions did. NFS and portalfs mounts may also be affected as the list of groups is truncated to 16. Users of NFS who use more than 16 groups, should take care that negative group permissions are not used on the exported file systems as they will not be reliable unless a GSSAPI based authentication method is used. 20090616: The compiling option ADAPTIVE_LOCKMGRS has been introduced. This option compiles in the support for adaptive spinning for lockmgrs which want to enable it. The lockinit() function now accepts the flag LK_ADAPTIVE in order to make the lock object subject to adaptive spinning when both held in write and read mode. 20090613: The layout of the structure returned by IEEE80211_IOC_STA_INFO has changed. User applications that use this ioctl need to be rebuilt. 20090611: The layout of struct thread has changed. Kernel and modules need to be rebuilt. 20090608: The layout of structs ifnet, domain, protosw and vnet_net has changed. Kernel modules need to be rebuilt. Bump __FreeBSD_version to 800097. 20090602: window(1) has been removed from the base system. It can now be installed from ports. The port is called misc/window. 20090601: The way we are storing and accessing `routing table' entries has changed. Programs reading the FIB, like netstat, need to be re-compiled. 20090601: A new netisr implementation has been added for FreeBSD 8. Network file system modules, such as igmp, ipdivert, and others, should be rebuilt. Bump __FreeBSD_version to 800096. 20090530: Remove the tunable/sysctl debug.mpsafevfs as its initial purpose is no more valid. 20090530: Add VOP_ACCESSX(9). File system modules need to be rebuilt. Bump __FreeBSD_version to 800094. 20090529: Add mnt_xflag field to 'struct mount'. File system modules need to be rebuilt. Bump __FreeBSD_version to 800093. 20090528: The compiling option ADAPTIVE_SX has been retired while it has been introduced the option NO_ADAPTIVE_SX which handles the reversed logic. The KPI for sx_init_flags() changes as accepting flags: SX_ADAPTIVESPIN flag has been retired while the SX_NOADAPTIVE flag has been introduced in order to handle the reversed logic. Bump __FreeBSD_version to 800092. 20090527: Add support for hierarchical jails. Remove global securelevel. Bump __FreeBSD_version to 800091. 20090523: The layout of struct vnet_net has changed, therefore modules need to be rebuilt. Bump __FreeBSD_version to 800090. 20090523: The newly imported zic(8) produces a new format in the output. Please run tzsetup(8) to install the newly created data to /etc/localtime. 20090520: The sysctl tree for the usb stack has renamed from hw.usb2.* to hw.usb.* and is now consistent again with previous releases. 20090520: 802.11 monitor mode support was revised and driver api's were changed. Drivers dependent on net80211 now support DLT_IEEE802_11_RADIO instead of DLT_IEEE802_11. No user-visible data structures were changed but applications that use DLT_IEEE802_11 may require changes. Bump __FreeBSD_version to 800088. 20090430: The layout of the following structs has changed: sysctl_oid, socket, ifnet, inpcbinfo, tcpcb, syncache_head, vnet_inet, vnet_inet6 and vnet_ipfw. Most modules need to be rebuild or panics may be experienced. World rebuild is required for correctly checking networking state from userland. Bump __FreeBSD_version to 800085. 20090429: MLDv2 and Source-Specific Multicast (SSM) have been merged to the IPv6 stack. VIMAGE hooks are in but not yet used. The implementation of SSM within FreeBSD's IPv6 stack closely follows the IPv4 implementation. For kernel developers: * The most important changes are that the ip6_output() and ip6_input() paths no longer take the IN6_MULTI_LOCK, and this lock has been downgraded to a non-recursive mutex. * As with the changes to the IPv4 stack to support SSM, filtering of inbound multicast traffic must now be performed by transport protocols within the IPv6 stack. This does not apply to TCP and SCTP, however, it does apply to UDP in IPv6 and raw IPv6. * The KPIs used by IPv6 multicast are similar to those used by the IPv4 stack, with the following differences: * im6o_mc_filter() is analogous to imo_multicast_filter(). * The legacy KAME entry points in6_joingroup and in6_leavegroup() are shimmed to in6_mc_join() and in6_mc_leave() respectively. * IN6_LOOKUP_MULTI() has been deprecated and removed. * IPv6 relies on MLD for the DAD mechanism. KAME's internal KPIs for MLDv1 have an additional 'timer' argument which is used to jitter the initial membership report for the solicited-node multicast membership on-link. * This is not strictly needed for MLDv2, which already jitters its report transmissions. However, the 'timer' argument is preserved in case MLDv1 is active on the interface. * The KAME linked-list based IPv6 membership implementation has been refactored to use a vector similar to that used by the IPv4 stack. Code which maintains a list of its own multicast memberships internally, e.g. carp, has been updated to reflect the new semantics. * There is a known Lock Order Reversal (LOR) due to in6_setscope() acquiring the IF_AFDATA_LOCK and being called within ip6_output(). Whilst MLDv2 tries to avoid this otherwise benign LOR, it is an implementation constraint which needs to be addressed in HEAD. For application developers: * The changes are broadly similar to those made for the IPv4 stack. * The use of IPv4 and IPv6 multicast socket options on the same socket, using mapped addresses, HAS NOT been tested or supported. * There are a number of issues with the implementation of various IPv6 multicast APIs which need to be resolved in the API surface before the implementation is fully compatible with KAME userland use, and these are mostly to do with interface index treatment. * The literature available discusses the use of either the delta / ASM API with setsockopt(2)/getsockopt(2), or the full-state / ASM API using setsourcefilter(3)/getsourcefilter(3). For more information please refer to RFC 3768, 'Socket Interface Extensions for Multicast Source Filters'. * Applications which use the published RFC 3678 APIs should be fine. For systems administrators: * The mtest(8) utility has been refactored to support IPv6, in addition to IPv4. Interface addresses are no longer accepted as arguments, their names must be used instead. The utility will map the interface name to its first IPv4 address as returned by getifaddrs(3). * The ifmcstat(8) utility has also been updated to print the MLDv2 endpoint state and source filter lists via sysctl(3). * The net.inet6.ip6.mcast.loop sysctl may be tuned to 0 to disable loopback of IPv6 multicast datagrams by default; it defaults to 1 to preserve the existing behaviour. Disabling multicast loopback is recommended for optimal system performance. * The IPv6 MROUTING code has been changed to examine this sysctl instead of attempting to perform a group lookup before looping back forwarded datagrams. Bump __FreeBSD_version to 800084. 20090422: Implement low-level Bluetooth HCI API. Bump __FreeBSD_version to 800083. 20090419: The layout of struct malloc_type, used by modules to register new memory allocation types, has changed. Most modules will need to be rebuilt or panics may be experienced. Bump __FreeBSD_version to 800081. 20090415: Anticipate overflowing inp_flags - add inp_flags2. This changes most offsets in inpcb, so checking v4 connection state will require a world rebuild. Bump __FreeBSD_version to 800080. 20090415: Add an llentry to struct route and struct route_in6. Modules embedding a struct route will need to be recompiled. Bump __FreeBSD_version to 800079. 20090414: The size of rt_metrics_lite and by extension rtentry has changed. Networking administration apps will need to be recompiled. The route command now supports show as an alias for get, weighting of routes, sticky and nostick flags to alter the behavior of stateful load balancing. Bump __FreeBSD_version to 800078. 20090408: Do not use Giant for kbdmux(4) locking. This is wrong and apparently causing more problems than it solves. This will re-open the issue where interrupt handlers may race with kbdmux(4) in polling mode. Typical symptoms include (but not limited to) duplicated and/or missing characters when low level console functions (such as gets) are used while interrupts are enabled (for example geli password prompt, mountroot prompt etc.). Disabling kbdmux(4) may help. 20090407: The size of structs vnet_net, vnet_inet and vnet_ipfw has changed; kernel modules referencing any of the above need to be recompiled. Bump __FreeBSD_version to 800075. 20090320: GEOM_PART has become the default partition slicer for storage devices, replacing GEOM_MBR, GEOM_BSD, GEOM_PC98 and GEOM_GPT slicers. It introduces some changes: MSDOS/EBR: the devices created from MSDOS extended partition entries (EBR) can be named differently than with GEOM_MBR and are now symlinks to devices with offset-based names. fstabs may need to be modified. BSD: the "geometry does not match label" warning is harmless in most cases but it points to problems in file system misalignment with disk geometry. The "c" partition is now implicit, covers the whole top-level drive and cannot be (mis)used by users. General: Kernel dumps are now not allowed to be written to devices whose partition types indicate they are meant to be used for file systems (or, in case of MSDOS partitions, as something else than the "386BSD" type). Most of these changes date approximately from 200812. 20090319: The uscanner(4) driver has been removed from the kernel. This follows Linux removing theirs in 2.6 and making libusb the default interface (supported by sane). 20090319: The multicast forwarding code has been cleaned up. netstat(1) only relies on KVM now for printing bandwidth upcall meters. The IPv4 and IPv6 modules are split into ip_mroute_mod and ip6_mroute_mod respectively. The config(5) options for statically compiling this code remain the same, i.e. 'options MROUTING'. 20090315: Support for the IFF_NEEDSGIANT network interface flag has been removed, which means that non-MPSAFE network device drivers are no longer supported. In particular, if_ar, if_sr, and network device drivers from the old (legacy) USB stack can no longer be built or used. 20090313: POSIX.1 Native Language Support (NLS) has been enabled in libc and a bunch of new language catalog files have also been added. This means that some common libc messages are now localized and they depend on the LC_MESSAGES environmental variable. 20090313: The k8temp(4) driver has been renamed to amdtemp(4) since support for Family 10 and Family 11 CPU families was added. 20090309: IGMPv3 and Source-Specific Multicast (SSM) have been merged to the IPv4 stack. VIMAGE hooks are in but not yet used. For kernel developers, the most important changes are that the ip_output() and ip_input() paths no longer take the IN_MULTI_LOCK(), and this lock has been downgraded to a non-recursive mutex. Transport protocols (UDP, Raw IP) are now responsible for filtering inbound multicast traffic according to group membership and source filters. The imo_multicast_filter() KPI exists for this purpose. Transports which do not use multicast (SCTP, TCP) already reject multicast by default. Forwarding and receive performance may improve as a mutex acquisition is no longer needed in the ip_input() low-level input path. in_addmulti() and in_delmulti() are shimmed to new KPIs which exist to support SSM in-kernel. For application developers, it is recommended that loopback of multicast datagrams be disabled for best performance, as this will still cause the lock to be taken for each looped-back datagram transmission. The net.inet.ip.mcast.loop sysctl may be tuned to 0 to disable loopback by default; it defaults to 1 to preserve the existing behaviour. For systems administrators, to obtain best performance with multicast reception and multiple groups, it is always recommended that a card with a suitably precise hash filter is used. Hash collisions will still result in the lock being taken within the transport protocol input path to check group membership. If deploying FreeBSD in an environment with IGMP snooping switches, it is recommended that the net.inet.igmp.sendlocal sysctl remain enabled; this forces 224.0.0.0/24 group membership to be announced via IGMP. The size of 'struct igmpstat' has changed; netstat needs to be recompiled to reflect this. Bump __FreeBSD_version to 800070. 20090309: libusb20.so.1 is now installed as libusb.so.1 and the ports system updated to use it. This requires a buildworld/installworld in order to update the library and dependencies (usbconfig, etc). Its advisable to rebuild all ports which uses libusb. More specific directions are given in the ports collection UPDATING file. Any /etc/libmap.conf entries for libusb are no longer required and can be removed. 20090302: A workaround is committed to allow the creation of System V shared memory segment of size > 2 GB on the 64-bit architectures. Due to a limitation of the existing ABI, the shm_segsz member of the struct shmid_ds, returned by shmctl(IPC_STAT) call is wrong for large segments. Note that limits must be explicitly raised to allow such segments to be created. 20090301: The layout of struct ifnet has changed, requiring a rebuild of all network device driver modules. 20090227: The /dev handling for the new USB stack has changed, a buildworld/installworld is required for libusb20. 20090223: The new USB2 stack has now been permanently moved in and all kernel and module names reverted to their previous values (eg, usb, ehci, ohci, ums, ...). The old usb stack can be compiled in by prefixing the name with the letter 'o', the old usb modules have been removed. Updating entry 20090216 for xorg and 20090215 for libmap may still apply. 20090217: The rc.conf(5) option if_up_delay has been renamed to defaultroute_delay to better reflect its purpose. If you have customized this setting in /etc/rc.conf you need to update it to use the new name. 20090216: xorg 7.4 wants to configure its input devices via hald which does not yet work with USB2. If the keyboard/mouse does not work in xorg then add Option "AllowEmptyInput" "off" to your ServerLayout section. This will cause X to use the configured kbd and mouse sections from your xorg.conf. 20090215: The GENERIC kernels for all architectures now default to the new USB2 stack. No kernel config options or code have been removed so if a problem arises please report it and optionally revert to the old USB stack. If you are loading USB kernel modules or have a custom kernel that includes GENERIC then ensure that usb names are also changed over, eg uftdi -> usb2_serial_ftdi. Older programs linked against the ports libusb 0.1 need to be redirected to the new stack's libusb20. /etc/libmap.conf can be used for this: # Map old usb library to new one for usb2 stack libusb-0.1.so.8 libusb20.so.1 20090209: All USB ethernet devices now attach as interfaces under the name ueN (eg. ue0). This is to provide a predictable name as vendors often change usb chipsets in a product without notice. 20090203: The ichsmb(4) driver has been changed to require SMBus slave addresses be left-justified (xxxxxxx0b) rather than right-justified. All of the other SMBus controller drivers require left-justified slave addresses, so this change makes all the drivers provide the same interface. 20090201: INET6 statistics (struct ip6stat) was updated. netstat(1) needs to be recompiled. 20090119: NTFS has been removed from GENERIC kernel on amd64 to match GENERIC on i386. Should not cause any issues since mount_ntfs(8) will load ntfs.ko module automatically when NTFS support is actually needed, unless ntfs.ko is not installed or security level prohibits loading kernel modules. If either is the case, "options NTFS" has to be added into kernel config. 20090115: TCP Appropriate Byte Counting (RFC 3465) support added to kernel. New field in struct tcpcb breaks ABI, so bump __FreeBSD_version to 800061. User space tools that rely on the size of struct tcpcb in tcp_var.h (e.g. sockstat) need to be recompiled. 20081225: ng_tty(4) module updated to match the new TTY subsystem. Due to API change, user-level applications must be updated. New API support added to mpd5 CVS and expected to be present in next mpd5.3 release. 20081219: With __FreeBSD_version 800060 the makefs tool is part of the base system (it was a port). 20081216: The afdata and ifnet locks have been changed from mutexes to rwlocks, network modules will need to be re-compiled. 20081214: __FreeBSD_version 800059 incorporates the new arp-v2 rewrite. RTF_CLONING, RTF_LLINFO and RTF_WASCLONED flags are eliminated. The new code reduced struct rtentry{} by 16 bytes on 32-bit architecture and 40 bytes on 64-bit architecture. The userland applications "arp" and "ndp" have been updated accordingly. The output from "netstat -r" shows only routing entries and none of the L2 information. 20081130: __FreeBSD_version 800057 marks the switchover from the binary ath hal to source code. Users must add the line: options AH_SUPPORT_AR5416 to their kernel config files when specifying: device ath_hal The ath_hal module no longer exists; the code is now compiled together with the driver in the ath module. It is now possible to tailor chip support (i.e. reduce the set of chips and thereby the code size); consult ath_hal(4) for details. 20081121: __FreeBSD_version 800054 adds memory barriers to , new interfaces to ifnet to facilitate multiple hardware transmit queues for cards that support them, and a lock-less ring-buffer implementation to enable drivers to more efficiently manage queueing of packets. 20081117: A new version of ZFS (version 13) has been merged to -HEAD. This version has zpool attribute "listsnapshots" off by default, which means "zfs list" does not show snapshots, and is the same as Solaris behavior. 20081028: dummynet(4) ABI has changed. ipfw(8) needs to be recompiled. 20081009: The uhci, ohci, ehci and slhci USB Host controller drivers have been put into separate modules. If you load the usb module separately through loader.conf you will need to load the appropriate *hci module as well. E.g. for a UHCI-based USB 2.0 controller add the following to loader.conf: uhci_load="YES" ehci_load="YES" 20081009: The ABI used by the PMC toolset has changed. Please keep userland (libpmc(3)) and the kernel module (hwpmc(4)) in sync. 20081009: atapci kernel module now includes only generic PCI ATA driver. AHCI driver moved to ataahci kernel module. All vendor-specific code moved into separate kernel modules: ataacard, ataacerlabs, ataadaptec, ataamd, ataati, atacenatek, atacypress, atacyrix, atahighpoint, ataintel, ataite, atajmicron, atamarvell, atamicron, atanational, atanetcell, atanvidia, atapromise, ataserverworks, atasiliconimage, atasis, atavia 20080820: The TTY subsystem of the kernel has been replaced by a new implementation, which provides better scalability and an improved driver model. Most common drivers have been migrated to the new TTY subsystem, while others have not. The following drivers have not yet been ported to the new TTY layer: PCI/ISA: cy, digi, rc, rp, sio USB: ubser, ucycom Line disciplines: ng_h4, ng_tty, ppp, sl, snp Adding these drivers to your kernel configuration file shall cause compilation to fail. 20080818: ntpd has been upgraded to 4.2.4p5. 20080801: OpenSSH has been upgraded to 5.1p1. For many years, FreeBSD's version of OpenSSH preferred DSA over RSA for host and user authentication keys. With this upgrade, we've switched to the vendor's default of RSA over DSA. This may cause upgraded clients to warn about unknown host keys even for previously known hosts. Users should follow the usual procedure for verifying host keys before accepting the RSA key. This can be circumvented by setting the "HostKeyAlgorithms" option to "ssh-dss,ssh-rsa" in ~/.ssh/config or on the ssh command line. Please note that the sequence of keys offered for authentication has been changed as well. You may want to specify IdentityFile in a different order to revert this behavior. 20080713: The sio(4) driver has been removed from the i386 and amd64 kernel configuration files. This means uart(4) is now the default serial port driver on those platforms as well. To prevent collisions with the sio(4) driver, the uart(4) driver uses different names for its device nodes. This means the onboard serial port will now most likely be called "ttyu0" instead of "ttyd0". You may need to reconfigure applications to use the new device names. When using the serial port as a boot console, be sure to update /boot/device.hints and /etc/ttys before booting the new kernel. If you forget to do so, you can still manually specify the hints at the loader prompt: set hint.uart.0.at="isa" set hint.uart.0.port="0x3F8" set hint.uart.0.flags="0x10" set hint.uart.0.irq="4" boot -s 20080609: The gpt(8) utility has been removed. Use gpart(8) to partition disks instead. 20080603: The version that Linuxulator emulates was changed from 2.4.2 to 2.6.16. If you experience any problems with Linux binaries please try to set sysctl compat.linux.osrelease to 2.4.2 and if it fixes the problem contact emulation mailing list. 20080525: ISDN4BSD (I4B) was removed from the src tree. You may need to update a your kernel configuration and remove relevant entries. 20080509: I have checked in code to support multiple routing tables. See the man pages setfib(1) and setfib(2). This is a hopefully backwards compatible version, but to make use of it you need to compile your kernel with options ROUTETABLES=2 (or more up to 16). 20080420: The 802.11 wireless support was redone to enable multi-bss operation on devices that are capable. The underlying device is no longer used directly but instead wlanX devices are cloned with ifconfig. This requires changes to rc.conf files. For example, change: ifconfig_ath0="WPA DHCP" to wlans_ath0=wlan0 ifconfig_wlan0="WPA DHCP" see rc.conf(5) for more details. In addition, mergemaster of /etc/rc.d is highly recommended. Simultaneous update of userland and kernel wouldn't hurt either. As part of the multi-bss changes the wlan_scan_ap and wlan_scan_sta modules were merged into the base wlan module. All references to these modules (e.g. in kernel config files) must be removed. 20080408: psm(4) has gained write(2) support in native operation level. Arbitrary commands can be written to /dev/psm%d and status can be read back from it. Therefore, an application is responsible for status validation and error recovery. It is a no-op in other operation levels. 20080312: Support for KSE threading has been removed from the kernel. To run legacy applications linked against KSE libmap.conf may be used. The following libmap.conf may be used to ensure compatibility with any prior release: libpthread.so.1 libthr.so.1 libpthread.so.2 libthr.so.2 libkse.so.3 libthr.so.3 20080301: The layout of struct vmspace has changed. This affects libkvm and any executables that link against libkvm and use the kvm_getprocs() function. In particular, but not exclusively, it affects ps(1), fstat(1), pkill(1), systat(1), top(1) and w(1). The effects are minimal, but it's advisable to upgrade world nonetheless. 20080229: The latest em driver no longer has support in it for the 82575 adapter, this is now moved to the igb driver. The split was done to make new features that are incompatible with older hardware easier to do. 20080220: The new geom_lvm(4) geom class has been renamed to geom_linux_lvm(4), likewise the kernel option is now GEOM_LINUX_LVM. 20080211: The default NFS mount mode has changed from UDP to TCP for increased reliability. If you rely on (insecurely) NFS mounting across a firewall you may need to update your firewall rules. 20080208: Belatedly note the addition of m_collapse for compacting mbuf chains. 20080126: The fts(3) structures have been changed to use adequate integer types for their members and so to be able to cope with huge file trees. The old fts(3) ABI is preserved through symbol versioning in libc, so third-party binaries using fts(3) should still work, although they will not take advantage of the extended types. At the same time, some third-party software might fail to build after this change due to unportable assumptions made in its source code about fts(3) structure members. Such software should be fixed by its vendor or, in the worst case, in the ports tree. FreeBSD_version 800015 marks this change for the unlikely case that a portable fix is impossible. 20080123: To upgrade to -current after this date, you must be running FreeBSD not older than 6.0-RELEASE. Upgrading to -current from 5.x now requires a stop over at RELENG_6 or RELENG_7 systems. 20071128: The ADAPTIVE_GIANT kernel option has been retired because its functionality is the default now. 20071118: The AT keyboard emulation of sunkbd(4) has been turned on by default. In order to make the special symbols of the Sun keyboards driven by sunkbd(4) work under X these now have to be configured the same way as Sun USB keyboards driven by ukbd(4) (which also does AT keyboard emulation), f.e.: Option "XkbLayout" "us" Option "XkbRules" "xorg" Option "XkbSymbols" "pc(pc105)+sun_vndr/usb(sun_usb)+us" 20071024: It has been decided that it is desirable to provide ABI backwards compatibility to the FreeBSD 4/5/6 versions of the PCIOCGETCONF, PCIOCREAD and PCIOCWRITE IOCTLs, which was broken with the introduction of PCI domain support (see the 20070930 entry). Unfortunately, this required the ABI of PCIOCGETCONF to be broken again in order to be able to provide backwards compatibility to the old version of that IOCTL. Thus consumers of PCIOCGETCONF have to be recompiled again. As for prominent ports this affects neither pciutils nor xorg-server this time, the hal port needs to be rebuilt however. 20071020: The misnamed kthread_create() and friends have been renamed to kproc_create() etc. Many of the callers already used kproc_start().. I will return kthread_create() and friends in a while with implementations that actually create threads, not procs. Renaming corresponds with version 800002. 20071010: RELENG_7 branched. COMMON ITEMS: General Notes ------------- Avoid using make -j when upgrading. While generally safe, there are sometimes problems using -j to upgrade. If your upgrade fails with -j, please try again without -j. From time to time in the past there have been problems using -j with buildworld and/or installworld. This is especially true when upgrading between "distant" versions (eg one that cross a major release boundary or several minor releases, or when several months have passed on the -current branch). Sometimes, obscure build problems are the result of environment poisoning. This can happen because the make utility reads its environment when searching for values for global variables. To run your build attempts in an "environmental clean room", prefix all make commands with 'env -i '. See the env(1) manual page for more details. When upgrading from one major version to another it is generally best to upgrade to the latest code in the currently installed branch first, then do an upgrade to the new branch. This is the best-tested upgrade path, and has the highest probability of being successful. Please try this approach before reporting problems with a major version upgrade. ZFS notes --------- When upgrading the boot ZFS pool to a new version, always follow these two steps: 1.) recompile and reinstall the ZFS boot loader and boot block (this is part of "make buildworld" and "make installworld") 2.) update the ZFS boot block on your boot drive The following example updates the ZFS boot block on the first partition (freebsd-boot) of a GPT partitioned drive ad0: "gpart bootcode -p /boot/gptzfsboot -i 1 ad0" Non-boot pools do not need these updates. To build a kernel ----------------- If you are updating from a prior version of FreeBSD (even one just a few days old), you should follow this procedure. It is the most failsafe as it uses a /usr/obj tree with a fresh mini-buildworld, make kernel-toolchain make -DALWAYS_CHECK_MAKE buildkernel KERNCONF=YOUR_KERNEL_HERE make -DALWAYS_CHECK_MAKE installkernel KERNCONF=YOUR_KERNEL_HERE To test a kernel once --------------------- If you just want to boot a kernel once (because you are not sure if it works, or if you want to boot a known bad kernel to provide debugging information) run make installkernel KERNCONF=YOUR_KERNEL_HERE KODIR=/boot/testkernel nextboot -k testkernel To just build a kernel when you know that it won't mess you up -------------------------------------------------------------- This assumes you are already running a CURRENT system. Replace ${arch} with the architecture of your machine (e.g. "i386", "arm", "amd64", "ia64", "pc98", "sparc64", "powerpc", "mips", etc). cd src/sys/${arch}/conf config KERNEL_NAME_HERE cd ../compile/KERNEL_NAME_HERE make depend make make install If this fails, go to the "To build a kernel" section. To rebuild everything and install it on the current system. ----------------------------------------------------------- # Note: sometimes if you are running current you gotta do more than # is listed here if you are upgrading from a really old current. make buildworld make kernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -p [5] make installworld mergemaster -i [4] make delete-old [6] To cross-install current onto a separate partition -------------------------------------------------- # In this approach we use a separate partition to hold # current's root, 'usr', and 'var' directories. A partition # holding "/", "/usr" and "/var" should be about 2GB in # size. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installworld DESTDIR=${CURRENT_ROOT} make distribution DESTDIR=${CURRENT_ROOT} # if newfs'd make installkernel KERNCONF=YOUR_KERNEL_HERE DESTDIR=${CURRENT_ROOT} cp /etc/fstab ${CURRENT_ROOT}/etc/fstab # if newfs'd To upgrade in-place from stable to current ---------------------------------------------- make buildworld [9] make kernel KERNCONF=YOUR_KERNEL_HERE [8] [1] [3] mergemaster -p [5] make installworld mergemaster -i [4] make delete-old [6] Make sure that you've read the UPDATING file to understand the tweaks to various things you need. At this point in the life cycle of current, things change often and you are on your own to cope. The defaults can also change, so please read ALL of the UPDATING entries. Also, if you are tracking -current, you must be subscribed to freebsd-current@freebsd.org. Make sure that before you update your sources that you have read and understood all the recent messages there. If in doubt, please track -stable which has much fewer pitfalls. [1] If you have third party modules, such as vmware, you should disable them at this point so they don't crash your system on reboot. [3] From the bootblocks, boot -s, and then do fsck -p mount -u / mount -a cd src adjkerntz -i # if CMOS is wall time Also, when doing a major release upgrade, it is required that you boot into single user mode to do the installworld. [4] Note: This step is non-optional. Failure to do this step can result in a significant reduction in the functionality of the system. Attempting to do it by hand is not recommended and those that pursue this avenue should read this file carefully, as well as the archives of freebsd-current and freebsd-hackers mailing lists for potential gotchas. The -U option is also useful to consider. See mergemaster(8) for more information. [5] Usually this step is a noop. However, from time to time you may need to do this if you get unknown user in the following step. It never hurts to do it all the time. You may need to install a new mergemaster (cd src/usr.sbin/mergemaster && make install) after the buildworld before this step if you last updated from [78]-stable or 9-stable before 20130430. [6] This only deletes old files and directories. Old libraries can be deleted by "make delete-old-libs", but you have to make sure that no program is using those libraries anymore. [8] In order to have a kernel that can run the 4.x binaries needed to do an installworld, you must include the COMPAT_FREEBSD4 option in your kernel. Failure to do so may leave you with a system that is hard to boot to recover. A similar kernel option COMPAT_FREEBSD5 is required to run the 5.x binaries on more recent kernels. And so on for COMPAT_FREEBSD6 and COMPAT_FREEBSD7. Make sure that you merge any new devices from GENERIC since the last time you updated your kernel config file. [9] When checking out sources, you must include the -P flag to have cvs prune empty directories. If CPUTYPE is defined in your /etc/make.conf, make sure to use the "?=" instead of the "=" assignment operator, so that buildworld can override the CPUTYPE if it needs to. MAKEOBJDIRPREFIX must be defined in an environment variable, and not on the command line, or in /etc/make.conf. buildworld will warn if it is improperly defined. FORMAT: This file contains a list, in reverse chronological order, of major breakages in tracking -current. It is not guaranteed to be a complete list of such breakages, and only contains entries since October 10, 2007. If you need to see UPDATING entries from before that date, you will need to fetch an UPDATING file from an older FreeBSD release. Copyright information: Copyright 1998-2009 M. Warner Losh. All Rights Reserved. Redistribution, publication, translation and use, with or without modification, in full or in part, in any form or format of this document are permitted without further permission from the author. THIS DOCUMENT IS PROVIDED BY WARNER LOSH ``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 WARNER LOSH 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. Contact Warner Losh if you have any questions about your use of this document. $FreeBSD$ Index: releng/9.3/contrib/bind9/lib/dns/resolver.c =================================================================== --- releng/9.3/contrib/bind9/lib/dns/resolver.c (revision 308204) +++ releng/9.3/contrib/bind9/lib/dns/resolver.c (revision 308205) @@ -1,9127 +1,9152 @@ /* * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id$ */ /*! \file */ #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 #include #include #include #include #include #include #include #define DNS_RESOLVER_TRACE #ifdef DNS_RESOLVER_TRACE #define RTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "res %p: %s", res, (m)) #define RRTRACE(r, m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "res %p: %s", (r), (m)) #define FCTXTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "fctx %p(%s): %s", fctx, fctx->info, (m)) #define FCTXTRACE2(m1, m2) \ isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "fctx %p(%s): %s %s", \ fctx, fctx->info, (m1), (m2)) #define FTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "fetch %p (fctx %p(%s)): %s", \ fetch, fetch->private, \ fetch->private->info, (m)) #define QTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ DNS_LOGMODULE_RESOLVER, \ ISC_LOG_DEBUG(3), \ "resquery %p (fctx %p(%s)): %s", \ query, query->fctx, \ query->fctx->info, (m)) #else #define RTRACE(m) #define RRTRACE(r, m) #define FCTXTRACE(m) #define FCTXTRACE2(m1, m2) #define FTRACE(m) #define QTRACE(m) #endif #define US_PER_SEC 1000000U /* * The maximum time we will wait for a single query. */ #define MAX_SINGLE_QUERY_TIMEOUT 9U #define MAX_SINGLE_QUERY_TIMEOUT_US (MAX_SINGLE_QUERY_TIMEOUT*US_PER_SEC) /* * We need to allow a individual query time to complete / timeout. */ #define MINIMUM_QUERY_TIMEOUT (MAX_SINGLE_QUERY_TIMEOUT + 1U) /* The default time in seconds for the whole query to live. */ #ifndef DEFAULT_QUERY_TIMEOUT #define DEFAULT_QUERY_TIMEOUT MINIMUM_QUERY_TIMEOUT #endif #ifndef MAXIMUM_QUERY_TIMEOUT #define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */ #endif /* The default maximum number of recursions to follow before giving up. */ #ifndef DEFAULT_RECURSION_DEPTH #define DEFAULT_RECURSION_DEPTH 7 #endif /* The default maximum number of iterative queries to allow before giving up. */ #ifndef DEFAULT_MAX_QUERIES #define DEFAULT_MAX_QUERIES 50 #endif /*% * Maximum EDNS0 input packet size. */ #define RECV_BUFFER_SIZE 4096 /* XXXRTH Constant. */ #define EDNSOPTS 2 /*% * This defines the maximum number of timeouts we will permit before we * disable EDNS0 on the query. */ #define MAX_EDNS0_TIMEOUTS 3 typedef struct fetchctx fetchctx_t; typedef struct query { /* Locked by task event serialization. */ unsigned int magic; fetchctx_t * fctx; isc_mem_t * mctx; dns_dispatchmgr_t * dispatchmgr; dns_dispatch_t * dispatch; isc_boolean_t exclusivesocket; dns_adbaddrinfo_t * addrinfo; isc_socket_t * tcpsocket; isc_time_t start; dns_messageid_t id; dns_dispentry_t * dispentry; ISC_LINK(struct query) link; isc_buffer_t buffer; isc_buffer_t *tsig; dns_tsigkey_t *tsigkey; isc_socketevent_t sendevent; unsigned int options; unsigned int attributes; unsigned int sends; unsigned int connects; unsigned char data[512]; } resquery_t; #define QUERY_MAGIC ISC_MAGIC('Q', '!', '!', '!') #define VALID_QUERY(query) ISC_MAGIC_VALID(query, QUERY_MAGIC) #define RESQUERY_ATTR_CANCELED 0x02 #define RESQUERY_CONNECTING(q) ((q)->connects > 0) #define RESQUERY_CANCELED(q) (((q)->attributes & \ RESQUERY_ATTR_CANCELED) != 0) #define RESQUERY_SENDING(q) ((q)->sends > 0) typedef enum { fetchstate_init = 0, /*%< Start event has not run yet. */ fetchstate_active, fetchstate_done /*%< FETCHDONE events posted. */ } fetchstate; typedef enum { badns_unreachable = 0, badns_response, badns_validation } badnstype_t; struct fetchctx { /*% Not locked. */ unsigned int magic; dns_resolver_t * res; dns_name_t name; dns_rdatatype_t type; unsigned int options; unsigned int bucketnum; char * info; isc_mem_t * mctx; /*% Locked by appropriate bucket lock. */ fetchstate state; isc_boolean_t want_shutdown; isc_boolean_t cloned; isc_boolean_t spilled; unsigned int references; isc_event_t control_event; ISC_LINK(struct fetchctx) link; ISC_LIST(dns_fetchevent_t) events; /*% Locked by task event serialization. */ dns_name_t domain; dns_rdataset_t nameservers; unsigned int attributes; isc_timer_t * timer; isc_time_t expires; isc_interval_t interval; dns_message_t * qmessage; dns_message_t * rmessage; ISC_LIST(resquery_t) queries; dns_adbfindlist_t finds; dns_adbfind_t * find; dns_adbfindlist_t altfinds; dns_adbfind_t * altfind; dns_adbaddrinfolist_t forwaddrs; dns_adbaddrinfolist_t altaddrs; isc_sockaddrlist_t forwarders; dns_fwdpolicy_t fwdpolicy; isc_sockaddrlist_t bad; isc_sockaddrlist_t edns; isc_sockaddrlist_t edns512; isc_sockaddrlist_t bad_edns; dns_validator_t *validator; ISC_LIST(dns_validator_t) validators; dns_db_t * cache; dns_adb_t * adb; isc_boolean_t ns_ttl_ok; isc_uint32_t ns_ttl; /*% * The number of events we're waiting for. */ unsigned int pending; /*% * The number of times we've "restarted" the current * nameserver set. This acts as a failsafe to prevent * us from pounding constantly on a particular set of * servers that, for whatever reason, are not giving * us useful responses, but are responding in such a * way that they are not marked "bad". */ unsigned int restarts; /*% * The number of timeouts that have occurred since we * last successfully received a response packet. This * is used for EDNS0 black hole detection. */ unsigned int timeouts; /*% * Look aside state for DS lookups. */ dns_name_t nsname; dns_fetch_t * nsfetch; dns_rdataset_t nsrrset; /*% * Number of queries that reference this context. */ unsigned int nqueries; /*% * The reason to print when logging a successful * response to a query. */ const char * reason; /*% * Random numbers to use for mixing up server addresses. */ isc_uint32_t rand_buf; isc_uint32_t rand_bits; /*% * Fetch-local statistics for detailed logging. */ isc_result_t result; /*%< fetch result */ isc_result_t vresult; /*%< validation result */ int exitline; isc_time_t start; isc_uint64_t duration; isc_boolean_t logged; unsigned int querysent; unsigned int totalqueries; unsigned int referrals; unsigned int lamecount; unsigned int neterr; unsigned int badresp; unsigned int adberr; unsigned int findfail; unsigned int valfail; isc_boolean_t timeout; dns_adbaddrinfo_t *addrinfo; isc_sockaddr_t *client; unsigned int depth; }; #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!') #define VALID_FCTX(fctx) ISC_MAGIC_VALID(fctx, FCTX_MAGIC) #define FCTX_ATTR_HAVEANSWER 0x0001 #define FCTX_ATTR_GLUING 0x0002 #define FCTX_ATTR_ADDRWAIT 0x0004 #define FCTX_ATTR_SHUTTINGDOWN 0x0008 #define FCTX_ATTR_WANTCACHE 0x0010 #define FCTX_ATTR_WANTNCACHE 0x0020 #define FCTX_ATTR_NEEDEDNS0 0x0040 #define FCTX_ATTR_TRIEDFIND 0x0080 #define FCTX_ATTR_TRIEDALT 0x0100 #define HAVE_ANSWER(f) (((f)->attributes & FCTX_ATTR_HAVEANSWER) != \ 0) #define GLUING(f) (((f)->attributes & FCTX_ATTR_GLUING) != \ 0) #define ADDRWAIT(f) (((f)->attributes & FCTX_ATTR_ADDRWAIT) != \ 0) #define SHUTTINGDOWN(f) (((f)->attributes & FCTX_ATTR_SHUTTINGDOWN) \ != 0) #define WANTCACHE(f) (((f)->attributes & FCTX_ATTR_WANTCACHE) != 0) #define WANTNCACHE(f) (((f)->attributes & FCTX_ATTR_WANTNCACHE) != 0) #define NEEDEDNS0(f) (((f)->attributes & FCTX_ATTR_NEEDEDNS0) != 0) #define TRIEDFIND(f) (((f)->attributes & FCTX_ATTR_TRIEDFIND) != 0) #define TRIEDALT(f) (((f)->attributes & FCTX_ATTR_TRIEDALT) != 0) typedef struct { dns_adbaddrinfo_t * addrinfo; fetchctx_t * fctx; } dns_valarg_t; struct dns_fetch { unsigned int magic; fetchctx_t * private; }; #define DNS_FETCH_MAGIC ISC_MAGIC('F', 't', 'c', 'h') #define DNS_FETCH_VALID(fetch) ISC_MAGIC_VALID(fetch, DNS_FETCH_MAGIC) typedef struct fctxbucket { isc_task_t * task; isc_mutex_t lock; ISC_LIST(fetchctx_t) fctxs; isc_boolean_t exiting; isc_mem_t * mctx; } fctxbucket_t; typedef struct alternate { isc_boolean_t isaddress; union { isc_sockaddr_t addr; struct { dns_name_t name; in_port_t port; } _n; } _u; ISC_LINK(struct alternate) link; } alternate_t; typedef struct dns_badcache dns_badcache_t; struct dns_badcache { dns_badcache_t * next; dns_rdatatype_t type; isc_time_t expire; unsigned int hashval; dns_name_t name; }; #define DNS_BADCACHE_SIZE 1021 #define DNS_BADCACHE_TTL(fctx) \ (((fctx)->res->lame_ttl > 30 ) ? (fctx)->res->lame_ttl : 30) struct dns_resolver { /* Unlocked. */ unsigned int magic; isc_mem_t * mctx; isc_mutex_t lock; isc_mutex_t nlock; isc_mutex_t primelock; dns_rdataclass_t rdclass; isc_socketmgr_t * socketmgr; isc_timermgr_t * timermgr; isc_taskmgr_t * taskmgr; dns_view_t * view; isc_boolean_t frozen; unsigned int options; dns_dispatchmgr_t * dispatchmgr; dns_dispatchset_t * dispatches4; isc_boolean_t exclusivev4; dns_dispatchset_t * dispatches6; isc_boolean_t exclusivev6; unsigned int nbuckets; fctxbucket_t * buckets; isc_uint32_t lame_ttl; ISC_LIST(alternate_t) alternates; isc_uint16_t udpsize; #if USE_ALGLOCK isc_rwlock_t alglock; #endif dns_rbt_t * algorithms; #if USE_MBSLOCK isc_rwlock_t mbslock; #endif dns_rbt_t * mustbesecure; unsigned int spillatmax; unsigned int spillatmin; isc_timer_t * spillattimer; isc_boolean_t zero_no_soa_ttl; unsigned int query_timeout; unsigned int maxdepth; /* Locked by lock. */ unsigned int references; isc_boolean_t exiting; isc_eventlist_t whenshutdown; unsigned int activebuckets; isc_boolean_t priming; unsigned int spillat; /* clients-per-query */ /* Bad cache. */ dns_badcache_t ** badcache; unsigned int badcount; unsigned int badhash; unsigned int badsweep; /* Locked by primelock. */ dns_fetch_t * primefetch; /* Locked by nlock. */ unsigned int nfctx; }; #define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!') #define VALID_RESOLVER(res) ISC_MAGIC_VALID(res, RES_MAGIC) /*% * Private addrinfo flags. These must not conflict with DNS_FETCHOPT_NOEDNS0, * which we also use as an addrinfo flag. */ #define FCTX_ADDRINFO_MARK 0x0001 #define FCTX_ADDRINFO_FORWARDER 0x1000 #define FCTX_ADDRINFO_TRIED 0x2000 #define UNMARKED(a) (((a)->flags & FCTX_ADDRINFO_MARK) \ == 0) #define ISFORWARDER(a) (((a)->flags & \ FCTX_ADDRINFO_FORWARDER) != 0) #define TRIED(a) (((a)->flags & \ FCTX_ADDRINFO_TRIED) != 0) #define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) #define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) static void destroy(dns_resolver_t *res); static void empty_bucket(dns_resolver_t *res); static isc_result_t resquery_send(resquery_t *query); static void resquery_response(isc_task_t *task, isc_event_t *event); static void resquery_connected(isc_task_t *task, isc_event_t *event); static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache); static void fctx_destroy(fetchctx_t *fctx); static isc_boolean_t fctx_unlink(fetchctx_t *fctx); static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, isc_boolean_t optout, isc_boolean_t secure, dns_rdataset_t *ardataset, isc_result_t *eresultp); static void validated(isc_task_t *task, isc_event_t *event); static isc_boolean_t maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked); static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, badnstype_t badtype); static inline isc_result_t findnoqname(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type, dns_name_t **noqname); /*% * Increment resolver-related statistics counters. */ static inline void inc_stats(dns_resolver_t *res, isc_statscounter_t counter) { if (res->view->resstats != NULL) isc_stats_increment(res->view->resstats, counter); } static isc_result_t valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, unsigned int valoptions, isc_task_t *task) { dns_validator_t *validator = NULL; dns_valarg_t *valarg; isc_result_t result; valarg = isc_mem_get(fctx->mctx, sizeof(*valarg)); if (valarg == NULL) return (ISC_R_NOMEMORY); valarg->fctx = fctx; valarg->addrinfo = addrinfo; if (!ISC_LIST_EMPTY(fctx->validators)) - INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0); + valoptions |= DNS_VALIDATOR_DEFER; + else + valoptions &= ~DNS_VALIDATOR_DEFER; result = dns_validator_create(fctx->res->view, name, type, rdataset, sigrdataset, fctx->rmessage, valoptions, task, validated, valarg, &validator); if (result == ISC_R_SUCCESS) { inc_stats(fctx->res, dns_resstatscounter_val); if ((valoptions & DNS_VALIDATOR_DEFER) == 0) { INSIST(fctx->validator == NULL); fctx->validator = validator; } ISC_LIST_APPEND(fctx->validators, validator, link); } else isc_mem_put(fctx->mctx, valarg, sizeof(*valarg)); return (result); } static isc_boolean_t rrsig_fromchildzone(fetchctx_t *fctx, dns_rdataset_t *rdataset) { dns_namereln_t namereln; dns_rdata_rrsig_t rrsig; dns_rdata_t rdata = DNS_RDATA_INIT; int order; isc_result_t result; unsigned int labels; for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &rrsig, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); namereln = dns_name_fullcompare(&rrsig.signer, &fctx->domain, &order, &labels); if (namereln == dns_namereln_subdomain) return (ISC_TRUE); dns_rdata_reset(&rdata); } return (ISC_FALSE); } static isc_boolean_t fix_mustbedelegationornxdomain(dns_message_t *message, fetchctx_t *fctx) { dns_name_t *name; dns_name_t *domain = &fctx->domain; dns_rdataset_t *rdataset; dns_rdatatype_t type; isc_result_t result; isc_boolean_t keep_auth = ISC_FALSE; if (message->rcode == dns_rcode_nxdomain) return (ISC_FALSE); /* * A DS RRset can appear anywhere in a zone, even for a delegation-only * zone. So a response to an explicit query for this type should be * excluded from delegation-only fixup. * * SOA, NS, and DNSKEY can only exist at a zone apex, so a postive * response to a query for these types can never violate the * delegation-only assumption: if the query name is below a * zone cut, the response should normally be a referral, which should * be accepted; if the query name is below a zone cut but the server * happens to have authority for the zone of the query name, the * response is a (non-referral) answer. But this does not violate * delegation-only because the query name must be in a different zone * due to the "apex-only" nature of these types. Note that if the * remote server happens to have authority for a child zone of a * delegation-only zone, we may still incorrectly "fix" the response * with NXDOMAIN for queries for other types. Unfortunately it's * generally impossible to differentiate this case from violation of * the delegation-only assumption. Once the resolver learns the * correct zone cut, possibly via a separate query for an "apex-only" * type, queries for other types will be resolved correctly. * * A query for type ANY will be accepted if it hits an exceptional * type above in the answer section as it should be from a child * zone. * * Also accept answers with RRSIG records from the child zone. * Direct queries for RRSIG records should not be answered from * the parent zone. */ if (message->counts[DNS_SECTION_ANSWER] != 0 && (fctx->type == dns_rdatatype_ns || fctx->type == dns_rdatatype_ds || fctx->type == dns_rdatatype_soa || fctx->type == dns_rdatatype_any || fctx->type == dns_rdatatype_rrsig || fctx->type == dns_rdatatype_dnskey)) { result = dns_message_firstname(message, DNS_SECTION_ANSWER); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, DNS_SECTION_ANSWER, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (!dns_name_equal(name, &fctx->name)) continue; type = rdataset->type; /* * RRsig from child? */ if (type == dns_rdatatype_rrsig && rrsig_fromchildzone(fctx, rdataset)) return (ISC_FALSE); /* * Direct query for apex records or DS. */ if (fctx->type == type && (type == dns_rdatatype_ds || type == dns_rdatatype_ns || type == dns_rdatatype_soa || type == dns_rdatatype_dnskey)) return (ISC_FALSE); /* * Indirect query for apex records or DS. */ if (fctx->type == dns_rdatatype_any && (type == dns_rdatatype_ns || type == dns_rdatatype_ds || type == dns_rdatatype_soa || type == dns_rdatatype_dnskey)) return (ISC_FALSE); } result = dns_message_nextname(message, DNS_SECTION_ANSWER); } } /* * A NODATA response to a DS query? */ if (fctx->type == dns_rdatatype_ds && message->counts[DNS_SECTION_ANSWER] == 0) return (ISC_FALSE); /* Look for referral or indication of answer from child zone? */ if (message->counts[DNS_SECTION_AUTHORITY] == 0) goto munge; result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { type = rdataset->type; if (type == dns_rdatatype_soa && dns_name_equal(name, domain)) keep_auth = ISC_TRUE; if (type != dns_rdatatype_ns && type != dns_rdatatype_soa && type != dns_rdatatype_rrsig) continue; if (type == dns_rdatatype_rrsig) { if (rrsig_fromchildzone(fctx, rdataset)) return (ISC_FALSE); else continue; } /* NS or SOA records. */ if (dns_name_equal(name, domain)) { /* * If a query for ANY causes a negative * response, we can be sure that this is * an empty node. For other type of queries * we cannot differentiate an empty node * from a node that just doesn't have that * type of record. We only accept the former * case. */ if (message->counts[DNS_SECTION_ANSWER] == 0 && fctx->type == dns_rdatatype_any) return (ISC_FALSE); } else if (dns_name_issubdomain(name, domain)) { /* Referral or answer from child zone. */ return (ISC_FALSE); } } result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); } munge: message->rcode = dns_rcode_nxdomain; message->counts[DNS_SECTION_ANSWER] = 0; if (!keep_auth) message->counts[DNS_SECTION_AUTHORITY] = 0; message->counts[DNS_SECTION_ADDITIONAL] = 0; return (ISC_TRUE); } static inline isc_result_t fctx_starttimer(fetchctx_t *fctx) { /* * Start the lifetime timer for fctx. * * This is also used for stopping the idle timer; in that * case we must purge events already posted to ensure that * no further idle events are delivered. */ return (isc_timer_reset(fctx->timer, isc_timertype_once, &fctx->expires, NULL, ISC_TRUE)); } static inline void fctx_stoptimer(fetchctx_t *fctx) { isc_result_t result; /* * We don't return a result if resetting the timer to inactive fails * since there's nothing to be done about it. Resetting to inactive * should never fail anyway, since the code as currently written * cannot fail in that case. */ result = isc_timer_reset(fctx->timer, isc_timertype_inactive, NULL, NULL, ISC_TRUE); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_reset(): %s", isc_result_totext(result)); } } static inline isc_result_t fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) { /* * Start the idle timer for fctx. The lifetime timer continues * to be in effect. */ return (isc_timer_reset(fctx->timer, isc_timertype_once, &fctx->expires, interval, ISC_FALSE)); } /* * Stopping the idle timer is equivalent to calling fctx_starttimer(), but * we use fctx_stopidletimer for readability in the code below. */ #define fctx_stopidletimer fctx_starttimer static inline void resquery_destroy(resquery_t **queryp) { resquery_t *query; REQUIRE(queryp != NULL); query = *queryp; REQUIRE(!ISC_LINK_LINKED(query, link)); INSIST(query->tcpsocket == NULL); query->fctx->nqueries--; if (SHUTTINGDOWN(query->fctx)) { dns_resolver_t *res = query->fctx->res; if (maybe_destroy(query->fctx, ISC_FALSE)) empty_bucket(res); } query->magic = 0; isc_mem_put(query->mctx, query, sizeof(*query)); *queryp = NULL; } static void fctx_cancelquery(resquery_t **queryp, dns_dispatchevent_t **deventp, isc_time_t *finish, isc_boolean_t no_response) { fetchctx_t *fctx; resquery_t *query; unsigned int rtt, rttms; unsigned int factor; dns_adbfind_t *find; dns_adbaddrinfo_t *addrinfo; isc_socket_t *socket; query = *queryp; fctx = query->fctx; FCTXTRACE("cancelquery"); REQUIRE(!RESQUERY_CANCELED(query)); query->attributes |= RESQUERY_ATTR_CANCELED; /* * Should we update the RTT? */ if (finish != NULL || no_response) { if (finish != NULL) { /* * We have both the start and finish times for this * packet, so we can compute a real RTT. */ rtt = (unsigned int)isc_time_microdiff(finish, &query->start); factor = DNS_ADB_RTTADJDEFAULT; rttms = rtt / 1000; if (rttms < DNS_RESOLVER_QRYRTTCLASS0) { inc_stats(fctx->res, dns_resstatscounter_queryrtt0); } else if (rttms < DNS_RESOLVER_QRYRTTCLASS1) { inc_stats(fctx->res, dns_resstatscounter_queryrtt1); } else if (rttms < DNS_RESOLVER_QRYRTTCLASS2) { inc_stats(fctx->res, dns_resstatscounter_queryrtt2); } else if (rttms < DNS_RESOLVER_QRYRTTCLASS3) { inc_stats(fctx->res, dns_resstatscounter_queryrtt3); } else if (rttms < DNS_RESOLVER_QRYRTTCLASS4) { inc_stats(fctx->res, dns_resstatscounter_queryrtt4); } else { inc_stats(fctx->res, dns_resstatscounter_queryrtt5); } } else { /* * We don't have an RTT for this query. Maybe the * packet was lost, or maybe this server is very * slow. We don't know. Increase the RTT. */ INSIST(no_response); rtt = query->addrinfo->srtt + 200000; if (rtt > MAX_SINGLE_QUERY_TIMEOUT_US) rtt = MAX_SINGLE_QUERY_TIMEOUT_US; /* * Replace the current RTT with our value. */ factor = DNS_ADB_RTTADJREPLACE; } dns_adb_adjustsrtt(fctx->adb, query->addrinfo, rtt, factor); } /* Remember that the server has been tried. */ if (!TRIED(query->addrinfo)) { dns_adb_changeflags(fctx->adb, query->addrinfo, FCTX_ADDRINFO_TRIED, FCTX_ADDRINFO_TRIED); } /* * Age RTTs of servers not tried. */ factor = DNS_ADB_RTTADJAGE; if (finish != NULL) for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); if (finish != NULL && TRIEDFIND(fctx)) for (find = ISC_LIST_HEAD(fctx->finds); find != NULL; find = ISC_LIST_NEXT(find, publink)) for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); if (finish != NULL && TRIEDALT(fctx)) { for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); for (find = ISC_LIST_HEAD(fctx->altfinds); find != NULL; find = ISC_LIST_NEXT(find, publink)) for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) if (UNMARKED(addrinfo)) dns_adb_adjustsrtt(fctx->adb, addrinfo, 0, factor); } /* * Check for any outstanding socket events. If they exist, cancel * them and let the event handlers finish the cleanup. The resolver * only needs to worry about managing the connect and send events; * the dispatcher manages the recv events. */ if (RESQUERY_CONNECTING(query)) { /* * Cancel the connect. */ if (query->tcpsocket != NULL) { isc_socket_cancel(query->tcpsocket, NULL, ISC_SOCKCANCEL_CONNECT); } else if (query->dispentry != NULL) { INSIST(query->exclusivesocket); socket = dns_dispatch_getentrysocket(query->dispentry); if (socket != NULL) isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_CONNECT); } } else if (RESQUERY_SENDING(query)) { /* * Cancel the pending send. */ if (query->exclusivesocket && query->dispentry != NULL) socket = dns_dispatch_getentrysocket(query->dispentry); else socket = dns_dispatch_getsocket(query->dispatch); if (socket != NULL) isc_socket_cancel(socket, NULL, ISC_SOCKCANCEL_SEND); } if (query->dispentry != NULL) dns_dispatch_removeresponse(&query->dispentry, deventp); ISC_LIST_UNLINK(fctx->queries, query, link); if (query->tsig != NULL) isc_buffer_free(&query->tsig); if (query->tsigkey != NULL) dns_tsigkey_detach(&query->tsigkey); if (query->dispatch != NULL) dns_dispatch_detach(&query->dispatch); if (! (RESQUERY_CONNECTING(query) || RESQUERY_SENDING(query))) /* * It's safe to destroy the query now. */ resquery_destroy(&query); } static void fctx_cancelqueries(fetchctx_t *fctx, isc_boolean_t no_response) { resquery_t *query, *next_query; FCTXTRACE("cancelqueries"); for (query = ISC_LIST_HEAD(fctx->queries); query != NULL; query = next_query) { next_query = ISC_LIST_NEXT(query, link); fctx_cancelquery(&query, NULL, NULL, no_response); } } static void fctx_cleanupfinds(fetchctx_t *fctx) { dns_adbfind_t *find, *next_find; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (find = ISC_LIST_HEAD(fctx->finds); find != NULL; find = next_find) { next_find = ISC_LIST_NEXT(find, publink); ISC_LIST_UNLINK(fctx->finds, find, publink); dns_adb_destroyfind(&find); } fctx->find = NULL; } static void fctx_cleanupaltfinds(fetchctx_t *fctx) { dns_adbfind_t *find, *next_find; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (find = ISC_LIST_HEAD(fctx->altfinds); find != NULL; find = next_find) { next_find = ISC_LIST_NEXT(find, publink); ISC_LIST_UNLINK(fctx->altfinds, find, publink); dns_adb_destroyfind(&find); } fctx->altfind = NULL; } static void fctx_cleanupforwaddrs(fetchctx_t *fctx) { dns_adbaddrinfo_t *addr, *next_addr; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->forwaddrs); addr != NULL; addr = next_addr) { next_addr = ISC_LIST_NEXT(addr, publink); ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink); dns_adb_freeaddrinfo(fctx->adb, &addr); } } static void fctx_cleanupaltaddrs(fetchctx_t *fctx) { dns_adbaddrinfo_t *addr, *next_addr; REQUIRE(ISC_LIST_EMPTY(fctx->queries)); for (addr = ISC_LIST_HEAD(fctx->altaddrs); addr != NULL; addr = next_addr) { next_addr = ISC_LIST_NEXT(addr, publink); ISC_LIST_UNLINK(fctx->altaddrs, addr, publink); dns_adb_freeaddrinfo(fctx->adb, &addr); } } static inline void fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) { FCTXTRACE("stopeverything"); fctx_cancelqueries(fctx, no_response); fctx_cleanupfinds(fctx); fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); fctx_cleanupaltaddrs(fctx); fctx_stoptimer(fctx); } static inline void fctx_sendevents(fetchctx_t *fctx, isc_result_t result, int line) { dns_fetchevent_t *event, *next_event; isc_task_t *task; unsigned int count = 0; isc_interval_t i; isc_boolean_t logit = ISC_FALSE; isc_time_t now; unsigned int old_spillat; unsigned int new_spillat = 0; /* initialized to silence compiler warnings */ /* * Caller must be holding the appropriate bucket lock. */ REQUIRE(fctx->state == fetchstate_done); FCTXTRACE("sendevents"); /* * Keep some record of fetch result for logging later (if required). */ fctx->result = result; fctx->exitline = line; TIME_NOW(&now); fctx->duration = isc_time_microdiff(&now, &fctx->start); for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, ev_link); ISC_LIST_UNLINK(fctx->events, event, ev_link); task = event->ev_sender; event->ev_sender = fctx; event->vresult = fctx->vresult; if (!HAVE_ANSWER(fctx)) event->result = result; INSIST(result != ISC_R_SUCCESS || dns_rdataset_isassociated(event->rdataset) || fctx->type == dns_rdatatype_any || fctx->type == dns_rdatatype_rrsig || fctx->type == dns_rdatatype_sig); /* * Negative results must be indicated in event->result. */ if (dns_rdataset_isassociated(event->rdataset) && NEGATIVE(event->rdataset)) { INSIST(event->result == DNS_R_NCACHENXDOMAIN || event->result == DNS_R_NCACHENXRRSET); } event->qtotal = fctx->totalqueries; isc_task_sendanddetach(&task, ISC_EVENT_PTR(&event)); count++; } if ((fctx->attributes & FCTX_ATTR_HAVEANSWER) != 0 && fctx->spilled && (count < fctx->res->spillatmax || fctx->res->spillatmax == 0)) { LOCK(&fctx->res->lock); if (count == fctx->res->spillat && !fctx->res->exiting) { old_spillat = fctx->res->spillat; fctx->res->spillat += 5; if (fctx->res->spillat > fctx->res->spillatmax && fctx->res->spillatmax != 0) fctx->res->spillat = fctx->res->spillatmax; new_spillat = fctx->res->spillat; if (new_spillat != old_spillat) { logit = ISC_TRUE; } isc_interval_set(&i, 20 * 60, 0); result = isc_timer_reset(fctx->res->spillattimer, isc_timertype_ticker, NULL, &i, ISC_TRUE); RUNTIME_CHECK(result == ISC_R_SUCCESS); } UNLOCK(&fctx->res->lock); if (logit) isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, "clients-per-query increased to %u", new_spillat); } } static inline void log_edns(fetchctx_t *fctx) { char domainbuf[DNS_NAME_FORMATSIZE]; if (fctx->reason == NULL) return; /* * We do not know if fctx->domain is the actual domain the record * lives in or a parent domain so we have a '?' after it. */ dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_EDNS_DISABLED, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, "success resolving '%s' (in '%s'?) after %s", fctx->info, domainbuf, fctx->reason); fctx->reason = NULL; } static void fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { dns_resolver_t *res; isc_boolean_t no_response; REQUIRE(line >= 0); FCTXTRACE("done"); res = fctx->res; if (result == ISC_R_SUCCESS) { /*% * Log any deferred EDNS timeout messages. */ log_edns(fctx); no_response = ISC_TRUE; } else no_response = ISC_FALSE; fctx->reason = NULL; fctx_stopeverything(fctx, no_response); LOCK(&res->buckets[fctx->bucketnum].lock); fctx->state = fetchstate_done; fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; fctx_sendevents(fctx, result, line); UNLOCK(&res->buckets[fctx->bucketnum].lock); } static void process_sendevent(resquery_t *query, isc_event_t *event) { isc_socketevent_t *sevent = (isc_socketevent_t *)event; isc_boolean_t retry = ISC_FALSE; isc_result_t result; fetchctx_t *fctx; fctx = query->fctx; if (RESQUERY_CANCELED(query)) { if (query->sends == 0 && query->connects == 0) { /* * This query was canceled while the * isc_socket_sendto/connect() was in progress. */ if (query->tcpsocket != NULL) isc_socket_detach(&query->tcpsocket); resquery_destroy(&query); } } else { switch (sevent->result) { case ISC_R_SUCCESS: break; case ISC_R_HOSTUNREACH: case ISC_R_NETUNREACH: case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNREFUSED: /* * No route to remote. */ add_bad(fctx, query->addrinfo, sevent->result, badns_unreachable); fctx_cancelquery(&query, NULL, NULL, ISC_TRUE); retry = ISC_TRUE; break; default: fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); break; } } if (event->ev_type == ISC_SOCKEVENT_CONNECT) isc_event_free(&event); if (retry) { /* * Behave as if the idle timer has expired. For TCP * this may not actually reflect the latest timer. */ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); else fctx_try(fctx, ISC_TRUE, ISC_FALSE); } } static void resquery_udpconnected(isc_task_t *task, isc_event_t *event) { resquery_t *query = event->ev_arg; REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); QTRACE("udpconnected"); UNUSED(task); INSIST(RESQUERY_CONNECTING(query)); query->connects--; process_sendevent(query, event); } static void resquery_senddone(isc_task_t *task, isc_event_t *event) { resquery_t *query = event->ev_arg; REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); QTRACE("senddone"); /* * XXXRTH * * Currently we don't wait for the senddone event before retrying * a query. This means that if we get really behind, we may end * up doing extra work! */ UNUSED(task); INSIST(RESQUERY_SENDING(query)); query->sends--; process_sendevent(query, event); } static inline isc_result_t fctx_addopt(dns_message_t *message, unsigned int version, isc_uint16_t udpsize, dns_ednsopt_t *ednsopts, size_t count) { dns_rdataset_t *rdataset = NULL; isc_result_t result; result = dns_message_buildopt(message, &rdataset, version, udpsize, DNS_MESSAGEEXTFLAG_DO, ednsopts, count); if (result != ISC_R_SUCCESS) return (result); return (dns_message_setopt(message, rdataset)); } static inline void fctx_setretryinterval(fetchctx_t *fctx, unsigned int rtt) { unsigned int seconds; unsigned int us; /* * We retry every .8 seconds the first two times through the address * list, and then we do exponential back-off. */ if (fctx->restarts < 3) us = 800000; else us = (800000 << (fctx->restarts - 2)); /* * Add a fudge factor to the expected rtt based on the current * estimate. */ if (rtt < 50000) rtt += 50000; else if (rtt < 100000) rtt += 100000; else rtt += 200000; /* * Always wait for at least the expected rtt. */ if (us < rtt) us = rtt; /* * But don't ever wait for more than 10 seconds. */ if (us > MAX_SINGLE_QUERY_TIMEOUT_US) us = MAX_SINGLE_QUERY_TIMEOUT_US; seconds = us / US_PER_SEC; us -= seconds * US_PER_SEC; isc_interval_set(&fctx->interval, seconds, us * 1000); } static isc_result_t fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, unsigned int options) { dns_resolver_t *res; isc_task_t *task; isc_result_t result; resquery_t *query; isc_sockaddr_t addr; isc_boolean_t have_addr = ISC_FALSE; unsigned int srtt; FCTXTRACE("query"); res = fctx->res; task = res->buckets[fctx->bucketnum].task; srtt = addrinfo->srtt; /* * A forwarder needs to make multiple queries. Give it at least * a second to do these in. */ if (ISFORWARDER(addrinfo) && srtt < 1000000) srtt = 1000000; fctx_setretryinterval(fctx, srtt); result = fctx_startidletimer(fctx, &fctx->interval); if (result != ISC_R_SUCCESS) return (result); INSIST(ISC_LIST_EMPTY(fctx->validators)); dns_message_reset(fctx->rmessage, DNS_MESSAGE_INTENTPARSE); query = isc_mem_get(fctx->mctx, sizeof(*query)); if (query == NULL) { result = ISC_R_NOMEMORY; goto stop_idle_timer; } query->mctx = fctx->mctx; query->options = options; query->attributes = 0; query->sends = 0; query->connects = 0; /* * Note that the caller MUST guarantee that 'addrinfo' will remain * valid until this query is canceled. */ query->addrinfo = addrinfo; TIME_NOW(&query->start); /* * If this is a TCP query, then we need to make a socket and * a dispatch for it here. Otherwise we use the resolver's * shared dispatch. */ query->dispatchmgr = res->dispatchmgr; query->dispatch = NULL; query->exclusivesocket = ISC_FALSE; query->tcpsocket = NULL; if (res->view->peers != NULL) { dns_peer_t *peer = NULL; isc_netaddr_t dstip; isc_netaddr_fromsockaddr(&dstip, &addrinfo->sockaddr); result = dns_peerlist_peerbyaddr(res->view->peers, &dstip, &peer); if (result == ISC_R_SUCCESS) { result = dns_peer_getquerysource(peer, &addr); if (result == ISC_R_SUCCESS) have_addr = ISC_TRUE; } } if ((query->options & DNS_FETCHOPT_TCP) != 0) { int pf; pf = isc_sockaddr_pf(&addrinfo->sockaddr); if (!have_addr) { switch (pf) { case PF_INET: result = dns_dispatch_getlocaladdress( res->dispatches4->dispatches[0], &addr); break; case PF_INET6: result = dns_dispatch_getlocaladdress( res->dispatches6->dispatches[0], &addr); break; default: result = ISC_R_NOTIMPLEMENTED; break; } if (result != ISC_R_SUCCESS) goto cleanup_query; } isc_sockaddr_setport(&addr, 0); result = isc_socket_create(res->socketmgr, pf, isc_sockettype_tcp, &query->tcpsocket); if (result != ISC_R_SUCCESS) goto cleanup_query; #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT result = isc_socket_bind(query->tcpsocket, &addr, 0); if (result != ISC_R_SUCCESS) goto cleanup_socket; #endif /* * A dispatch will be created once the connect succeeds. */ } else { if (have_addr) { unsigned int attrs, attrmask; attrs = DNS_DISPATCHATTR_UDP; switch (isc_sockaddr_pf(&addr)) { case AF_INET: attrs |= DNS_DISPATCHATTR_IPV4; break; case AF_INET6: attrs |= DNS_DISPATCHATTR_IPV6; break; default: result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } attrmask = DNS_DISPATCHATTR_UDP; attrmask |= DNS_DISPATCHATTR_TCP; attrmask |= DNS_DISPATCHATTR_IPV4; attrmask |= DNS_DISPATCHATTR_IPV6; result = dns_dispatch_getudp(res->dispatchmgr, res->socketmgr, res->taskmgr, &addr, 4096, 1000, 32768, 16411, 16433, attrs, attrmask, &query->dispatch); if (result != ISC_R_SUCCESS) goto cleanup_query; } else { switch (isc_sockaddr_pf(&addrinfo->sockaddr)) { case PF_INET: dns_dispatch_attach( dns_resolver_dispatchv4(res), &query->dispatch); query->exclusivesocket = res->exclusivev4; break; case PF_INET6: dns_dispatch_attach( dns_resolver_dispatchv6(res), &query->dispatch); query->exclusivesocket = res->exclusivev6; break; default: result = ISC_R_NOTIMPLEMENTED; goto cleanup_query; } } /* * We should always have a valid dispatcher here. If we * don't support a protocol family, then its dispatcher * will be NULL, but we shouldn't be finding addresses for * protocol types we don't support, so the dispatcher * we found should never be NULL. */ INSIST(query->dispatch != NULL); } query->dispentry = NULL; query->fctx = fctx; query->tsig = NULL; query->tsigkey = NULL; ISC_LINK_INIT(query, link); query->magic = QUERY_MAGIC; if ((query->options & DNS_FETCHOPT_TCP) != 0) { /* * Connect to the remote server. * * XXXRTH Should we attach to the socket? */ result = isc_socket_connect(query->tcpsocket, &addrinfo->sockaddr, task, resquery_connected, query); if (result != ISC_R_SUCCESS) goto cleanup_socket; query->connects++; QTRACE("connecting via TCP"); } else { result = resquery_send(query); if (result != ISC_R_SUCCESS) goto cleanup_dispatch; } fctx->querysent++; fctx->totalqueries++; ISC_LIST_APPEND(fctx->queries, query, link); query->fctx->nqueries++; if (isc_sockaddr_pf(&addrinfo->sockaddr) == PF_INET) inc_stats(res, dns_resstatscounter_queryv4); else inc_stats(res, dns_resstatscounter_queryv6); if (res->view->resquerystats != NULL) dns_rdatatypestats_increment(res->view->resquerystats, fctx->type); return (ISC_R_SUCCESS); cleanup_socket: isc_socket_detach(&query->tcpsocket); cleanup_dispatch: if (query->dispatch != NULL) dns_dispatch_detach(&query->dispatch); cleanup_query: if (query->connects == 0) { query->magic = 0; isc_mem_put(fctx->mctx, query, sizeof(*query)); } stop_idle_timer: RUNTIME_CHECK(fctx_stopidletimer(fctx) == ISC_R_SUCCESS); return (result); } static isc_boolean_t bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; for (sa = ISC_LIST_HEAD(fctx->bad_edns); sa != NULL; sa = ISC_LIST_NEXT(sa, link)) { if (isc_sockaddr_equal(sa, address)) return (ISC_TRUE); } return (ISC_FALSE); } static void add_bad_edns(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; if (bad_edns(fctx, address)) return; sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; *sa = *address; ISC_LIST_INITANDAPPEND(fctx->bad_edns, sa, link); } static isc_boolean_t triededns(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; for (sa = ISC_LIST_HEAD(fctx->edns); sa != NULL; sa = ISC_LIST_NEXT(sa, link)) { if (isc_sockaddr_equal(sa, address)) return (ISC_TRUE); } return (ISC_FALSE); } static void add_triededns(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; if (triededns(fctx, address)) return; sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; *sa = *address; ISC_LIST_INITANDAPPEND(fctx->edns, sa, link); } static isc_boolean_t triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; for (sa = ISC_LIST_HEAD(fctx->edns512); sa != NULL; sa = ISC_LIST_NEXT(sa, link)) { if (isc_sockaddr_equal(sa, address)) return (ISC_TRUE); } return (ISC_FALSE); } static void add_triededns512(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; if (triededns512(fctx, address)) return; sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; *sa = *address; ISC_LIST_INITANDAPPEND(fctx->edns512, sa, link); } static isc_result_t resquery_send(resquery_t *query) { fetchctx_t *fctx; isc_result_t result; dns_name_t *qname = NULL; dns_rdataset_t *qrdataset = NULL; isc_region_t r; dns_resolver_t *res; isc_task_t *task; isc_socket_t *socket; isc_buffer_t tcpbuffer; isc_sockaddr_t *address; isc_buffer_t *buffer; isc_netaddr_t ipaddr; dns_tsigkey_t *tsigkey = NULL; dns_peer_t *peer = NULL; isc_boolean_t useedns; dns_compress_t cctx; isc_boolean_t cleanup_cctx = ISC_FALSE; isc_boolean_t secure_domain; isc_boolean_t connecting = ISC_FALSE; dns_ednsopt_t ednsopts[EDNSOPTS]; unsigned ednsopt = 0; fctx = query->fctx; QTRACE("send"); res = fctx->res; task = res->buckets[fctx->bucketnum].task; address = NULL; if ((query->options & DNS_FETCHOPT_TCP) != 0) { /* * Reserve space for the TCP message length. */ isc_buffer_init(&tcpbuffer, query->data, sizeof(query->data)); isc_buffer_init(&query->buffer, query->data + 2, sizeof(query->data) - 2); buffer = &tcpbuffer; } else { isc_buffer_init(&query->buffer, query->data, sizeof(query->data)); buffer = &query->buffer; } result = dns_message_gettempname(fctx->qmessage, &qname); if (result != ISC_R_SUCCESS) goto cleanup_temps; result = dns_message_gettemprdataset(fctx->qmessage, &qrdataset); if (result != ISC_R_SUCCESS) goto cleanup_temps; /* * Get a query id from the dispatch. */ result = dns_dispatch_addresponse2(query->dispatch, &query->addrinfo->sockaddr, task, resquery_response, query, &query->id, &query->dispentry, res->socketmgr); if (result != ISC_R_SUCCESS) goto cleanup_temps; fctx->qmessage->opcode = dns_opcode_query; /* * Set up question. */ dns_name_init(qname, NULL); dns_name_clone(&fctx->name, qname); dns_rdataset_init(qrdataset); dns_rdataset_makequestion(qrdataset, res->rdclass, fctx->type); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(fctx->qmessage, qname, DNS_SECTION_QUESTION); qname = NULL; qrdataset = NULL; /* * Set RD if the client has requested that we do a recursive query, * or if we're sending to a forwarder. */ if ((query->options & DNS_FETCHOPT_RECURSIVE) != 0 || ISFORWARDER(query->addrinfo)) fctx->qmessage->flags |= DNS_MESSAGEFLAG_RD; /* * Set CD if the client says don't validate or the question is * under a secure entry point. */ if ((query->options & DNS_FETCHOPT_NOVALIDATE) != 0) { fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; } else if (res->view->enablevalidation) { result = dns_view_issecuredomain(res->view, &fctx->name, &secure_domain); if (result != ISC_R_SUCCESS) secure_domain = ISC_FALSE; if (res->view->dlv != NULL) secure_domain = ISC_TRUE; if (secure_domain) fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD; } /* * We don't have to set opcode because it defaults to query. */ fctx->qmessage->id = query->id; /* * Convert the question to wire format. */ result = dns_compress_init(&cctx, -1, fctx->res->mctx); if (result != ISC_R_SUCCESS) goto cleanup_message; cleanup_cctx = ISC_TRUE; result = dns_message_renderbegin(fctx->qmessage, &cctx, &query->buffer); if (result != ISC_R_SUCCESS) goto cleanup_message; result = dns_message_rendersection(fctx->qmessage, DNS_SECTION_QUESTION, 0); if (result != ISC_R_SUCCESS) goto cleanup_message; peer = NULL; isc_netaddr_fromsockaddr(&ipaddr, &query->addrinfo->sockaddr); (void) dns_peerlist_peerbyaddr(fctx->res->view->peers, &ipaddr, &peer); /* * The ADB does not know about servers with "edns no". Check this, * and then inform the ADB for future use. */ if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0 && peer != NULL && dns_peer_getsupportedns(peer, &useedns) == ISC_R_SUCCESS && !useedns) { query->options |= DNS_FETCHOPT_NOEDNS0; dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); } /* Sync NOEDNS0 flag in addrinfo->flags and options now. */ if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) != 0) query->options |= DNS_FETCHOPT_NOEDNS0; /* * Handle timeouts by reducing the UDP response size to 512 bytes * then if that doesn't work disabling EDNS (includes DO) and CD. * * These timeout can be due to: * * broken nameservers that don't respond to EDNS queries. * * broken/misconfigured firewalls and NAT implementations * that don't handle IP fragmentation. * * broken/misconfigured firewalls that don't handle responses * greater than 512 bytes. * * broken/misconfigured firewalls that don't handle EDNS, DO * or CD. * * packet loss / link outage. */ if (fctx->timeout) { if ((triededns512(fctx, &query->addrinfo->sockaddr) || fctx->timeouts >= (MAX_EDNS0_TIMEOUTS * 2)) && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { query->options |= DNS_FETCHOPT_NOEDNS0; fctx->reason = "disabling EDNS"; } else if ((triededns(fctx, &query->addrinfo->sockaddr) || fctx->timeouts >= MAX_EDNS0_TIMEOUTS) && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { query->options |= DNS_FETCHOPT_EDNS512; fctx->reason = "reducing the advertised EDNS UDP " "packet size to 512 octets"; } fctx->timeout = ISC_FALSE; } /* * Use EDNS0, unless the caller doesn't want it, or we know that * the remote server doesn't like it. */ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { if ((query->addrinfo->flags & DNS_FETCHOPT_NOEDNS0) == 0) { unsigned int version = 0; /* Default version. */ unsigned int flags; isc_uint16_t udpsize = res->udpsize; isc_boolean_t reqnsid = res->view->requestnsid; flags = query->addrinfo->flags; if ((flags & DNS_FETCHOPT_EDNSVERSIONSET) != 0) { version = flags & DNS_FETCHOPT_EDNSVERSIONMASK; version >>= DNS_FETCHOPT_EDNSVERSIONSHIFT; } if ((query->options & DNS_FETCHOPT_EDNS512) != 0) udpsize = 512; else if (peer != NULL) (void)dns_peer_getudpsize(peer, &udpsize); /* request NSID for current view or peer? */ if (peer != NULL) (void) dns_peer_getrequestnsid(peer, &reqnsid); if (reqnsid) { INSIST(ednsopt < EDNSOPTS); ednsopts[ednsopt].code = DNS_OPT_NSID; ednsopts[ednsopt].length = 0; ednsopts[ednsopt].value = NULL; ednsopt++; } result = fctx_addopt(fctx->qmessage, version, udpsize, ednsopts, ednsopt); if (reqnsid && result == ISC_R_SUCCESS) { query->options |= DNS_FETCHOPT_WANTNSID; } else if (result != ISC_R_SUCCESS) { /* * We couldn't add the OPT, but we'll press on. * We're not using EDNS0, so set the NOEDNS0 * bit. */ query->options |= DNS_FETCHOPT_NOEDNS0; } } else { /* * We know this server doesn't like EDNS0, so we * won't use it. Set the NOEDNS0 bit since we're * not using EDNS0. */ query->options |= DNS_FETCHOPT_NOEDNS0; } } /* * If we need EDNS0 to do this query and aren't using it, we lose. */ if (NEEDEDNS0(fctx) && (query->options & DNS_FETCHOPT_NOEDNS0) != 0) { result = DNS_R_SERVFAIL; goto cleanup_message; } if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) add_triededns(fctx, &query->addrinfo->sockaddr); if ((query->options & DNS_FETCHOPT_EDNS512) != 0) add_triededns512(fctx, &query->addrinfo->sockaddr); /* * Clear CD if EDNS is not in use. */ if ((query->options & DNS_FETCHOPT_NOEDNS0) != 0) fctx->qmessage->flags &= ~DNS_MESSAGEFLAG_CD; /* * Add TSIG record tailored to the current recipient. */ result = dns_view_getpeertsig(fctx->res->view, &ipaddr, &tsigkey); if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) goto cleanup_message; if (tsigkey != NULL) { result = dns_message_settsigkey(fctx->qmessage, tsigkey); dns_tsigkey_detach(&tsigkey); if (result != ISC_R_SUCCESS) goto cleanup_message; } result = dns_message_rendersection(fctx->qmessage, DNS_SECTION_ADDITIONAL, 0); if (result != ISC_R_SUCCESS) goto cleanup_message; result = dns_message_renderend(fctx->qmessage); if (result != ISC_R_SUCCESS) goto cleanup_message; dns_compress_invalidate(&cctx); cleanup_cctx = ISC_FALSE; if (dns_message_gettsigkey(fctx->qmessage) != NULL) { dns_tsigkey_attach(dns_message_gettsigkey(fctx->qmessage), &query->tsigkey); result = dns_message_getquerytsig(fctx->qmessage, fctx->res->mctx, &query->tsig); if (result != ISC_R_SUCCESS) goto cleanup_message; } /* * If using TCP, write the length of the message at the beginning * of the buffer. */ if ((query->options & DNS_FETCHOPT_TCP) != 0) { isc_buffer_usedregion(&query->buffer, &r); isc_buffer_putuint16(&tcpbuffer, (isc_uint16_t)r.length); isc_buffer_add(&tcpbuffer, r.length); } /* * We're now done with the query message. */ dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER); if (query->exclusivesocket) socket = dns_dispatch_getentrysocket(query->dispentry); else socket = dns_dispatch_getsocket(query->dispatch); /* * Send the query! */ if ((query->options & DNS_FETCHOPT_TCP) == 0) { address = &query->addrinfo->sockaddr; if (query->exclusivesocket) { result = isc_socket_connect(socket, address, task, resquery_udpconnected, query); if (result != ISC_R_SUCCESS) goto cleanup_message; connecting = ISC_TRUE; query->connects++; } } isc_buffer_usedregion(buffer, &r); /* * XXXRTH Make sure we don't send to ourselves! We should probably * prune out these addresses when we get them from the ADB. */ ISC_EVENT_INIT(&query->sendevent, sizeof(query->sendevent), 0, NULL, ISC_SOCKEVENT_SENDDONE, resquery_senddone, query, NULL, NULL, NULL); result = isc_socket_sendto2(socket, &r, task, address, NULL, &query->sendevent, 0); if (result != ISC_R_SUCCESS) { if (connecting) { /* * This query is still connecting. * Mark it as canceled so that it will just be * cleaned up when the connected event is received. * Keep fctx around until the event is processed. */ query->fctx->nqueries++; query->attributes |= RESQUERY_ATTR_CANCELED; } goto cleanup_message; } query->sends++; QTRACE("sent"); return (ISC_R_SUCCESS); cleanup_message: if (cleanup_cctx) dns_compress_invalidate(&cctx); dns_message_reset(fctx->qmessage, DNS_MESSAGE_INTENTRENDER); /* * Stop the dispatcher from listening. */ dns_dispatch_removeresponse(&query->dispentry, NULL); cleanup_temps: if (qname != NULL) dns_message_puttempname(fctx->qmessage, &qname); if (qrdataset != NULL) dns_message_puttemprdataset(fctx->qmessage, &qrdataset); return (result); } static void resquery_connected(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = (isc_socketevent_t *)event; resquery_t *query = event->ev_arg; isc_boolean_t retry = ISC_FALSE; isc_interval_t interval; isc_result_t result; unsigned int attrs; fetchctx_t *fctx; REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); REQUIRE(VALID_QUERY(query)); QTRACE("connected"); UNUSED(task); /* * XXXRTH * * Currently we don't wait for the connect event before retrying * a query. This means that if we get really behind, we may end * up doing extra work! */ query->connects--; fctx = query->fctx; if (RESQUERY_CANCELED(query)) { /* * This query was canceled while the connect() was in * progress. */ isc_socket_detach(&query->tcpsocket); resquery_destroy(&query); } else { switch (sevent->result) { case ISC_R_SUCCESS: /* * Extend the idle timer for TCP. 20 seconds * should be long enough for a TCP connection to be * established, a single DNS request to be sent, * and the response received. */ isc_interval_set(&interval, 20, 0); result = fctx_startidletimer(query->fctx, &interval); if (result != ISC_R_SUCCESS) { fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); fctx_done(fctx, result, __LINE__); break; } /* * We are connected. Create a dispatcher and * send the query. */ attrs = 0; attrs |= DNS_DISPATCHATTR_TCP; attrs |= DNS_DISPATCHATTR_PRIVATE; attrs |= DNS_DISPATCHATTR_CONNECTED; if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == AF_INET) attrs |= DNS_DISPATCHATTR_IPV4; else attrs |= DNS_DISPATCHATTR_IPV6; attrs |= DNS_DISPATCHATTR_MAKEQUERY; result = dns_dispatch_createtcp(query->dispatchmgr, query->tcpsocket, query->fctx->res->taskmgr, 4096, 2, 1, 1, 3, attrs, &query->dispatch); /* * Regardless of whether dns_dispatch_create() * succeeded or not, we don't need our reference * to the socket anymore. */ isc_socket_detach(&query->tcpsocket); if (result == ISC_R_SUCCESS) result = resquery_send(query); if (result != ISC_R_SUCCESS) { fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); fctx_done(fctx, result, __LINE__); } break; case ISC_R_NETUNREACH: case ISC_R_HOSTUNREACH: case ISC_R_CONNREFUSED: case ISC_R_NOPERM: case ISC_R_ADDRNOTAVAIL: case ISC_R_CONNECTIONRESET: /* * No route to remote. */ isc_socket_detach(&query->tcpsocket); fctx_cancelquery(&query, NULL, NULL, ISC_TRUE); retry = ISC_TRUE; break; default: isc_socket_detach(&query->tcpsocket); fctx_cancelquery(&query, NULL, NULL, ISC_FALSE); break; } } isc_event_free(&event); if (retry) { /* * Behave as if the idle timer has expired. For TCP * connections this may not actually reflect the latest timer. */ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); else fctx_try(fctx, ISC_TRUE, ISC_FALSE); } } static void fctx_finddone(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx; dns_adbfind_t *find; dns_resolver_t *res; isc_boolean_t want_try = ISC_FALSE; isc_boolean_t want_done = ISC_FALSE; isc_boolean_t bucket_empty = ISC_FALSE; unsigned int bucketnum; isc_boolean_t destroy = ISC_FALSE; find = event->ev_sender; fctx = event->ev_arg; REQUIRE(VALID_FCTX(fctx)); res = fctx->res; UNUSED(task); FCTXTRACE("finddone"); bucketnum = fctx->bucketnum; LOCK(&res->buckets[bucketnum].lock); INSIST(fctx->pending > 0); fctx->pending--; if (ADDRWAIT(fctx)) { /* * The fetch is waiting for a name to be found. */ INSIST(!SHUTTINGDOWN(fctx)); fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) { want_try = ISC_TRUE; fctx->totalqueries += find->qtotal; } else { fctx->findfail++; if (fctx->pending == 0) { /* * We've got nothing else to wait for and don't * know the answer. There's nothing to do but * fail the fctx. */ want_done = ISC_TRUE; } } } else if (SHUTTINGDOWN(fctx) && fctx->pending == 0 && fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { if (fctx->references == 0) { bucket_empty = fctx_unlink(fctx); destroy = ISC_TRUE; } } UNLOCK(&res->buckets[bucketnum].lock); isc_event_free(&event); dns_adb_destroyfind(&find); if (want_try) fctx_try(fctx, ISC_TRUE, ISC_FALSE); else if (want_done) fctx_done(fctx, ISC_R_FAILURE, __LINE__); else if (destroy) { fctx_destroy(fctx); if (bucket_empty) empty_bucket(res); } } static inline isc_boolean_t bad_server(fetchctx_t *fctx, isc_sockaddr_t *address) { isc_sockaddr_t *sa; for (sa = ISC_LIST_HEAD(fctx->bad); sa != NULL; sa = ISC_LIST_NEXT(sa, link)) { if (isc_sockaddr_equal(sa, address)) return (ISC_TRUE); } return (ISC_FALSE); } static inline isc_boolean_t mark_bad(fetchctx_t *fctx) { dns_adbfind_t *curr; dns_adbaddrinfo_t *addrinfo; isc_boolean_t all_bad = ISC_TRUE; /* * Mark all known bad servers, so we don't try to talk to them * again. */ /* * Mark any bad nameservers. */ for (curr = ISC_LIST_HEAD(fctx->finds); curr != NULL; curr = ISC_LIST_NEXT(curr, publink)) { for (addrinfo = ISC_LIST_HEAD(curr->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (bad_server(fctx, &addrinfo->sockaddr)) addrinfo->flags |= FCTX_ADDRINFO_MARK; else all_bad = ISC_FALSE; } } /* * Mark any bad forwarders. */ for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (bad_server(fctx, &addrinfo->sockaddr)) addrinfo->flags |= FCTX_ADDRINFO_MARK; else all_bad = ISC_FALSE; } /* * Mark any bad alternates. */ for (curr = ISC_LIST_HEAD(fctx->altfinds); curr != NULL; curr = ISC_LIST_NEXT(curr, publink)) { for (addrinfo = ISC_LIST_HEAD(curr->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (bad_server(fctx, &addrinfo->sockaddr)) addrinfo->flags |= FCTX_ADDRINFO_MARK; else all_bad = ISC_FALSE; } } for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (bad_server(fctx, &addrinfo->sockaddr)) addrinfo->flags |= FCTX_ADDRINFO_MARK; else all_bad = ISC_FALSE; } return (all_bad); } static void add_bad(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_result_t reason, badnstype_t badtype) { char namebuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; char classbuf[64]; char typebuf[64]; char code[64]; isc_buffer_t b; isc_sockaddr_t *sa; const char *spc = ""; isc_sockaddr_t *address = &addrinfo->sockaddr; if (reason == DNS_R_LAME) fctx->lamecount++; else { switch (badtype) { case badns_unreachable: fctx->neterr++; break; case badns_response: fctx->badresp++; break; case badns_validation: break; /* counted as 'valfail' */ } } if (bad_server(fctx, address)) { /* * We already know this server is bad. */ return; } FCTXTRACE("add_bad"); sa = isc_mem_get(fctx->mctx, sizeof(*sa)); if (sa == NULL) return; *sa = *address; ISC_LIST_INITANDAPPEND(fctx->bad, sa, link); if (reason == DNS_R_LAME) /* already logged */ return; if (reason == DNS_R_UNEXPECTEDRCODE && fctx->rmessage->rcode == dns_rcode_servfail && ISFORWARDER(addrinfo)) return; if (reason == DNS_R_UNEXPECTEDRCODE) { isc_buffer_init(&b, code, sizeof(code) - 1); dns_rcode_totext(fctx->rmessage->rcode, &b); code[isc_buffer_usedlength(&b)] = '\0'; spc = " "; } else if (reason == DNS_R_UNEXPECTEDOPCODE) { isc_buffer_init(&b, code, sizeof(code) - 1); dns_opcode_totext((dns_opcode_t)fctx->rmessage->opcode, &b); code[isc_buffer_usedlength(&b)] = '\0'; spc = " "; } else { code[0] = '\0'; } dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf)); isc_sockaddr_format(address, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, "error (%s%s%s) resolving '%s/%s/%s': %s", dns_result_totext(reason), spc, code, namebuf, typebuf, classbuf, addrbuf); } /* * Sort addrinfo list by RTT. */ static void sort_adbfind(dns_adbfind_t *find) { dns_adbaddrinfo_t *best, *curr; dns_adbaddrinfolist_t sorted; /* Lame N^2 bubble sort. */ ISC_LIST_INIT(sorted); while (!ISC_LIST_EMPTY(find->list)) { best = ISC_LIST_HEAD(find->list); curr = ISC_LIST_NEXT(best, publink); while (curr != NULL) { if (curr->srtt < best->srtt) best = curr; curr = ISC_LIST_NEXT(curr, publink); } ISC_LIST_UNLINK(find->list, best, publink); ISC_LIST_APPEND(sorted, best, publink); } find->list = sorted; } /* * Sort a list of finds by server RTT. */ static void sort_finds(dns_adbfindlist_t *findlist) { dns_adbfind_t *best, *curr; dns_adbfindlist_t sorted; dns_adbaddrinfo_t *addrinfo, *bestaddrinfo; /* Sort each find's addrinfo list by SRTT. */ for (curr = ISC_LIST_HEAD(*findlist); curr != NULL; curr = ISC_LIST_NEXT(curr, publink)) sort_adbfind(curr); /* Lame N^2 bubble sort. */ ISC_LIST_INIT(sorted); while (!ISC_LIST_EMPTY(*findlist)) { best = ISC_LIST_HEAD(*findlist); bestaddrinfo = ISC_LIST_HEAD(best->list); INSIST(bestaddrinfo != NULL); curr = ISC_LIST_NEXT(best, publink); while (curr != NULL) { addrinfo = ISC_LIST_HEAD(curr->list); INSIST(addrinfo != NULL); if (addrinfo->srtt < bestaddrinfo->srtt) { best = curr; bestaddrinfo = addrinfo; } curr = ISC_LIST_NEXT(curr, publink); } ISC_LIST_UNLINK(*findlist, best, publink); ISC_LIST_APPEND(sorted, best, publink); } *findlist = sorted; } static void findname(fetchctx_t *fctx, dns_name_t *name, in_port_t port, unsigned int options, unsigned int flags, isc_stdtime_t now, isc_boolean_t *need_alternate) { dns_adbaddrinfo_t *ai; dns_adbfind_t *find; dns_resolver_t *res; isc_boolean_t unshared; isc_result_t result; res = fctx->res; unshared = ISC_TF((fctx->options & DNS_FETCHOPT_UNSHARED) != 0); /* * If this name is a subdomain of the query domain, tell * the ADB to start looking using zone/hint data. This keeps us * from getting stuck if the nameserver is beneath the zone cut * and we don't know its address (e.g. because the A record has * expired). */ if (dns_name_issubdomain(name, &fctx->domain)) options |= DNS_ADBFIND_STARTATZONE; options |= DNS_ADBFIND_GLUEOK; options |= DNS_ADBFIND_HINTOK; /* * See what we know about this address. */ find = NULL; result = dns_adb_createfind2(fctx->adb, res->buckets[fctx->bucketnum].task, fctx_finddone, fctx, name, &fctx->name, fctx->type, options, now, NULL, res->view->dstport, fctx->depth + 1, &find); if (result != ISC_R_SUCCESS) { if (result == DNS_R_ALIAS) { /* * XXXRTH Follow the CNAME/DNAME chain? */ dns_adb_destroyfind(&find); fctx->adberr++; } } else if (!ISC_LIST_EMPTY(find->list)) { /* * We have at least some of the addresses for the * name. */ INSIST((find->options & DNS_ADBFIND_WANTEVENT) == 0); if (flags != 0 || port != 0) { for (ai = ISC_LIST_HEAD(find->list); ai != NULL; ai = ISC_LIST_NEXT(ai, publink)) { ai->flags |= flags; if (port != 0) isc_sockaddr_setport(&ai->sockaddr, port); } } if ((flags & FCTX_ADDRINFO_FORWARDER) != 0) ISC_LIST_APPEND(fctx->altfinds, find, publink); else ISC_LIST_APPEND(fctx->finds, find, publink); } else { /* * We don't know any of the addresses for this * name. */ if ((find->options & DNS_ADBFIND_WANTEVENT) != 0) { /* * We're looking for them and will get an * event about it later. */ fctx->pending++; /* * Bootstrap. */ if (need_alternate != NULL && !*need_alternate && unshared && ((res->dispatches4 == NULL && find->result_v6 != DNS_R_NXDOMAIN) || (res->dispatches6 == NULL && find->result_v4 != DNS_R_NXDOMAIN))) *need_alternate = ISC_TRUE; } else { if ((find->options & DNS_ADBFIND_LAMEPRUNED) != 0) fctx->lamecount++; /* cached lame server */ else fctx->adberr++; /* unreachable server, etc. */ /* * If we know there are no addresses for * the family we are using then try to add * an alternative server. */ if (need_alternate != NULL && !*need_alternate && ((res->dispatches4 == NULL && find->result_v6 == DNS_R_NXRRSET) || (res->dispatches6 == NULL && find->result_v4 == DNS_R_NXRRSET))) *need_alternate = ISC_TRUE; dns_adb_destroyfind(&find); } } } static isc_boolean_t isstrictsubdomain(dns_name_t *name1, dns_name_t *name2) { int order; unsigned int nlabels; dns_namereln_t namereln; namereln = dns_name_fullcompare(name1, name2, &order, &nlabels); return (ISC_TF(namereln == dns_namereln_subdomain)); } static isc_result_t fctx_getaddresses(fetchctx_t *fctx, isc_boolean_t badcache) { dns_rdata_t rdata = DNS_RDATA_INIT; isc_result_t result; dns_resolver_t *res; isc_stdtime_t now; unsigned int stdoptions = 0; isc_sockaddr_t *sa; dns_adbaddrinfo_t *ai; isc_boolean_t all_bad; dns_rdata_ns_t ns; isc_boolean_t need_alternate = ISC_FALSE; FCTXTRACE("getaddresses"); /* * Don't pound on remote servers. (Failsafe!) */ fctx->restarts++; if (fctx->restarts > 10) { FCTXTRACE("too many restarts"); return (DNS_R_SERVFAIL); } res = fctx->res; if (fctx->depth > res->maxdepth) { FCTXTRACE("too much NS indirection"); return (DNS_R_SERVFAIL); } /* * Forwarders. */ INSIST(ISC_LIST_EMPTY(fctx->forwaddrs)); INSIST(ISC_LIST_EMPTY(fctx->altaddrs)); /* * If this fctx has forwarders, use them; otherwise use any * selective forwarders specified in the view; otherwise use the * resolver's forwarders (if any). */ sa = ISC_LIST_HEAD(fctx->forwarders); if (sa == NULL) { dns_forwarders_t *forwarders = NULL; dns_name_t *name = &fctx->name; dns_name_t suffix; unsigned int labels; dns_fixedname_t fixed; dns_name_t *domain; /* * DS records are found in the parent server. * Strip label to get the correct forwarder (if any). */ if (dns_rdatatype_atparent(fctx->type) && dns_name_countlabels(name) > 1) { dns_name_init(&suffix, NULL); labels = dns_name_countlabels(name); dns_name_getlabelsequence(name, 1, labels - 1, &suffix); name = &suffix; } dns_fixedname_init(&fixed); domain = dns_fixedname_name(&fixed); result = dns_fwdtable_find2(fctx->res->view->fwdtable, name, domain, &forwarders); if (result == ISC_R_SUCCESS) { sa = ISC_LIST_HEAD(forwarders->addrs); fctx->fwdpolicy = forwarders->fwdpolicy; if (fctx->fwdpolicy == dns_fwdpolicy_only && isstrictsubdomain(domain, &fctx->domain)) { dns_name_free(&fctx->domain, fctx->mctx); dns_name_init(&fctx->domain, NULL); result = dns_name_dup(domain, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) return (result); } } } while (sa != NULL) { if ((isc_sockaddr_pf(sa) == AF_INET && fctx->res->dispatches4 == NULL) || (isc_sockaddr_pf(sa) == AF_INET6 && fctx->res->dispatches6 == NULL)) { sa = ISC_LIST_NEXT(sa, link); continue; } ai = NULL; result = dns_adb_findaddrinfo(fctx->adb, sa, &ai, 0); /* XXXMLG */ if (result == ISC_R_SUCCESS) { dns_adbaddrinfo_t *cur; ai->flags |= FCTX_ADDRINFO_FORWARDER; cur = ISC_LIST_HEAD(fctx->forwaddrs); while (cur != NULL && cur->srtt < ai->srtt) cur = ISC_LIST_NEXT(cur, publink); if (cur != NULL) ISC_LIST_INSERTBEFORE(fctx->forwaddrs, cur, ai, publink); else ISC_LIST_APPEND(fctx->forwaddrs, ai, publink); } sa = ISC_LIST_NEXT(sa, link); } /* * If the forwarding policy is "only", we don't need the addresses * of the nameservers. */ if (fctx->fwdpolicy == dns_fwdpolicy_only) goto out; /* * Normal nameservers. */ stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT; if (fctx->restarts == 1) { /* * To avoid sending out a flood of queries likely to * result in NXRRSET, we suppress fetches for address * families we don't have the first time through, * provided that we have addresses in some family we * can use. * * We don't want to set this option all the time, since * if fctx->restarts > 1, we've clearly been having trouble * with the addresses we had, so getting more could help. */ stdoptions |= DNS_ADBFIND_AVOIDFETCHES; } if (res->dispatches4 != NULL) stdoptions |= DNS_ADBFIND_INET; if (res->dispatches6 != NULL) stdoptions |= DNS_ADBFIND_INET6; isc_stdtime_get(&now); INSIST(ISC_LIST_EMPTY(fctx->finds)); INSIST(ISC_LIST_EMPTY(fctx->altfinds)); for (result = dns_rdataset_first(&fctx->nameservers); result == ISC_R_SUCCESS; result = dns_rdataset_next(&fctx->nameservers)) { dns_rdataset_current(&fctx->nameservers, &rdata); /* * Extract the name from the NS record. */ result = dns_rdata_tostruct(&rdata, &ns, NULL); if (result != ISC_R_SUCCESS) continue; findname(fctx, &ns.name, 0, stdoptions, 0, now, &need_alternate); dns_rdata_reset(&rdata); dns_rdata_freestruct(&ns); } if (result != ISC_R_NOMORE) return (result); /* * Do we need to use 6 to 4? */ if (need_alternate) { int family; alternate_t *a; family = (res->dispatches6 != NULL) ? AF_INET6 : AF_INET; for (a = ISC_LIST_HEAD(fctx->res->alternates); a != NULL; a = ISC_LIST_NEXT(a, link)) { if (!a->isaddress) { findname(fctx, &a->_u._n.name, a->_u._n.port, stdoptions, FCTX_ADDRINFO_FORWARDER, now, NULL); continue; } if (isc_sockaddr_pf(&a->_u.addr) != family) continue; ai = NULL; result = dns_adb_findaddrinfo(fctx->adb, &a->_u.addr, &ai, 0); if (result == ISC_R_SUCCESS) { dns_adbaddrinfo_t *cur; ai->flags |= FCTX_ADDRINFO_FORWARDER; cur = ISC_LIST_HEAD(fctx->altaddrs); while (cur != NULL && cur->srtt < ai->srtt) cur = ISC_LIST_NEXT(cur, publink); if (cur != NULL) ISC_LIST_INSERTBEFORE(fctx->altaddrs, cur, ai, publink); else ISC_LIST_APPEND(fctx->altaddrs, ai, publink); } } } out: /* * Mark all known bad servers. */ all_bad = mark_bad(fctx); /* * How are we doing? */ if (all_bad) { /* * We've got no addresses. */ if (fctx->pending > 0) { /* * We're fetching the addresses, but don't have any * yet. Tell the caller to wait for an answer. */ result = DNS_R_WAIT; } else { isc_time_t expire; isc_interval_t i; /* * We've lost completely. We don't know any * addresses, and the ADB has told us it can't get * them. */ FCTXTRACE("no addresses"); isc_interval_set(&i, DNS_BADCACHE_TTL(fctx), 0); result = isc_time_nowplusinterval(&expire, &i); if (badcache && (fctx->type == dns_rdatatype_dnskey || fctx->type == dns_rdatatype_dlv || fctx->type == dns_rdatatype_ds) && result == ISC_R_SUCCESS) dns_resolver_addbadcache(fctx->res, &fctx->name, fctx->type, &expire); result = ISC_R_FAILURE; } } else { /* * We've found some addresses. We might still be looking * for more addresses. */ sort_finds(&fctx->finds); sort_finds(&fctx->altfinds); result = ISC_R_SUCCESS; } return (result); } static inline void possibly_mark(fetchctx_t *fctx, dns_adbaddrinfo_t *addr) { isc_netaddr_t na; char buf[ISC_NETADDR_FORMATSIZE]; isc_sockaddr_t *sa; isc_boolean_t aborted = ISC_FALSE; isc_boolean_t bogus; dns_acl_t *blackhole; isc_netaddr_t ipaddr; dns_peer_t *peer = NULL; dns_resolver_t *res; const char *msg = NULL; sa = &addr->sockaddr; res = fctx->res; isc_netaddr_fromsockaddr(&ipaddr, sa); blackhole = dns_dispatchmgr_getblackhole(res->dispatchmgr); (void) dns_peerlist_peerbyaddr(res->view->peers, &ipaddr, &peer); if (blackhole != NULL) { int match; if (dns_acl_match(&ipaddr, NULL, blackhole, &res->view->aclenv, &match, NULL) == ISC_R_SUCCESS && match > 0) aborted = ISC_TRUE; } if (peer != NULL && dns_peer_getbogus(peer, &bogus) == ISC_R_SUCCESS && bogus) aborted = ISC_TRUE; if (aborted) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring blackholed / bogus server: "; } else if (isc_sockaddr_ismulticast(sa)) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring multicast address: "; } else if (isc_sockaddr_isexperimental(sa)) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring experimental address: "; } else if (sa->type.sa.sa_family != AF_INET6) { return; } else if (IN6_IS_ADDR_V4MAPPED(&sa->type.sin6.sin6_addr)) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring IPv6 mapped IPV4 address: "; } else if (IN6_IS_ADDR_V4COMPAT(&sa->type.sin6.sin6_addr)) { addr->flags |= FCTX_ADDRINFO_MARK; msg = "ignoring IPv6 compatibility IPV4 address: "; } else return; if (!isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) return; isc_netaddr_fromsockaddr(&na, sa); isc_netaddr_format(&na, buf, sizeof(buf)); FCTXTRACE2(msg, buf); } static inline dns_adbaddrinfo_t * fctx_nextaddress(fetchctx_t *fctx) { dns_adbfind_t *find, *start; dns_adbaddrinfo_t *addrinfo; dns_adbaddrinfo_t *faddrinfo; /* * Return the next untried address, if any. */ /* * Find the first unmarked forwarder (if any). */ for (addrinfo = ISC_LIST_HEAD(fctx->forwaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (!UNMARKED(addrinfo)) continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; fctx->find = NULL; return (addrinfo); } } /* * No forwarders. Move to the next find. */ fctx->attributes |= FCTX_ATTR_TRIEDFIND; find = fctx->find; if (find == NULL) find = ISC_LIST_HEAD(fctx->finds); else { find = ISC_LIST_NEXT(find, publink); if (find == NULL) find = ISC_LIST_HEAD(fctx->finds); } /* * Find the first unmarked addrinfo. */ addrinfo = NULL; if (find != NULL) { start = find; do { for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (!UNMARKED(addrinfo)) continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; break; } } if (addrinfo != NULL) break; find = ISC_LIST_NEXT(find, publink); if (find == NULL) find = ISC_LIST_HEAD(fctx->finds); } while (find != start); } fctx->find = find; if (addrinfo != NULL) return (addrinfo); /* * No nameservers left. Try alternates. */ fctx->attributes |= FCTX_ATTR_TRIEDALT; find = fctx->altfind; if (find == NULL) find = ISC_LIST_HEAD(fctx->altfinds); else { find = ISC_LIST_NEXT(find, publink); if (find == NULL) find = ISC_LIST_HEAD(fctx->altfinds); } /* * Find the first unmarked addrinfo. */ addrinfo = NULL; if (find != NULL) { start = find; do { for (addrinfo = ISC_LIST_HEAD(find->list); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (!UNMARKED(addrinfo)) continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo)) { addrinfo->flags |= FCTX_ADDRINFO_MARK; break; } } if (addrinfo != NULL) break; find = ISC_LIST_NEXT(find, publink); if (find == NULL) find = ISC_LIST_HEAD(fctx->altfinds); } while (find != start); } faddrinfo = addrinfo; /* * See if we have a better alternate server by address. */ for (addrinfo = ISC_LIST_HEAD(fctx->altaddrs); addrinfo != NULL; addrinfo = ISC_LIST_NEXT(addrinfo, publink)) { if (!UNMARKED(addrinfo)) continue; possibly_mark(fctx, addrinfo); if (UNMARKED(addrinfo) && (faddrinfo == NULL || addrinfo->srtt < faddrinfo->srtt)) { if (faddrinfo != NULL) faddrinfo->flags &= ~FCTX_ADDRINFO_MARK; addrinfo->flags |= FCTX_ADDRINFO_MARK; break; } } if (addrinfo == NULL) { addrinfo = faddrinfo; fctx->altfind = find; } return (addrinfo); } static void fctx_try(fetchctx_t *fctx, isc_boolean_t retrying, isc_boolean_t badcache) { isc_result_t result; dns_adbaddrinfo_t *addrinfo; FCTXTRACE("try"); REQUIRE(!ADDRWAIT(fctx)); if (fctx->totalqueries > DEFAULT_MAX_QUERIES) fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); addrinfo = fctx_nextaddress(fctx); if (addrinfo == NULL) { /* * We have no more addresses. Start over. */ fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); fctx_cleanupaltaddrs(fctx); result = fctx_getaddresses(fctx, badcache); if (result == DNS_R_WAIT) { /* * Sleep waiting for addresses. */ FCTXTRACE("addrwait"); fctx->attributes |= FCTX_ATTR_ADDRWAIT; return; } else if (result != ISC_R_SUCCESS) { /* * Something bad happened. */ fctx_done(fctx, result, __LINE__); return; } addrinfo = fctx_nextaddress(fctx); /* * While we may have addresses from the ADB, they * might be bad ones. In this case, return SERVFAIL. */ if (addrinfo == NULL) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } } result = fctx_query(fctx, addrinfo, fctx->options); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); else if (retrying) inc_stats(fctx->res, dns_resstatscounter_retry); } static isc_boolean_t fctx_unlink(fetchctx_t *fctx) { dns_resolver_t *res; unsigned int bucketnum; /* * Caller must be holding the bucket lock. */ REQUIRE(VALID_FCTX(fctx)); REQUIRE(fctx->state == fetchstate_done || fctx->state == fetchstate_init); REQUIRE(ISC_LIST_EMPTY(fctx->events)); REQUIRE(ISC_LIST_EMPTY(fctx->queries)); REQUIRE(ISC_LIST_EMPTY(fctx->finds)); REQUIRE(ISC_LIST_EMPTY(fctx->altfinds)); REQUIRE(fctx->pending == 0); REQUIRE(fctx->references == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); FCTXTRACE("unlink"); res = fctx->res; bucketnum = fctx->bucketnum; ISC_LIST_UNLINK(res->buckets[bucketnum].fctxs, fctx, link); LOCK(&res->nlock); res->nfctx--; UNLOCK(&res->nlock); if (res->buckets[bucketnum].exiting && ISC_LIST_EMPTY(res->buckets[bucketnum].fctxs)) return (ISC_TRUE); return (ISC_FALSE); } static void fctx_destroy(fetchctx_t *fctx) { isc_sockaddr_t *sa, *next_sa; REQUIRE(VALID_FCTX(fctx)); REQUIRE(fctx->state == fetchstate_done || fctx->state == fetchstate_init); REQUIRE(ISC_LIST_EMPTY(fctx->events)); REQUIRE(ISC_LIST_EMPTY(fctx->queries)); REQUIRE(ISC_LIST_EMPTY(fctx->finds)); REQUIRE(ISC_LIST_EMPTY(fctx->altfinds)); REQUIRE(fctx->pending == 0); REQUIRE(fctx->references == 0); REQUIRE(ISC_LIST_EMPTY(fctx->validators)); REQUIRE(!ISC_LINK_LINKED(fctx, link)); FCTXTRACE("destroy"); /* * Free bad. */ for (sa = ISC_LIST_HEAD(fctx->bad); sa != NULL; sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->bad, sa, link); isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } for (sa = ISC_LIST_HEAD(fctx->edns); sa != NULL; sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->edns, sa, link); isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } for (sa = ISC_LIST_HEAD(fctx->edns512); sa != NULL; sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->edns512, sa, link); isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } for (sa = ISC_LIST_HEAD(fctx->bad_edns); sa != NULL; sa = next_sa) { next_sa = ISC_LIST_NEXT(sa, link); ISC_LIST_UNLINK(fctx->bad_edns, sa, link); isc_mem_put(fctx->mctx, sa, sizeof(*sa)); } isc_timer_detach(&fctx->timer); dns_message_destroy(&fctx->rmessage); dns_message_destroy(&fctx->qmessage); if (dns_name_countlabels(&fctx->domain) > 0) dns_name_free(&fctx->domain, fctx->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); dns_name_free(&fctx->name, fctx->mctx); dns_db_detach(&fctx->cache); dns_adb_detach(&fctx->adb); isc_mem_free(fctx->mctx, fctx->info); isc_mem_putanddetach(&fctx->mctx, fctx, sizeof(*fctx)); } /* * Fetch event handlers. */ static void fctx_timeout(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; isc_timerevent_t *tevent = (isc_timerevent_t *)event; resquery_t *query; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); FCTXTRACE("timeout"); inc_stats(fctx->res, dns_resstatscounter_querytimeout); if (event->ev_type == ISC_TIMEREVENT_LIFE) { fctx->reason = NULL; fctx_done(fctx, ISC_R_TIMEDOUT, __LINE__); } else { isc_result_t result; fctx->timeouts++; fctx->timeout = ISC_TRUE; /* * We could cancel the running queries here, or we could let * them keep going. Since we normally use separate sockets for * different queries, we adopt the former approach to reduce * the number of open sockets: cancel the oldest query if it * expired after the query had started (this is usually the * case but is not always so, depending on the task schedule * timing). */ query = ISC_LIST_HEAD(fctx->queries); if (query != NULL && isc_time_compare(&tevent->due, &query->start) >= 0) { fctx_cancelquery(&query, NULL, NULL, ISC_TRUE); } fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; /* * Our timer has triggered. Reestablish the fctx lifetime * timer. */ result = fctx_starttimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); else /* * Keep trying. */ fctx_try(fctx, ISC_TRUE, ISC_FALSE); } isc_event_free(&event); } static void fctx_shutdown(fetchctx_t *fctx) { isc_event_t *cevent; /* * Start the shutdown process for fctx, if it isn't already underway. */ FCTXTRACE("shutdown"); /* * The caller must be holding the appropriate bucket lock. */ if (fctx->want_shutdown) return; fctx->want_shutdown = ISC_TRUE; /* * Unless we're still initializing (in which case the * control event is still outstanding), we need to post * the control event to tell the fetch we want it to * exit. */ if (fctx->state != fetchstate_init) { cevent = &fctx->control_event; isc_task_send(fctx->res->buckets[fctx->bucketnum].task, &cevent); } } static void fctx_doshutdown(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res; unsigned int bucketnum; dns_validator_t *validator; isc_boolean_t destroy = ISC_FALSE; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); res = fctx->res; bucketnum = fctx->bucketnum; FCTXTRACE("doshutdown"); /* * An fctx that is shutting down is no longer in ADDRWAIT mode. */ fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; /* * Cancel all pending validators. Note that this must be done * without the bucket lock held, since that could cause deadlock. */ validator = ISC_LIST_HEAD(fctx->validators); while (validator != NULL) { dns_validator_cancel(validator); validator = ISC_LIST_NEXT(validator, link); } if (fctx->nsfetch != NULL) dns_resolver_cancelfetch(fctx->nsfetch); /* * Shut down anything that is still running on behalf of this * fetch. To avoid deadlock with the ADB, we must do this * before we lock the bucket lock. */ fctx_stopeverything(fctx, ISC_FALSE); LOCK(&res->buckets[bucketnum].lock); fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN; INSIST(fctx->state == fetchstate_active || fctx->state == fetchstate_done); INSIST(fctx->want_shutdown); if (fctx->state != fetchstate_done) { fctx->state = fetchstate_done; fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__); } if (fctx->references == 0 && fctx->pending == 0 && fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators)) { bucket_empty = fctx_unlink(fctx); destroy = ISC_TRUE; } UNLOCK(&res->buckets[bucketnum].lock); if (destroy) { fctx_destroy(fctx); if (bucket_empty) empty_bucket(res); } } static void fctx_start(isc_task_t *task, isc_event_t *event) { fetchctx_t *fctx = event->ev_arg; isc_boolean_t done = ISC_FALSE, bucket_empty = ISC_FALSE; dns_resolver_t *res; unsigned int bucketnum; isc_boolean_t destroy = ISC_FALSE; REQUIRE(VALID_FCTX(fctx)); UNUSED(task); res = fctx->res; bucketnum = fctx->bucketnum; FCTXTRACE("start"); LOCK(&res->buckets[bucketnum].lock); INSIST(fctx->state == fetchstate_init); if (fctx->want_shutdown) { /* * We haven't started this fctx yet, and we've been requested * to shut it down. */ fctx->attributes |= FCTX_ATTR_SHUTTINGDOWN; fctx->state = fetchstate_done; fctx_sendevents(fctx, ISC_R_CANCELED, __LINE__); /* * Since we haven't started, we INSIST that we have no * pending ADB finds and no pending validations. */ INSIST(fctx->pending == 0); INSIST(fctx->nqueries == 0); INSIST(ISC_LIST_EMPTY(fctx->validators)); if (fctx->references == 0) { /* * It's now safe to destroy this fctx. */ bucket_empty = fctx_unlink(fctx); destroy = ISC_TRUE; } done = ISC_TRUE; } else { /* * Normal fctx startup. */ fctx->state = fetchstate_active; fctx->totalqueries = 0; /* * Reset the control event for later use in shutting down * the fctx. */ ISC_EVENT_INIT(event, sizeof(*event), 0, NULL, DNS_EVENT_FETCHCONTROL, fctx_doshutdown, fctx, NULL, NULL, NULL); } UNLOCK(&res->buckets[bucketnum].lock); if (!done) { isc_result_t result; INSIST(!destroy); /* * All is well. Start working on the fetch. */ result = fctx_starttimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); else fctx_try(fctx, ISC_FALSE, ISC_FALSE); } else if (destroy) { fctx_destroy(fctx); if (bucket_empty) empty_bucket(res); } } /* * Fetch Creation, Joining, and Cancelation. */ static inline isc_result_t fctx_join(fetchctx_t *fctx, isc_task_t *task, isc_sockaddr_t *client, dns_messageid_t id, isc_taskaction_t action, void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_fetch_t *fetch) { isc_task_t *clone; dns_fetchevent_t *event; FCTXTRACE("join"); /* * We store the task we're going to send this event to in the * sender field. We'll make the fetch the sender when we actually * send the event. */ clone = NULL; isc_task_attach(task, &clone); event = (dns_fetchevent_t *) isc_event_allocate(fctx->res->mctx, clone, DNS_EVENT_FETCHDONE, action, arg, sizeof(*event)); if (event == NULL) { isc_task_detach(&clone); return (ISC_R_NOMEMORY); } event->result = DNS_R_SERVFAIL; event->qtype = fctx->type; event->db = NULL; event->node = NULL; event->rdataset = rdataset; event->sigrdataset = sigrdataset; event->fetch = fetch; event->client = client; event->id = id; event->qtotal = 0; dns_fixedname_init(&event->foundname); /* * Make sure that we can store the sigrdataset in the * first event if it is needed by any of the events. */ if (event->sigrdataset != NULL) ISC_LIST_PREPEND(fctx->events, event, ev_link); else ISC_LIST_APPEND(fctx->events, event, ev_link); fctx->references++; fctx->client = client; fetch->magic = DNS_FETCH_MAGIC; fetch->private = fctx; return (ISC_R_SUCCESS); } static inline void log_ns_ttl(fetchctx_t *fctx, const char *where) { char namebuf[DNS_NAME_FORMATSIZE]; char domainbuf[DNS_NAME_FORMATSIZE]; dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10), "log_ns_ttl: fctx %p: %s: %s (in '%s'?): %u %u", fctx, where, namebuf, domainbuf, fctx->ns_ttl_ok, fctx->ns_ttl); } static isc_result_t fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_name_t *domain, dns_rdataset_t *nameservers, unsigned int options, unsigned int bucketnum, unsigned int depth, fetchctx_t **fctxp) { fetchctx_t *fctx; isc_result_t result; isc_result_t iresult; isc_interval_t interval; dns_fixedname_t fixed; unsigned int findoptions = 0; char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; dns_name_t suffix; isc_mem_t *mctx; /* * Caller must be holding the lock for bucket number 'bucketnum'. */ REQUIRE(fctxp != NULL && *fctxp == NULL); mctx = res->buckets[bucketnum].mctx; fctx = isc_mem_get(mctx, sizeof(*fctx)); if (fctx == NULL) return (ISC_R_NOMEMORY); dns_name_format(name, buf, sizeof(buf)); dns_rdatatype_format(type, typebuf, sizeof(typebuf)); strcat(buf, "/"); /* checked */ strcat(buf, typebuf); /* checked */ fctx->info = isc_mem_strdup(mctx, buf); if (fctx->info == NULL) { result = ISC_R_NOMEMORY; goto cleanup_fetch; } FCTXTRACE("create"); dns_name_init(&fctx->name, NULL); result = dns_name_dup(name, mctx, &fctx->name); if (result != ISC_R_SUCCESS) goto cleanup_info; dns_name_init(&fctx->domain, NULL); dns_rdataset_init(&fctx->nameservers); fctx->type = type; fctx->options = options; /* * Note! We do not attach to the task. We are relying on the * resolver to ensure that this task doesn't go away while we are * using it. */ fctx->res = res; fctx->references = 0; fctx->bucketnum = bucketnum; fctx->state = fetchstate_init; fctx->want_shutdown = ISC_FALSE; fctx->cloned = ISC_FALSE; fctx->depth = depth; ISC_LIST_INIT(fctx->queries); ISC_LIST_INIT(fctx->finds); ISC_LIST_INIT(fctx->altfinds); ISC_LIST_INIT(fctx->forwaddrs); ISC_LIST_INIT(fctx->altaddrs); ISC_LIST_INIT(fctx->forwarders); fctx->fwdpolicy = dns_fwdpolicy_none; ISC_LIST_INIT(fctx->bad); ISC_LIST_INIT(fctx->edns); ISC_LIST_INIT(fctx->edns512); ISC_LIST_INIT(fctx->bad_edns); ISC_LIST_INIT(fctx->validators); fctx->validator = NULL; fctx->find = NULL; fctx->altfind = NULL; fctx->pending = 0; fctx->restarts = 0; fctx->querysent = 0; fctx->totalqueries = 0; fctx->referrals = 0; TIME_NOW(&fctx->start); fctx->timeouts = 0; fctx->lamecount = 0; fctx->adberr = 0; fctx->neterr = 0; fctx->badresp = 0; fctx->findfail = 0; fctx->valfail = 0; fctx->result = ISC_R_FAILURE; fctx->vresult = ISC_R_SUCCESS; fctx->exitline = -1; /* sentinel */ fctx->logged = ISC_FALSE; fctx->attributes = 0; fctx->spilled = ISC_FALSE; fctx->nqueries = 0; fctx->reason = NULL; fctx->rand_buf = 0; fctx->rand_bits = 0; fctx->timeout = ISC_FALSE; fctx->addrinfo = NULL; fctx->client = NULL; fctx->ns_ttl = 0; fctx->ns_ttl_ok = ISC_FALSE; dns_name_init(&fctx->nsname, NULL); fctx->nsfetch = NULL; dns_rdataset_init(&fctx->nsrrset); if (domain == NULL) { dns_forwarders_t *forwarders = NULL; unsigned int labels; dns_name_t *fwdname = name; /* * DS records are found in the parent server. * Strip label to get the correct forwarder (if any). */ if (dns_rdatatype_atparent(fctx->type) && dns_name_countlabels(name) > 1) { dns_name_init(&suffix, NULL); labels = dns_name_countlabels(name); dns_name_getlabelsequence(name, 1, labels - 1, &suffix); fwdname = &suffix; } dns_fixedname_init(&fixed); domain = dns_fixedname_name(&fixed); result = dns_fwdtable_find2(fctx->res->view->fwdtable, fwdname, domain, &forwarders); if (result == ISC_R_SUCCESS) fctx->fwdpolicy = forwarders->fwdpolicy; if (fctx->fwdpolicy != dns_fwdpolicy_only) { /* * The caller didn't supply a query domain and * nameservers, and we're not in forward-only mode, * so find the best nameservers to use. */ if (dns_rdatatype_atparent(fctx->type)) findoptions |= DNS_DBFIND_NOEXACT; result = dns_view_findzonecut(res->view, fwdname, domain, 0, findoptions, ISC_TRUE, &fctx->nameservers, NULL); if (result != ISC_R_SUCCESS) goto cleanup_name; result = dns_name_dup(domain, mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { dns_rdataset_disassociate(&fctx->nameservers); goto cleanup_name; } fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = ISC_TRUE; } else { /* * We're in forward-only mode. Set the query domain. */ result = dns_name_dup(domain, mctx, &fctx->domain); if (result != ISC_R_SUCCESS) goto cleanup_name; } } else { result = dns_name_dup(domain, mctx, &fctx->domain); if (result != ISC_R_SUCCESS) goto cleanup_name; dns_rdataset_clone(nameservers, &fctx->nameservers); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = ISC_TRUE; } log_ns_ttl(fctx, "fctx_create"); INSIST(dns_name_issubdomain(&fctx->name, &fctx->domain)); fctx->qmessage = NULL; result = dns_message_create(mctx, DNS_MESSAGE_INTENTRENDER, &fctx->qmessage); if (result != ISC_R_SUCCESS) goto cleanup_domain; fctx->rmessage = NULL; result = dns_message_create(mctx, DNS_MESSAGE_INTENTPARSE, &fctx->rmessage); if (result != ISC_R_SUCCESS) goto cleanup_qmessage; /* * Compute an expiration time for the entire fetch. */ isc_interval_set(&interval, res->query_timeout, 0); iresult = isc_time_nowplusinterval(&fctx->expires, &interval); if (iresult != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_time_nowplusinterval: %s", isc_result_totext(iresult)); result = ISC_R_UNEXPECTED; goto cleanup_rmessage; } /* * Default retry interval initialization. We set the interval now * mostly so it won't be uninitialized. It will be set to the * correct value before a query is issued. */ isc_interval_set(&fctx->interval, 2, 0); /* * Create an inactive timer. It will be made active when the fetch * is actually started. */ fctx->timer = NULL; iresult = isc_timer_create(res->timermgr, isc_timertype_inactive, NULL, NULL, res->buckets[bucketnum].task, fctx_timeout, fctx, &fctx->timer); if (iresult != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_timer_create: %s", isc_result_totext(iresult)); result = ISC_R_UNEXPECTED; goto cleanup_rmessage; } /* * Attach to the view's cache and adb. */ fctx->cache = NULL; dns_db_attach(res->view->cachedb, &fctx->cache); fctx->adb = NULL; dns_adb_attach(res->view->adb, &fctx->adb); fctx->mctx = NULL; isc_mem_attach(mctx, &fctx->mctx); ISC_LIST_INIT(fctx->events); ISC_LINK_INIT(fctx, link); fctx->magic = FCTX_MAGIC; ISC_LIST_APPEND(res->buckets[bucketnum].fctxs, fctx, link); LOCK(&res->nlock); res->nfctx++; UNLOCK(&res->nlock); *fctxp = fctx; return (ISC_R_SUCCESS); cleanup_rmessage: dns_message_destroy(&fctx->rmessage); cleanup_qmessage: dns_message_destroy(&fctx->qmessage); cleanup_domain: if (dns_name_countlabels(&fctx->domain) > 0) dns_name_free(&fctx->domain, mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); cleanup_name: dns_name_free(&fctx->name, mctx); cleanup_info: isc_mem_free(mctx, fctx->info); cleanup_fetch: isc_mem_put(mctx, fctx, sizeof(*fctx)); return (result); } /* * Handle Responses */ static inline isc_boolean_t is_lame(fetchctx_t *fctx) { dns_message_t *message = fctx->rmessage; dns_name_t *name; dns_rdataset_t *rdataset; isc_result_t result; if (message->rcode != dns_rcode_noerror && message->rcode != dns_rcode_nxdomain) return (ISC_FALSE); if (message->counts[DNS_SECTION_ANSWER] != 0) return (ISC_FALSE); if (message->counts[DNS_SECTION_AUTHORITY] == 0) return (ISC_FALSE); result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { dns_namereln_t namereln; int order; unsigned int labels; if (rdataset->type != dns_rdatatype_ns) continue; namereln = dns_name_fullcompare(name, &fctx->domain, &order, &labels); if (namereln == dns_namereln_equal && (message->flags & DNS_MESSAGEFLAG_AA) != 0) return (ISC_FALSE); if (namereln == dns_namereln_subdomain) return (ISC_FALSE); return (ISC_TRUE); } result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); } return (ISC_FALSE); } static inline void log_lame(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo) { char namebuf[DNS_NAME_FORMATSIZE]; char domainbuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, "lame server resolving '%s' (in '%s'?): %s", namebuf, domainbuf, addrbuf); } static inline void log_formerr(fetchctx_t *fctx, const char *format, ...) { char nsbuf[ISC_SOCKADDR_FORMATSIZE]; char clbuf[ISC_SOCKADDR_FORMATSIZE]; const char *clmsg = ""; char msgbuf[2048]; va_list args; va_start(args, format); vsnprintf(msgbuf, sizeof(msgbuf), format, args); va_end(args); isc_sockaddr_format(&fctx->addrinfo->sockaddr, nsbuf, sizeof(nsbuf)); if (fctx->client != NULL) { clmsg = " for client "; isc_sockaddr_format(fctx->client, clbuf, sizeof(clbuf)); } else { clbuf[0] = '\0'; } isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, "DNS format error from %s resolving %s%s%s: %s", nsbuf, fctx->info, clmsg, clbuf, msgbuf); } static inline isc_result_t same_question(fetchctx_t *fctx) { isc_result_t result; dns_message_t *message = fctx->rmessage; dns_name_t *name; dns_rdataset_t *rdataset; /* * Caller must be holding the fctx lock. */ /* * XXXRTH Currently we support only one question. */ if (message->counts[DNS_SECTION_QUESTION] != 1) { log_formerr(fctx, "too many questions"); return (DNS_R_FORMERR); } result = dns_message_firstname(message, DNS_SECTION_QUESTION); if (result != ISC_R_SUCCESS) return (result); name = NULL; dns_message_currentname(message, DNS_SECTION_QUESTION, &name); rdataset = ISC_LIST_HEAD(name->list); INSIST(rdataset != NULL); INSIST(ISC_LIST_NEXT(rdataset, link) == NULL); if (fctx->type != rdataset->type || fctx->res->rdclass != rdataset->rdclass || !dns_name_equal(&fctx->name, name)) { char namebuf[DNS_NAME_FORMATSIZE]; char class[DNS_RDATACLASS_FORMATSIZE]; char type[DNS_RDATATYPE_FORMATSIZE]; dns_name_format(name, namebuf, sizeof(namebuf)); dns_rdataclass_format(rdataset->rdclass, class, sizeof(class)); dns_rdatatype_format(rdataset->type, type, sizeof(type)); log_formerr(fctx, "question section mismatch: got %s/%s/%s", namebuf, class, type); return (DNS_R_FORMERR); } return (ISC_R_SUCCESS); } static void clone_results(fetchctx_t *fctx) { dns_fetchevent_t *event, *hevent; isc_result_t result; dns_name_t *name, *hname; FCTXTRACE("clone_results"); /* * Set up any other events to have the same data as the first * event. * * Caller must be holding the appropriate lock. */ fctx->cloned = ISC_TRUE; hevent = ISC_LIST_HEAD(fctx->events); if (hevent == NULL) return; hname = dns_fixedname_name(&hevent->foundname); for (event = ISC_LIST_NEXT(hevent, ev_link); event != NULL; event = ISC_LIST_NEXT(event, ev_link)) { name = dns_fixedname_name(&event->foundname); result = dns_name_copy(hname, name, NULL); if (result != ISC_R_SUCCESS) event->result = result; else event->result = hevent->result; dns_db_attach(hevent->db, &event->db); dns_db_attachnode(hevent->db, hevent->node, &event->node); INSIST(hevent->rdataset != NULL); INSIST(event->rdataset != NULL); if (dns_rdataset_isassociated(hevent->rdataset)) dns_rdataset_clone(hevent->rdataset, event->rdataset); INSIST(! (hevent->sigrdataset == NULL && event->sigrdataset != NULL)); if (hevent->sigrdataset != NULL && dns_rdataset_isassociated(hevent->sigrdataset) && event->sigrdataset != NULL) dns_rdataset_clone(hevent->sigrdataset, event->sigrdataset); } } #define CACHE(r) (((r)->attributes & DNS_RDATASETATTR_CACHE) != 0) #define ANSWER(r) (((r)->attributes & DNS_RDATASETATTR_ANSWER) != 0) #define ANSWERSIG(r) (((r)->attributes & DNS_RDATASETATTR_ANSWERSIG) != 0) #define EXTERNAL(r) (((r)->attributes & DNS_RDATASETATTR_EXTERNAL) != 0) #define CHAINING(r) (((r)->attributes & DNS_RDATASETATTR_CHAINING) != 0) #define CHASE(r) (((r)->attributes & DNS_RDATASETATTR_CHASE) != 0) #define CHECKNAMES(r) (((r)->attributes & DNS_RDATASETATTR_CHECKNAMES) != 0) /* * Destroy '*fctx' if it is ready to be destroyed (i.e., if it has * no references and is no longer waiting for any events). * * Requires: * '*fctx' is shutting down. * * Returns: * true if the resolver is exiting and this is the last fctx in the bucket. */ static isc_boolean_t maybe_destroy(fetchctx_t *fctx, isc_boolean_t locked) { unsigned int bucketnum; isc_boolean_t bucket_empty = ISC_FALSE; dns_resolver_t *res = fctx->res; dns_validator_t *validator, *next_validator; isc_boolean_t destroy = ISC_FALSE; REQUIRE(SHUTTINGDOWN(fctx)); bucketnum = fctx->bucketnum; if (!locked) LOCK(&res->buckets[bucketnum].lock); if (fctx->pending != 0 || fctx->nqueries != 0) goto unlock; for (validator = ISC_LIST_HEAD(fctx->validators); validator != NULL; validator = next_validator) { next_validator = ISC_LIST_NEXT(validator, link); dns_validator_cancel(validator); } if (fctx->references == 0 && ISC_LIST_EMPTY(fctx->validators)) { bucket_empty = fctx_unlink(fctx); destroy = ISC_TRUE; } unlock: if (!locked) UNLOCK(&res->buckets[bucketnum].lock); if (destroy) fctx_destroy(fctx); return (bucket_empty); } /* * The validator has finished. */ static void validated(isc_task_t *task, isc_event_t *event) { dns_adbaddrinfo_t *addrinfo; dns_dbnode_t *node = NULL; dns_dbnode_t *nsnode = NULL; dns_fetchevent_t *hevent; dns_name_t *name; dns_rdataset_t *ardataset = NULL; dns_rdataset_t *asigrdataset = NULL; dns_rdataset_t *rdataset; dns_rdataset_t *sigrdataset; dns_resolver_t *res; dns_valarg_t *valarg; dns_validatorevent_t *vevent; fetchctx_t *fctx; isc_boolean_t chaining; isc_boolean_t negative; isc_boolean_t sentresponse; isc_result_t eresult = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS; isc_stdtime_t now; isc_uint32_t ttl; UNUSED(task); /* for now */ REQUIRE(event->ev_type == DNS_EVENT_VALIDATORDONE); valarg = event->ev_arg; fctx = valarg->fctx; res = fctx->res; addrinfo = valarg->addrinfo; REQUIRE(VALID_FCTX(fctx)); REQUIRE(!ISC_LIST_EMPTY(fctx->validators)); vevent = (dns_validatorevent_t *)event; fctx->vresult = vevent->result; FCTXTRACE("received validation completion event"); LOCK(&res->buckets[fctx->bucketnum].lock); ISC_LIST_UNLINK(fctx->validators, vevent->validator, link); fctx->validator = NULL; /* * Destroy the validator early so that we can * destroy the fctx if necessary. */ dns_validator_destroy(&vevent->validator); isc_mem_put(fctx->mctx, valarg, sizeof(*valarg)); negative = ISC_TF(vevent->rdataset == NULL); sentresponse = ISC_TF((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0); /* * If shutting down, ignore the results. Check to see if we're * done waiting for validator completions and ADB pending events; if * so, destroy the fctx. */ if (SHUTTINGDOWN(fctx) && !sentresponse) { isc_uint32_t bucketnum = fctx->bucketnum; isc_boolean_t bucket_empty; bucket_empty = maybe_destroy(fctx, ISC_TRUE); UNLOCK(&res->buckets[bucketnum].lock); if (bucket_empty) empty_bucket(res); goto cleanup_event; } isc_stdtime_get(&now); /* * If chaining, we need to make sure that the right result code is * returned, and that the rdatasets are bound. */ if (vevent->result == ISC_R_SUCCESS && !negative && vevent->rdataset != NULL && CHAINING(vevent->rdataset)) { if (vevent->rdataset->type == dns_rdatatype_cname) eresult = DNS_R_CNAME; else { INSIST(vevent->rdataset->type == dns_rdatatype_dname); eresult = DNS_R_DNAME; } chaining = ISC_TRUE; } else chaining = ISC_FALSE; /* * Either we're not shutting down, or we are shutting down but want * to cache the result anyway (if this was a validation started by * a query with cd set) */ hevent = ISC_LIST_HEAD(fctx->events); if (hevent != NULL) { if (!negative && !chaining && (fctx->type == dns_rdatatype_any || fctx->type == dns_rdatatype_rrsig || fctx->type == dns_rdatatype_sig)) { /* * Don't bind rdatasets; the caller * will iterate the node. */ } else { ardataset = hevent->rdataset; asigrdataset = hevent->sigrdataset; } } if (vevent->result != ISC_R_SUCCESS) { FCTXTRACE("validation failed"); inc_stats(res, dns_resstatscounter_valfail); fctx->valfail++; fctx->vresult = vevent->result; if (fctx->vresult != DNS_R_BROKENCHAIN) { result = ISC_R_NOTFOUND; if (vevent->rdataset != NULL) result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node); if (result == ISC_R_SUCCESS) (void)dns_db_deleterdataset(fctx->cache, node, NULL, vevent->type, 0); if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL) (void)dns_db_deleterdataset(fctx->cache, node, NULL, dns_rdatatype_rrsig, vevent->type); if (result == ISC_R_SUCCESS) dns_db_detachnode(fctx->cache, &node); } if (fctx->vresult == DNS_R_BROKENCHAIN && !negative) { /* * Cache the data as pending for later validation. */ result = ISC_R_NOTFOUND; if (vevent->rdataset != NULL) result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node); if (result == ISC_R_SUCCESS) { (void)dns_db_addrdataset(fctx->cache, node, NULL, now, vevent->rdataset, 0, NULL); } if (result == ISC_R_SUCCESS && vevent->sigrdataset != NULL) (void)dns_db_addrdataset(fctx->cache, node, NULL, now, vevent->sigrdataset, 0, NULL); if (result == ISC_R_SUCCESS) dns_db_detachnode(fctx->cache, &node); } result = fctx->vresult; add_bad(fctx, addrinfo, result, badns_validation); isc_event_free(&event); UNLOCK(&res->buckets[fctx->bucketnum].lock); INSIST(fctx->validator == NULL); fctx->validator = ISC_LIST_HEAD(fctx->validators); if (fctx->validator != NULL) dns_validator_send(fctx->validator); else if (sentresponse) fctx_done(fctx, result, __LINE__); /* Locks bucket. */ else if (result == DNS_R_BROKENCHAIN) { isc_result_t tresult; isc_time_t expire; isc_interval_t i; isc_interval_set(&i, DNS_BADCACHE_TTL(fctx), 0); tresult = isc_time_nowplusinterval(&expire, &i); if (negative && (fctx->type == dns_rdatatype_dnskey || fctx->type == dns_rdatatype_dlv || fctx->type == dns_rdatatype_ds) && tresult == ISC_R_SUCCESS) dns_resolver_addbadcache(res, &fctx->name, fctx->type, &expire); fctx_done(fctx, result, __LINE__); /* Locks bucket. */ } else fctx_try(fctx, ISC_TRUE, ISC_TRUE); /* Locks bucket. */ return; } if (negative) { dns_rdatatype_t covers; FCTXTRACE("nonexistence validation OK"); inc_stats(res, dns_resstatscounter_valnegsuccess); if (fctx->rmessage->rcode == dns_rcode_nxdomain) covers = dns_rdatatype_any; else covers = fctx->type; result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node); if (result != ISC_R_SUCCESS) goto noanswer_response; /* * If we are asking for a SOA record set the cache time * to zero to facilitate locating the containing zone of * a arbitrary zone. */ ttl = res->view->maxncachettl; if (fctx->type == dns_rdatatype_soa && covers == dns_rdatatype_any && res->zero_no_soa_ttl) ttl = 0; result = ncache_adderesult(fctx->rmessage, fctx->cache, node, covers, now, ttl, vevent->optout, vevent->secure, ardataset, &eresult); if (result != ISC_R_SUCCESS) goto noanswer_response; goto answer_response; } else inc_stats(res, dns_resstatscounter_valsuccess); FCTXTRACE("validation OK"); if (vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF] != NULL) { result = dns_rdataset_addnoqname(vevent->rdataset, vevent->proofs[DNS_VALIDATOR_NOQNAMEPROOF]); RUNTIME_CHECK(result == ISC_R_SUCCESS); INSIST(vevent->sigrdataset != NULL); vevent->sigrdataset->ttl = vevent->rdataset->ttl; if (vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER] != NULL) { result = dns_rdataset_addclosest(vevent->rdataset, vevent->proofs[DNS_VALIDATOR_CLOSESTENCLOSER]); RUNTIME_CHECK(result == ISC_R_SUCCESS); } } else if (vevent->rdataset->trust == dns_trust_answer && vevent->rdataset->type != dns_rdatatype_rrsig) { isc_result_t tresult; dns_name_t *noqname = NULL; tresult = findnoqname(fctx, vevent->name, vevent->rdataset->type, &noqname); if (tresult == ISC_R_SUCCESS && noqname != NULL) { tresult = dns_rdataset_addnoqname(vevent->rdataset, noqname); RUNTIME_CHECK(tresult == ISC_R_SUCCESS); } } /* * The data was already cached as pending data. * Re-cache it as secure and bind the cached * rdatasets to the first event on the fetch * event list. */ result = dns_db_findnode(fctx->cache, vevent->name, ISC_TRUE, &node); if (result != ISC_R_SUCCESS) goto noanswer_response; result = dns_db_addrdataset(fctx->cache, node, NULL, now, vevent->rdataset, 0, ardataset); if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) goto noanswer_response; if (ardataset != NULL && NEGATIVE(ardataset)) { if (NXDOMAIN(ardataset)) eresult = DNS_R_NCACHENXDOMAIN; else eresult = DNS_R_NCACHENXRRSET; } else if (vevent->sigrdataset != NULL) { result = dns_db_addrdataset(fctx->cache, node, NULL, now, vevent->sigrdataset, 0, asigrdataset); if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) goto noanswer_response; } if (sentresponse) { isc_boolean_t bucket_empty = ISC_FALSE; /* * If we only deferred the destroy because we wanted to cache * the data, destroy now. */ dns_db_detachnode(fctx->cache, &node); if (SHUTTINGDOWN(fctx)) bucket_empty = maybe_destroy(fctx, ISC_TRUE); UNLOCK(&res->buckets[fctx->bucketnum].lock); if (bucket_empty) empty_bucket(res); goto cleanup_event; } if (!ISC_LIST_EMPTY(fctx->validators)) { INSIST(!negative); INSIST(fctx->type == dns_rdatatype_any || fctx->type == dns_rdatatype_rrsig || fctx->type == dns_rdatatype_sig); /* * Don't send a response yet - we have * more rdatasets that still need to * be validated. */ dns_db_detachnode(fctx->cache, &node); UNLOCK(&res->buckets[fctx->bucketnum].lock); dns_validator_send(ISC_LIST_HEAD(fctx->validators)); goto cleanup_event; } answer_response: /* * Cache any NS/NSEC records that happened to be validated. */ result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(fctx->rmessage, DNS_SECTION_AUTHORITY, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if ((rdataset->type != dns_rdatatype_ns && rdataset->type != dns_rdatatype_nsec) || rdataset->trust != dns_trust_secure) continue; for (sigrdataset = ISC_LIST_HEAD(name->list); sigrdataset != NULL; sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) { if (sigrdataset->type != dns_rdatatype_rrsig || sigrdataset->covers != rdataset->type) continue; break; } if (sigrdataset == NULL || sigrdataset->trust != dns_trust_secure) continue; result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &nsnode); if (result != ISC_R_SUCCESS) continue; result = dns_db_addrdataset(fctx->cache, nsnode, NULL, now, rdataset, 0, NULL); if (result == ISC_R_SUCCESS) result = dns_db_addrdataset(fctx->cache, nsnode, NULL, now, sigrdataset, 0, NULL); dns_db_detachnode(fctx->cache, &nsnode); if (result != ISC_R_SUCCESS) continue; } result = dns_message_nextname(fctx->rmessage, DNS_SECTION_AUTHORITY); } result = ISC_R_SUCCESS; /* * Respond with an answer, positive or negative, * as opposed to an error. 'node' must be non-NULL. */ fctx->attributes |= FCTX_ATTR_HAVEANSWER; if (hevent != NULL) { /* * Negative results must be indicated in event->result. */ if (dns_rdataset_isassociated(hevent->rdataset) && NEGATIVE(hevent->rdataset)) { INSIST(eresult == DNS_R_NCACHENXDOMAIN || eresult == DNS_R_NCACHENXRRSET); } hevent->result = eresult; RUNTIME_CHECK(dns_name_copy(vevent->name, dns_fixedname_name(&hevent->foundname), NULL) == ISC_R_SUCCESS); dns_db_attach(fctx->cache, &hevent->db); dns_db_transfernode(fctx->cache, &node, &hevent->node); clone_results(fctx); } noanswer_response: if (node != NULL) dns_db_detachnode(fctx->cache, &node); UNLOCK(&res->buckets[fctx->bucketnum].lock); fctx_done(fctx, result, __LINE__); /* Locks bucket. */ cleanup_event: INSIST(node == NULL); isc_event_free(&event); } static void fctx_log(void *arg, int level, const char *fmt, ...) { char msgbuf[2048]; va_list args; fetchctx_t *fctx = arg; va_start(args, fmt); vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); va_end(args); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, level, "fctx %p(%s): %s", fctx, fctx->info, msgbuf); } static inline isc_result_t findnoqname(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type, dns_name_t **noqnamep) { dns_rdataset_t *nrdataset, *next, *sigrdataset; dns_rdata_rrsig_t rrsig; isc_result_t result; unsigned int labels; dns_section_t section; dns_name_t *zonename; dns_fixedname_t fzonename; dns_name_t *closest; dns_fixedname_t fclosest; dns_name_t *nearest; dns_fixedname_t fnearest; dns_rdatatype_t found = dns_rdatatype_none; dns_name_t *noqname = NULL; FCTXTRACE("findnoqname"); REQUIRE(noqnamep != NULL && *noqnamep == NULL); /* * Find the SIG for this rdataset, if we have it. */ for (sigrdataset = ISC_LIST_HEAD(name->list); sigrdataset != NULL; sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) { if (sigrdataset->type == dns_rdatatype_rrsig && sigrdataset->covers == type) break; } if (sigrdataset == NULL) return (ISC_R_NOTFOUND); labels = dns_name_countlabels(name); for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(sigrdataset)) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(sigrdataset, &rdata); result = dns_rdata_tostruct(&rdata, &rrsig, NULL); RUNTIME_CHECK(result == ISC_R_SUCCESS); /* Wildcard has rrsig.labels < labels - 1. */ if (rrsig.labels + 1U >= labels) continue; break; } if (result == ISC_R_NOMORE) return (ISC_R_NOTFOUND); if (result != ISC_R_SUCCESS) return (result); dns_fixedname_init(&fzonename); zonename = dns_fixedname_name(&fzonename); dns_fixedname_init(&fclosest); closest = dns_fixedname_name(&fclosest); dns_fixedname_init(&fnearest); nearest = dns_fixedname_name(&fnearest); #define NXND(x) ((x) == ISC_R_SUCCESS) section = DNS_SECTION_AUTHORITY; for (result = dns_message_firstname(fctx->rmessage, section); result == ISC_R_SUCCESS; result = dns_message_nextname(fctx->rmessage, section)) { dns_name_t *nsec = NULL; dns_message_currentname(fctx->rmessage, section, &nsec); for (nrdataset = ISC_LIST_HEAD(nsec->list); nrdataset != NULL; nrdataset = next) { isc_boolean_t data = ISC_FALSE, exists = ISC_FALSE; isc_boolean_t optout = ISC_FALSE, unknown = ISC_FALSE; isc_boolean_t setclosest = ISC_FALSE; isc_boolean_t setnearest = ISC_FALSE; next = ISC_LIST_NEXT(nrdataset, link); if (nrdataset->type != dns_rdatatype_nsec && nrdataset->type != dns_rdatatype_nsec3) continue; if (nrdataset->type == dns_rdatatype_nsec && NXND(dns_nsec_noexistnodata(type, name, nsec, nrdataset, &exists, &data, NULL, fctx_log, fctx))) { if (!exists) { noqname = nsec; found = dns_rdatatype_nsec; } } if (nrdataset->type == dns_rdatatype_nsec3 && NXND(dns_nsec3_noexistnodata(type, name, nsec, nrdataset, zonename, &exists, &data, &optout, &unknown, &setclosest, &setnearest, closest, nearest, fctx_log, fctx))) { if (!exists && setnearest) { noqname = nsec; found = dns_rdatatype_nsec3; } } } } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; if (noqname != NULL) { for (sigrdataset = ISC_LIST_HEAD(noqname->list); sigrdataset != NULL; sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) { if (sigrdataset->type == dns_rdatatype_rrsig && sigrdataset->covers == found) break; } if (sigrdataset != NULL) *noqnamep = noqname; } return (result); } static inline isc_result_t cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) { dns_rdataset_t *rdataset, *sigrdataset; dns_rdataset_t *addedrdataset, *ardataset, *asigrdataset; dns_rdataset_t *valrdataset = NULL, *valsigrdataset = NULL; dns_dbnode_t *node, **anodep; dns_db_t **adbp; dns_name_t *aname; dns_resolver_t *res; isc_boolean_t need_validation, secure_domain, have_answer; isc_result_t result, eresult; dns_fetchevent_t *event; unsigned int options; isc_task_t *task; isc_boolean_t fail; unsigned int valoptions = 0; /* * The appropriate bucket lock must be held. */ res = fctx->res; need_validation = ISC_FALSE; POST(need_validation); secure_domain = ISC_FALSE; have_answer = ISC_FALSE; eresult = ISC_R_SUCCESS; task = res->buckets[fctx->bucketnum].task; /* * Is DNSSEC validation required for this name? */ if (res->view->enablevalidation) { result = dns_view_issecuredomain(res->view, name, &secure_domain); if (result != ISC_R_SUCCESS) return (result); if (!secure_domain && res->view->dlv != NULL) { valoptions = DNS_VALIDATOR_DLV; secure_domain = ISC_TRUE; } } if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0) need_validation = ISC_FALSE; else need_validation = secure_domain; adbp = NULL; aname = NULL; anodep = NULL; ardataset = NULL; asigrdataset = NULL; event = NULL; if ((name->attributes & DNS_NAMEATTR_ANSWER) != 0 && !need_validation) { have_answer = ISC_TRUE; event = ISC_LIST_HEAD(fctx->events); if (event != NULL) { adbp = &event->db; aname = dns_fixedname_name(&event->foundname); result = dns_name_copy(name, aname, NULL); if (result != ISC_R_SUCCESS) return (result); anodep = &event->node; /* * If this is an ANY, SIG or RRSIG query, we're not * going to return any rdatasets, unless we encountered * a CNAME or DNAME as "the answer". In this case, * we're going to return DNS_R_CNAME or DNS_R_DNAME * and we must set up the rdatasets. */ if ((fctx->type != dns_rdatatype_any && fctx->type != dns_rdatatype_rrsig && fctx->type != dns_rdatatype_sig) || (name->attributes & DNS_NAMEATTR_CHAINING) != 0) { ardataset = event->rdataset; asigrdataset = event->sigrdataset; } } } /* * Find or create the cache node. */ node = NULL; result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node); if (result != ISC_R_SUCCESS) return (result); /* * Cache or validate each cacheable rdataset. */ fail = ISC_TF((fctx->res->options & DNS_RESOLVER_CHECKNAMESFAIL) != 0); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (!CACHE(rdataset)) continue; if (CHECKNAMES(rdataset)) { char namebuf[DNS_NAME_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; char classbuf[DNS_RDATATYPE_FORMATSIZE]; dns_name_format(name, namebuf, sizeof(namebuf)); dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, "check-names %s %s/%s/%s", fail ? "failure" : "warning", namebuf, typebuf, classbuf); if (fail) { if (ANSWER(rdataset)) { dns_db_detachnode(fctx->cache, &node); return (DNS_R_BADNAME); } continue; } } /* * Enforce the configure maximum cache TTL. */ if (rdataset->ttl > res->view->maxcachettl) rdataset->ttl = res->view->maxcachettl; /* * Find the SIG for this rdataset, if we have it. */ for (sigrdataset = ISC_LIST_HEAD(name->list); sigrdataset != NULL; sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) { if (sigrdataset->type == dns_rdatatype_rrsig && sigrdataset->covers == rdataset->type) break; } /* * If this RRset is in a secure domain, is in bailiwick, * and is not glue, attempt DNSSEC validation. (We do not * attempt to validate glue or out-of-bailiwick data--even * though there might be some performance benefit to doing * so--because it makes it simpler and safer to ensure that * records from a secure domain are only cached if validated * within the context of a query to the domain that owns * them.) */ if (secure_domain && rdataset->trust != dns_trust_glue && !EXTERNAL(rdataset)) { dns_trust_t trust; /* * RRSIGs are validated as part of validating the * type they cover. */ if (rdataset->type == dns_rdatatype_rrsig) continue; if (sigrdataset == NULL) { if (!ANSWER(rdataset) && need_validation) { /* * Ignore non-answer rdatasets that * are missing signatures. */ continue; } } /* * Normalize the rdataset and sigrdataset TTLs. */ if (sigrdataset != NULL) { rdataset->ttl = ISC_MIN(rdataset->ttl, sigrdataset->ttl); sigrdataset->ttl = rdataset->ttl; } /* * Cache this rdataset/sigrdataset pair as * pending data. Track whether it was additional * or not. */ if (rdataset->trust == dns_trust_additional) trust = dns_trust_pending_additional; else trust = dns_trust_pending_answer; rdataset->trust = trust; if (sigrdataset != NULL) sigrdataset->trust = trust; if (!need_validation || !ANSWER(rdataset)) { if (ANSWER(rdataset) && rdataset->type != dns_rdatatype_rrsig) { isc_result_t tresult; dns_name_t *noqname = NULL; tresult = findnoqname(fctx, name, rdataset->type, &noqname); if (tresult == ISC_R_SUCCESS && noqname != NULL) { tresult = dns_rdataset_addnoqname( rdataset, noqname); RUNTIME_CHECK(tresult == ISC_R_SUCCESS); } } addedrdataset = ardataset; result = dns_db_addrdataset(fctx->cache, node, NULL, now, rdataset, 0, addedrdataset); if (result == DNS_R_UNCHANGED) { result = ISC_R_SUCCESS; if (!need_validation && ardataset != NULL && NEGATIVE(ardataset)) { /* * The answer in the cache is * better than the answer we * found, and is a negative * cache entry, so we must set * eresult appropriately. */ if (NXDOMAIN(ardataset)) eresult = DNS_R_NCACHENXDOMAIN; else eresult = DNS_R_NCACHENXRRSET; /* * We have a negative response * from the cache so don't * attempt to add the RRSIG * rrset. */ continue; } } if (result != ISC_R_SUCCESS) break; if (sigrdataset != NULL) { addedrdataset = asigrdataset; result = dns_db_addrdataset(fctx->cache, node, NULL, now, sigrdataset, 0, addedrdataset); if (result == DNS_R_UNCHANGED) result = ISC_R_SUCCESS; if (result != ISC_R_SUCCESS) break; } else if (!ANSWER(rdataset)) continue; } if (ANSWER(rdataset) && need_validation) { if (fctx->type != dns_rdatatype_any && fctx->type != dns_rdatatype_rrsig && fctx->type != dns_rdatatype_sig) { /* * This is The Answer. We will * validate it, but first we cache * the rest of the response - it may * contain useful keys. */ INSIST(valrdataset == NULL && valsigrdataset == NULL); valrdataset = rdataset; valsigrdataset = sigrdataset; } else { /* * This is one of (potentially) * multiple answers to an ANY * or SIG query. To keep things * simple, we just start the * validator right away rather * than caching first and * having to remember which * rdatasets needed validation. */ result = valcreate(fctx, addrinfo, name, rdataset->type, rdataset, sigrdataset, valoptions, task); - /* - * Defer any further validations. - * This prevents multiple validators - * from manipulating fctx->rmessage - * simultaneously. - */ - valoptions |= DNS_VALIDATOR_DEFER; } } else if (CHAINING(rdataset)) { if (rdataset->type == dns_rdatatype_cname) eresult = DNS_R_CNAME; else { INSIST(rdataset->type == dns_rdatatype_dname); eresult = DNS_R_DNAME; } } } else if (!EXTERNAL(rdataset)) { /* * It's OK to cache this rdataset now. */ if (ANSWER(rdataset)) addedrdataset = ardataset; else if (ANSWERSIG(rdataset)) addedrdataset = asigrdataset; else addedrdataset = NULL; if (CHAINING(rdataset)) { if (rdataset->type == dns_rdatatype_cname) eresult = DNS_R_CNAME; else { INSIST(rdataset->type == dns_rdatatype_dname); eresult = DNS_R_DNAME; } } if (rdataset->trust == dns_trust_glue && (rdataset->type == dns_rdatatype_ns || (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == dns_rdatatype_ns))) { /* * If the trust level is 'dns_trust_glue' * then we are adding data from a referral * we got while executing the search algorithm. * New referral data always takes precedence * over the existing cache contents. */ options = DNS_DBADD_FORCE; } else options = 0; if (ANSWER(rdataset) && rdataset->type != dns_rdatatype_rrsig) { isc_result_t tresult; dns_name_t *noqname = NULL; tresult = findnoqname(fctx, name, rdataset->type, &noqname); if (tresult == ISC_R_SUCCESS && noqname != NULL) { tresult = dns_rdataset_addnoqname( rdataset, noqname); RUNTIME_CHECK(tresult == ISC_R_SUCCESS); } } /* * Now we can add the rdataset. */ result = dns_db_addrdataset(fctx->cache, node, NULL, now, rdataset, options, addedrdataset); if (result == DNS_R_UNCHANGED) { if (ANSWER(rdataset) && ardataset != NULL && NEGATIVE(ardataset)) { /* * The answer in the cache is better * than the answer we found, and is * a negative cache entry, so we * must set eresult appropriately. */ if (NXDOMAIN(ardataset)) eresult = DNS_R_NCACHENXDOMAIN; else eresult = DNS_R_NCACHENXRRSET; } result = ISC_R_SUCCESS; } else if (result != ISC_R_SUCCESS) break; } } if (valrdataset != NULL) result = valcreate(fctx, addrinfo, name, fctx->type, valrdataset, valsigrdataset, valoptions, task); if (result == ISC_R_SUCCESS && have_answer) { fctx->attributes |= FCTX_ATTR_HAVEANSWER; if (event != NULL) { /* * Negative results must be indicated in event->result. */ if (dns_rdataset_isassociated(event->rdataset) && NEGATIVE(event->rdataset)) { INSIST(eresult == DNS_R_NCACHENXDOMAIN || eresult == DNS_R_NCACHENXRRSET); } event->result = eresult; + if (adbp != NULL && *adbp != NULL) { + if (anodep != NULL && *anodep != NULL) + dns_db_detachnode(*adbp, anodep); + dns_db_detach(adbp); + } dns_db_attach(fctx->cache, adbp); dns_db_transfernode(fctx->cache, &node, anodep); clone_results(fctx); } } if (node != NULL) dns_db_detachnode(fctx->cache, &node); return (result); } static inline isc_result_t cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) { isc_result_t result; dns_section_t section; dns_name_t *name; FCTXTRACE("cache_message"); fctx->attributes &= ~FCTX_ATTR_WANTCACHE; LOCK(&fctx->res->buckets[fctx->bucketnum].lock); for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL; section++) { result = dns_message_firstname(fctx->rmessage, section); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(fctx->rmessage, section, &name); if ((name->attributes & DNS_NAMEATTR_CACHE) != 0) { result = cache_name(fctx, name, addrinfo, now); if (result != ISC_R_SUCCESS) break; } result = dns_message_nextname(fctx->rmessage, section); } if (result != ISC_R_NOMORE) break; } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); return (result); } /* * Do what dns_ncache_addoptout() does, and then compute an appropriate eresult. */ static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, isc_boolean_t optout, isc_boolean_t secure, dns_rdataset_t *ardataset, isc_result_t *eresultp) { isc_result_t result; dns_rdataset_t rdataset; if (ardataset == NULL) { dns_rdataset_init(&rdataset); ardataset = &rdataset; } if (secure) result = dns_ncache_addoptout(message, cache, node, covers, now, maxttl, optout, ardataset); else result = dns_ncache_add(message, cache, node, covers, now, maxttl, ardataset); if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) { /* * If the cache now contains a negative entry and we * care about whether it is DNS_R_NCACHENXDOMAIN or * DNS_R_NCACHENXRRSET then extract it. */ if (NEGATIVE(ardataset)) { /* * The cache data is a negative cache entry. */ if (NXDOMAIN(ardataset)) *eresultp = DNS_R_NCACHENXDOMAIN; else *eresultp = DNS_R_NCACHENXRRSET; } else { /* * Either we don't care about the nature of the * cache rdataset (because no fetch is interested * in the outcome), or the cache rdataset is not * a negative cache entry. Whichever case it is, * we can return success. * * XXXRTH There's a CNAME/DNAME problem here. */ *eresultp = ISC_R_SUCCESS; } result = ISC_R_SUCCESS; } if (ardataset == &rdataset && dns_rdataset_isassociated(ardataset)) dns_rdataset_disassociate(ardataset); return (result); } static inline isc_result_t ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_rdatatype_t covers, isc_stdtime_t now) { isc_result_t result, eresult; dns_name_t *name; dns_resolver_t *res; dns_db_t **adbp; dns_dbnode_t *node, **anodep; dns_rdataset_t *ardataset; isc_boolean_t need_validation, secure_domain; dns_name_t *aname; dns_fetchevent_t *event; isc_uint32_t ttl; unsigned int valoptions = 0; FCTXTRACE("ncache_message"); fctx->attributes &= ~FCTX_ATTR_WANTNCACHE; res = fctx->res; need_validation = ISC_FALSE; POST(need_validation); secure_domain = ISC_FALSE; eresult = ISC_R_SUCCESS; name = &fctx->name; node = NULL; /* * XXXMPA remove when we follow cnames and adjust the setting * of FCTX_ATTR_WANTNCACHE in noanswer_response(). */ INSIST(fctx->rmessage->counts[DNS_SECTION_ANSWER] == 0); /* * Is DNSSEC validation required for this name? */ if (fctx->res->view->enablevalidation) { result = dns_view_issecuredomain(res->view, name, &secure_domain); if (result != ISC_R_SUCCESS) return (result); if (!secure_domain && res->view->dlv != NULL) { valoptions = DNS_VALIDATOR_DLV; secure_domain = ISC_TRUE; } } if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0) need_validation = ISC_FALSE; else need_validation = secure_domain; if (secure_domain) { /* * Mark all rdatasets as pending. */ dns_rdataset_t *trdataset; dns_name_t *tname; result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { tname = NULL; dns_message_currentname(fctx->rmessage, DNS_SECTION_AUTHORITY, &tname); for (trdataset = ISC_LIST_HEAD(tname->list); trdataset != NULL; trdataset = ISC_LIST_NEXT(trdataset, link)) trdataset->trust = dns_trust_pending_answer; result = dns_message_nextname(fctx->rmessage, DNS_SECTION_AUTHORITY); } if (result != ISC_R_NOMORE) return (result); } if (need_validation) { /* * Do negative response validation. */ result = valcreate(fctx, addrinfo, name, fctx->type, NULL, NULL, valoptions, res->buckets[fctx->bucketnum].task); /* * If validation is necessary, return now. Otherwise continue * to process the message, letting the validation complete * in its own good time. */ return (result); } LOCK(&res->buckets[fctx->bucketnum].lock); adbp = NULL; aname = NULL; anodep = NULL; ardataset = NULL; if (!HAVE_ANSWER(fctx)) { event = ISC_LIST_HEAD(fctx->events); if (event != NULL) { adbp = &event->db; aname = dns_fixedname_name(&event->foundname); result = dns_name_copy(name, aname, NULL); if (result != ISC_R_SUCCESS) goto unlock; anodep = &event->node; ardataset = event->rdataset; } } else event = NULL; result = dns_db_findnode(fctx->cache, name, ISC_TRUE, &node); if (result != ISC_R_SUCCESS) goto unlock; /* * If we are asking for a SOA record set the cache time * to zero to facilitate locating the containing zone of * a arbitrary zone. */ ttl = fctx->res->view->maxncachettl; if (fctx->type == dns_rdatatype_soa && covers == dns_rdatatype_any && fctx->res->zero_no_soa_ttl) ttl = 0; result = ncache_adderesult(fctx->rmessage, fctx->cache, node, covers, now, ttl, ISC_FALSE, ISC_FALSE, ardataset, &eresult); if (result != ISC_R_SUCCESS) goto unlock; if (!HAVE_ANSWER(fctx)) { fctx->attributes |= FCTX_ATTR_HAVEANSWER; if (event != NULL) { event->result = eresult; + if (adbp != NULL && *adbp != NULL) { + if (anodep != NULL && *anodep != NULL) + dns_db_detachnode(*adbp, anodep); + dns_db_detach(adbp); + } dns_db_attach(fctx->cache, adbp); dns_db_transfernode(fctx->cache, &node, anodep); clone_results(fctx); } } unlock: UNLOCK(&res->buckets[fctx->bucketnum].lock); if (node != NULL) dns_db_detachnode(fctx->cache, &node); return (result); } static inline void mark_related(dns_name_t *name, dns_rdataset_t *rdataset, isc_boolean_t external, isc_boolean_t gluing) { name->attributes |= DNS_NAMEATTR_CACHE; if (gluing) { rdataset->trust = dns_trust_glue; /* * Glue with 0 TTL causes problems. We force the TTL to * 1 second to prevent this. */ if (rdataset->ttl == 0) rdataset->ttl = 1; } else rdataset->trust = dns_trust_additional; /* * Avoid infinite loops by only marking new rdatasets. */ if (!CACHE(rdataset)) { name->attributes |= DNS_NAMEATTR_CHASE; rdataset->attributes |= DNS_RDATASETATTR_CHASE; } rdataset->attributes |= DNS_RDATASETATTR_CACHE; if (external) rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL; } static isc_result_t check_section(void *arg, dns_name_t *addname, dns_rdatatype_t type, dns_section_t section) { fetchctx_t *fctx = arg; isc_result_t result; dns_name_t *name; dns_rdataset_t *rdataset; isc_boolean_t external; dns_rdatatype_t rtype; isc_boolean_t gluing; REQUIRE(VALID_FCTX(fctx)); #if CHECK_FOR_GLUE_IN_ANSWER if (section == DNS_SECTION_ANSWER && type != dns_rdatatype_a) return (ISC_R_SUCCESS); #endif if (GLUING(fctx)) gluing = ISC_TRUE; else gluing = ISC_FALSE; name = NULL; rdataset = NULL; result = dns_message_findname(fctx->rmessage, section, addname, dns_rdatatype_any, 0, &name, NULL); if (result == ISC_R_SUCCESS) { external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); if (type == dns_rdatatype_a) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->type == dns_rdatatype_rrsig) rtype = rdataset->covers; else rtype = rdataset->type; if (rtype == dns_rdatatype_a || rtype == dns_rdatatype_aaaa) mark_related(name, rdataset, external, gluing); } } else { result = dns_message_findtype(name, type, 0, &rdataset); if (result == ISC_R_SUCCESS) { mark_related(name, rdataset, external, gluing); /* * Do we have its SIG too? */ rdataset = NULL; result = dns_message_findtype(name, dns_rdatatype_rrsig, type, &rdataset); if (result == ISC_R_SUCCESS) mark_related(name, rdataset, external, gluing); } } } return (ISC_R_SUCCESS); } static isc_result_t check_related(void *arg, dns_name_t *addname, dns_rdatatype_t type) { return (check_section(arg, addname, type, DNS_SECTION_ADDITIONAL)); } #ifndef CHECK_FOR_GLUE_IN_ANSWER #define CHECK_FOR_GLUE_IN_ANSWER 0 #endif #if CHECK_FOR_GLUE_IN_ANSWER static isc_result_t check_answer(void *arg, dns_name_t *addname, dns_rdatatype_t type) { return (check_section(arg, addname, type, DNS_SECTION_ANSWER)); } #endif static void chase_additional(fetchctx_t *fctx) { isc_boolean_t rescan; dns_section_t section = DNS_SECTION_ADDITIONAL; isc_result_t result; again: rescan = ISC_FALSE; for (result = dns_message_firstname(fctx->rmessage, section); result == ISC_R_SUCCESS; result = dns_message_nextname(fctx->rmessage, section)) { dns_name_t *name = NULL; dns_rdataset_t *rdataset; dns_message_currentname(fctx->rmessage, DNS_SECTION_ADDITIONAL, &name); if ((name->attributes & DNS_NAMEATTR_CHASE) == 0) continue; name->attributes &= ~DNS_NAMEATTR_CHASE; for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (CHASE(rdataset)) { rdataset->attributes &= ~DNS_RDATASETATTR_CHASE; (void)dns_rdataset_additionaldata(rdataset, check_related, fctx); rescan = ISC_TRUE; } } } if (rescan) goto again; } static inline isc_result_t cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_cname_t cname; result = dns_rdataset_first(rdataset); if (result != ISC_R_SUCCESS) return (result); dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &cname, NULL); if (result != ISC_R_SUCCESS) return (result); dns_name_init(tname, NULL); dns_name_clone(&cname.cname, tname); dns_rdata_freestruct(&cname); return (ISC_R_SUCCESS); } static inline isc_result_t dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, unsigned int nlabels, dns_fixedname_t *fixeddname) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_dname_t dname; dns_fixedname_t prefix; /* * Get the target name of the DNAME. */ result = dns_rdataset_first(rdataset); if (result != ISC_R_SUCCESS) return (result); dns_rdataset_current(rdataset, &rdata); result = dns_rdata_tostruct(&rdata, &dname, NULL); if (result != ISC_R_SUCCESS) return (result); dns_fixedname_init(&prefix); dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); dns_fixedname_init(fixeddname); result = dns_name_concatenate(dns_fixedname_name(&prefix), &dname.dname, dns_fixedname_name(fixeddname), NULL); dns_rdata_freestruct(&dname); return (result); } static isc_boolean_t is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, dns_rdataset_t *rdataset) { isc_result_t result; dns_rdata_t rdata = DNS_RDATA_INIT; struct in_addr ina; struct in6_addr in6a; isc_netaddr_t netaddr; char addrbuf[ISC_NETADDR_FORMATSIZE]; char namebuf[DNS_NAME_FORMATSIZE]; char classbuf[64]; char typebuf[64]; int match; /* By default, we allow any addresses. */ if (view->denyansweracl == NULL) return (ISC_TRUE); /* * If the owner name matches one in the exclusion list, either exactly * or partially, allow it. */ if (view->answeracl_exclude != NULL) { dns_rbtnode_t *node = NULL; result = dns_rbt_findnode(view->answeracl_exclude, name, NULL, &node, NULL, 0, NULL, NULL); if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) return (ISC_TRUE); } /* * Otherwise, search the filter list for a match for each address * record. If a match is found, the address should be filtered, * so should the entire answer. */ for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { dns_rdata_reset(&rdata); dns_rdataset_current(rdataset, &rdata); if (rdataset->type == dns_rdatatype_a) { INSIST(rdata.length == sizeof(ina.s_addr)); memmove(&ina.s_addr, rdata.data, sizeof(ina.s_addr)); isc_netaddr_fromin(&netaddr, &ina); } else { INSIST(rdata.length == sizeof(in6a.s6_addr)); memmove(in6a.s6_addr, rdata.data, sizeof(in6a.s6_addr)); isc_netaddr_fromin6(&netaddr, &in6a); } result = dns_acl_match(&netaddr, NULL, view->denyansweracl, &view->aclenv, &match, NULL); if (result == ISC_R_SUCCESS && match > 0) { isc_netaddr_format(&netaddr, addrbuf, sizeof(addrbuf)); dns_name_format(name, namebuf, sizeof(namebuf)); dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, "answer address %s denied for %s/%s/%s", addrbuf, namebuf, typebuf, classbuf); return (ISC_FALSE); } } return (ISC_TRUE); } static isc_boolean_t is_answertarget_allowed(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, dns_name_t *tname, dns_name_t *domain) { isc_result_t result; dns_rbtnode_t *node = NULL; char qnamebuf[DNS_NAME_FORMATSIZE]; char tnamebuf[DNS_NAME_FORMATSIZE]; char classbuf[64]; char typebuf[64]; /* By default, we allow any target name. */ if (view->denyanswernames == NULL) return (ISC_TRUE); /* * If the owner name matches one in the exclusion list, either exactly * or partially, allow it. */ if (view->answernames_exclude != NULL) { result = dns_rbt_findnode(view->answernames_exclude, name, NULL, &node, NULL, 0, NULL, NULL); if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) return (ISC_TRUE); } /* * If the target name is a subdomain of the search domain, allow it. */ if (dns_name_issubdomain(tname, domain)) return (ISC_TRUE); /* * Otherwise, apply filters. */ result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node, NULL, 0, NULL, NULL); if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { dns_name_format(name, qnamebuf, sizeof(qnamebuf)); dns_name_format(tname, tnamebuf, sizeof(tnamebuf)); dns_rdatatype_format(type, typebuf, sizeof(typebuf)); dns_rdataclass_format(view->rdclass, classbuf, sizeof(classbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, "%s target %s denied for %s/%s", typebuf, tnamebuf, qnamebuf, classbuf); return (ISC_FALSE); } return (ISC_TRUE); } static void trim_ns_ttl(fetchctx_t *fctx, dns_name_t *name, dns_rdataset_t *rdataset) { char ns_namebuf[DNS_NAME_FORMATSIZE]; char namebuf[DNS_NAME_FORMATSIZE]; char tbuf[DNS_RDATATYPE_FORMATSIZE]; if (fctx->ns_ttl_ok && rdataset->ttl > fctx->ns_ttl) { dns_name_format(name, ns_namebuf, sizeof(ns_namebuf)); dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(fctx->type, tbuf, sizeof(tbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(10), "fctx %p: trimming ttl of %s/NS for %s/%s: " "%u -> %u", fctx, ns_namebuf, namebuf, tbuf, rdataset->ttl, fctx->ns_ttl); rdataset->ttl = fctx->ns_ttl; } } /* * Handle a no-answer response (NXDOMAIN, NXRRSET, or referral). * If look_in_options has LOOK_FOR_NS_IN_ANSWER then we look in the answer * section for the NS RRset if the query type is NS; if it has * LOOK_FOR_GLUE_IN_ANSWER we look for glue incorrectly returned in the answer * section for A and AAAA queries. */ #define LOOK_FOR_NS_IN_ANSWER 0x1 #define LOOK_FOR_GLUE_IN_ANSWER 0x2 static isc_result_t noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, unsigned int look_in_options) { isc_result_t result; dns_message_t *message; dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name, *save_name; dns_rdataset_t *rdataset, *ns_rdataset; isc_boolean_t aa, negative_response; dns_rdatatype_t type, save_type; dns_section_t section; FCTXTRACE("noanswer_response"); if ((look_in_options & LOOK_FOR_NS_IN_ANSWER) != 0) { INSIST(fctx->type == dns_rdatatype_ns); section = DNS_SECTION_ANSWER; } else section = DNS_SECTION_AUTHORITY; message = fctx->rmessage; /* * Setup qname. */ if (oqname == NULL) { /* * We have a normal, non-chained negative response or * referral. */ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0) aa = ISC_TRUE; else aa = ISC_FALSE; qname = &fctx->name; } else { /* * We're being invoked by answer_response() after it has * followed a CNAME/DNAME chain. */ qname = oqname; aa = ISC_FALSE; /* * If the current qname is not a subdomain of the query * domain, there's no point in looking at the authority * section without doing DNSSEC validation. * * Until we do that validation, we'll just return success * in this case. */ if (!dns_name_issubdomain(qname, &fctx->domain)) return (ISC_R_SUCCESS); } /* * We have to figure out if this is a negative response, or a * referral. */ /* * Sometimes we can tell if its a negative response by looking at * the message header. */ negative_response = ISC_FALSE; if (message->rcode == dns_rcode_nxdomain || (message->counts[DNS_SECTION_ANSWER] == 0 && message->counts[DNS_SECTION_AUTHORITY] == 0)) negative_response = ISC_TRUE; /* * Process the authority section. */ ns_name = NULL; ns_rdataset = NULL; soa_name = NULL; ds_name = NULL; save_name = NULL; save_type = dns_rdatatype_none; result = dns_message_firstname(message, section); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, section, &name); if (dns_name_issubdomain(name, &fctx->domain)) { /* * Look for NS/SOA RRsets first. */ for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { type = rdataset->type; if (type == dns_rdatatype_rrsig) type = rdataset->covers; if (((type == dns_rdatatype_ns || type == dns_rdatatype_soa) && !dns_name_issubdomain(qname, name))) { char qbuf[DNS_NAME_FORMATSIZE]; char nbuf[DNS_NAME_FORMATSIZE]; char tbuf[DNS_RDATATYPE_FORMATSIZE]; dns_rdatatype_format(fctx->type, tbuf, sizeof(tbuf)); dns_name_format(name, nbuf, sizeof(nbuf)); dns_name_format(qname, qbuf, sizeof(qbuf)); log_formerr(fctx, "unrelated %s %s in " "%s authority section", tbuf, qbuf, nbuf); return (DNS_R_FORMERR); } if (type == dns_rdatatype_ns) { /* * NS or RRSIG NS. * * Only one set of NS RRs is allowed. */ if (rdataset->type == dns_rdatatype_ns) { if (ns_name != NULL && name != ns_name) { log_formerr(fctx, "multiple NS " "RRsets in " "authority " "section"); return (DNS_R_FORMERR); } ns_name = name; ns_rdataset = rdataset; } name->attributes |= DNS_NAMEATTR_CACHE; rdataset->attributes |= DNS_RDATASETATTR_CACHE; rdataset->trust = dns_trust_glue; } if (type == dns_rdatatype_soa) { /* * SOA, or RRSIG SOA. * * Only one SOA is allowed. */ if (rdataset->type == dns_rdatatype_soa) { if (soa_name != NULL && name != soa_name) { log_formerr(fctx, "multiple SOA " "RRs in " "authority " "section"); return (DNS_R_FORMERR); } soa_name = name; } name->attributes |= DNS_NAMEATTR_NCACHE; rdataset->attributes |= DNS_RDATASETATTR_NCACHE; if (aa) rdataset->trust = dns_trust_authauthority; else if (ISFORWARDER(fctx->addrinfo)) rdataset->trust = dns_trust_answer; else rdataset->trust = dns_trust_additional; } } } result = dns_message_nextname(message, section); if (result == ISC_R_NOMORE) break; else if (result != ISC_R_SUCCESS) return (result); } log_ns_ttl(fctx, "noanswer_response"); if (ns_rdataset != NULL && dns_name_equal(&fctx->domain, ns_name) && !dns_name_equal(ns_name, dns_rootname)) trim_ns_ttl(fctx, ns_name, ns_rdataset); /* * A negative response has a SOA record (Type 2) * and a optional NS RRset (Type 1) or it has neither * a SOA or a NS RRset (Type 3, handled above) or * rcode is NXDOMAIN (handled above) in which case * the NS RRset is allowed (Type 4). */ if (soa_name != NULL) negative_response = ISC_TRUE; result = dns_message_firstname(message, section); while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, section, &name); if (dns_name_issubdomain(name, &fctx->domain)) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { type = rdataset->type; if (type == dns_rdatatype_rrsig) type = rdataset->covers; if (type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3) { /* * NSEC or RRSIG NSEC. */ if (negative_response) { name->attributes |= DNS_NAMEATTR_NCACHE; rdataset->attributes |= DNS_RDATASETATTR_NCACHE; } else if (type == dns_rdatatype_nsec) { name->attributes |= DNS_NAMEATTR_CACHE; rdataset->attributes |= DNS_RDATASETATTR_CACHE; } if (aa) rdataset->trust = dns_trust_authauthority; else if (ISFORWARDER(fctx->addrinfo)) rdataset->trust = dns_trust_answer; else rdataset->trust = dns_trust_additional; /* * No additional data needs to be * marked. */ } else if (type == dns_rdatatype_ds) { /* * DS or SIG DS. * * These should only be here if * this is a referral, and there * should only be one DS RRset. */ if (ns_name == NULL) { log_formerr(fctx, "DS with no " "referral"); return (DNS_R_FORMERR); } if (rdataset->type == dns_rdatatype_ds) { if (ds_name != NULL && name != ds_name) { log_formerr(fctx, "DS doesn't " "match " "referral " "(NS)"); return (DNS_R_FORMERR); } ds_name = name; } name->attributes |= DNS_NAMEATTR_CACHE; rdataset->attributes |= DNS_RDATASETATTR_CACHE; if (aa) rdataset->trust = dns_trust_authauthority; else if (ISFORWARDER(fctx->addrinfo)) rdataset->trust = dns_trust_answer; else rdataset->trust = dns_trust_additional; } } } else { save_name = name; save_type = ISC_LIST_HEAD(name->list)->type; } result = dns_message_nextname(message, section); if (result == ISC_R_NOMORE) break; else if (result != ISC_R_SUCCESS) return (result); } /* * Trigger lookups for DNS nameservers. */ if (negative_response && message->rcode == dns_rcode_noerror && fctx->type == dns_rdatatype_ds && soa_name != NULL && dns_name_equal(soa_name, qname) && !dns_name_equal(qname, dns_rootname)) return (DNS_R_CHASEDSSERVERS); /* * Did we find anything? */ if (!negative_response && ns_name == NULL) { /* * Nope. */ if (oqname != NULL) { /* * We've already got a partial CNAME/DNAME chain, * and haven't found else anything useful here, but * no error has occurred since we have an answer. */ return (ISC_R_SUCCESS); } else { /* * The responder is insane. */ if (save_name == NULL) { log_formerr(fctx, "invalid response"); return (DNS_R_FORMERR); } if (!dns_name_issubdomain(save_name, &fctx->domain)) { char nbuf[DNS_NAME_FORMATSIZE]; char dbuf[DNS_NAME_FORMATSIZE]; char tbuf[DNS_RDATATYPE_FORMATSIZE]; dns_rdatatype_format(save_type, tbuf, sizeof(tbuf)); dns_name_format(save_name, nbuf, sizeof(nbuf)); dns_name_format(&fctx->domain, dbuf, sizeof(dbuf)); log_formerr(fctx, "Name %s (%s) not subdomain" " of zone %s -- invalid response", nbuf, tbuf, dbuf); } else { log_formerr(fctx, "invalid response"); } return (DNS_R_FORMERR); } } /* * If we found both NS and SOA, they should be the same name. */ if (ns_name != NULL && soa_name != NULL && ns_name != soa_name) { log_formerr(fctx, "NS/SOA mismatch"); return (DNS_R_FORMERR); } /* * Do we have a referral? (We only want to follow a referral if * we're not following a chain.) */ if (!negative_response && ns_name != NULL && oqname == NULL) { /* * We already know ns_name is a subdomain of fctx->domain. * If ns_name is equal to fctx->domain, we're not making * progress. We return DNS_R_FORMERR so that we'll keep * trying other servers. */ if (dns_name_equal(ns_name, &fctx->domain)) { log_formerr(fctx, "non-improving referral"); return (DNS_R_FORMERR); } /* * If the referral name is not a parent of the query * name, consider the responder insane. */ if (! dns_name_issubdomain(&fctx->name, ns_name)) { /* Logged twice */ log_formerr(fctx, "referral to non-parent"); FCTXTRACE("referral to non-parent"); return (DNS_R_FORMERR); } /* * Mark any additional data related to this rdataset. * It's important that we do this before we change the * query domain. */ INSIST(ns_rdataset != NULL); fctx->attributes |= FCTX_ATTR_GLUING; (void)dns_rdataset_additionaldata(ns_rdataset, check_related, fctx); #if CHECK_FOR_GLUE_IN_ANSWER /* * Look in the answer section for "glue" that is incorrectly * returned as a answer. This is needed if the server also * minimizes the response size by not adding records to the * additional section that are in the answer section or if * the record gets dropped due to message size constraints. */ if ((look_in_options & LOOK_FOR_GLUE_IN_ANSWER) != 0 && (fctx->type == dns_rdatatype_aaaa || fctx->type == dns_rdatatype_a)) (void)dns_rdataset_additionaldata(ns_rdataset, check_answer, fctx); #endif fctx->attributes &= ~FCTX_ATTR_GLUING; /* * NS rdatasets with 0 TTL cause problems. * dns_view_findzonecut() will not find them when we * try to follow the referral, and we'll SERVFAIL * because the best nameservers are now above QDOMAIN. * We force the TTL to 1 second to prevent this. */ if (ns_rdataset->ttl == 0) ns_rdataset->ttl = 1; /* * Set the current query domain to the referral name. * * XXXRTH We should check if we're in forward-only mode, and * if so we should bail out. */ INSIST(dns_name_countlabels(&fctx->domain) > 0); dns_name_free(&fctx->domain, fctx->mctx); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); dns_name_init(&fctx->domain, NULL); result = dns_name_dup(ns_name, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) return (result); fctx->attributes |= FCTX_ATTR_WANTCACHE; fctx->ns_ttl_ok = ISC_FALSE; log_ns_ttl(fctx, "DELEGATION"); return (DNS_R_DELEGATION); } /* * Since we're not doing a referral, we don't want to cache any * NS RRs we may have found. */ if (ns_name != NULL) ns_name->attributes &= ~DNS_NAMEATTR_CACHE; if (negative_response && oqname == NULL) fctx->attributes |= FCTX_ATTR_WANTNCACHE; return (ISC_R_SUCCESS); } static isc_result_t answer_response(fetchctx_t *fctx) { isc_result_t result; dns_message_t *message; - dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; + dns_name_t *name, *dname = NULL, *qname, *dqname, tname, *ns_name; + dns_name_t *cname = NULL; dns_rdataset_t *rdataset, *ns_rdataset; isc_boolean_t done, external, chaining, aa, found, want_chaining; - isc_boolean_t have_answer, found_cname, found_type, wanted_chaining; + isc_boolean_t have_answer, found_cname, found_dname, found_type; + isc_boolean_t wanted_chaining; unsigned int aflag; dns_rdatatype_t type; - dns_fixedname_t fdname, fqname; + dns_fixedname_t fdname, fqname, fqdname; dns_view_t *view; FCTXTRACE("answer_response"); message = fctx->rmessage; /* * Examine the answer section, marking those rdatasets which are * part of the answer and should be cached. */ done = ISC_FALSE; found_cname = ISC_FALSE; + found_dname = ISC_FALSE; found_type = ISC_FALSE; chaining = ISC_FALSE; have_answer = ISC_FALSE; want_chaining = ISC_FALSE; POST(want_chaining); if ((message->flags & DNS_MESSAGEFLAG_AA) != 0) aa = ISC_TRUE; else aa = ISC_FALSE; - qname = &fctx->name; + dqname = qname = &fctx->name; type = fctx->type; view = fctx->res->view; + dns_fixedname_init(&fqdname); result = dns_message_firstname(message, DNS_SECTION_ANSWER); while (!done && result == ISC_R_SUCCESS) { - dns_namereln_t namereln; + dns_namereln_t namereln, dnamereln; int order; unsigned int nlabels; name = NULL; dns_message_currentname(message, DNS_SECTION_ANSWER, &name); external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); namereln = dns_name_fullcompare(qname, name, &order, &nlabels); + dnamereln = dns_name_fullcompare(dqname, name, &order, + &nlabels); if (namereln == dns_namereln_equal) { wanted_chaining = ISC_FALSE; for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { found = ISC_FALSE; want_chaining = ISC_FALSE; aflag = 0; if (rdataset->type == dns_rdatatype_nsec3) { /* * NSEC3 records are not allowed to * appear in the answer section. */ log_formerr(fctx, "NSEC3 in answer"); return (DNS_R_FORMERR); } /* * Apply filters, if given, on answers to reject * a malicious attempt of rebinding. */ if ((rdataset->type == dns_rdatatype_a || rdataset->type == dns_rdatatype_aaaa) && !is_answeraddress_allowed(view, name, rdataset)) { return (DNS_R_SERVFAIL); } if (rdataset->type == type && !found_cname) { /* * We've found an ordinary answer. */ found = ISC_TRUE; found_type = ISC_TRUE; done = ISC_TRUE; aflag = DNS_RDATASETATTR_ANSWER; } else if (type == dns_rdatatype_any) { /* * We've found an answer matching * an ANY query. There may be * more. */ found = ISC_TRUE; aflag = DNS_RDATASETATTR_ANSWER; } else if (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == type && !found_cname) { /* * We've found a signature that * covers the type we're looking for. */ found = ISC_TRUE; found_type = ISC_TRUE; aflag = DNS_RDATASETATTR_ANSWERSIG; } else if (rdataset->type == dns_rdatatype_cname && !found_type) { /* * We're looking for something else, * but we found a CNAME. * * Getting a CNAME response for some * query types is an error, see * RFC 4035, Section 2.5. */ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_key || type == dns_rdatatype_nsec) { char buf[DNS_RDATATYPE_FORMATSIZE]; dns_rdatatype_format(fctx->type, buf, sizeof(buf)); log_formerr(fctx, "CNAME response " "for %s RR", buf); return (DNS_R_FORMERR); } found = ISC_TRUE; found_cname = ISC_TRUE; want_chaining = ISC_TRUE; aflag = DNS_RDATASETATTR_ANSWER; result = cname_target(rdataset, &tname); if (result != ISC_R_SUCCESS) return (result); /* Apply filters on the target name. */ if (!is_answertarget_allowed(view, name, rdataset->type, &tname, &fctx->domain)) { return (DNS_R_SERVFAIL); } } else if (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == - dns_rdatatype_cname + dns_rdatatype_cname && !found_type) { /* * We're looking for something else, * but we found a SIG CNAME. */ found = ISC_TRUE; found_cname = ISC_TRUE; aflag = DNS_RDATASETATTR_ANSWERSIG; } if (found) { /* * We've found an answer to our * question. */ name->attributes |= DNS_NAMEATTR_CACHE; rdataset->attributes |= DNS_RDATASETATTR_CACHE; rdataset->trust = dns_trust_answer; if (!chaining) { /* * This data is "the" answer * to our question only if * we're not chaining (i.e. * if we haven't followed * a CNAME or DNAME). */ INSIST(!external); - if (aflag == - DNS_RDATASETATTR_ANSWER) { + if ((rdataset->type != + dns_rdatatype_cname) || + !found_dname || + (aflag == + DNS_RDATASETATTR_ANSWER)) + { have_answer = ISC_TRUE; + if (rdataset->type == + dns_rdatatype_cname) + cname = name; name->attributes |= - DNS_NAMEATTR_ANSWER; + DNS_NAMEATTR_ANSWER; } rdataset->attributes |= aflag; if (aa) rdataset->trust = dns_trust_authanswer; } else if (external) { /* * This data is outside of * our query domain, and * may not be cached. */ rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL; } /* * Mark any additional data related * to this rdataset. */ (void)dns_rdataset_additionaldata( rdataset, check_related, fctx); /* * CNAME chaining. */ if (want_chaining) { wanted_chaining = ISC_TRUE; name->attributes |= DNS_NAMEATTR_CHAINING; rdataset->attributes |= DNS_RDATASETATTR_CHAINING; qname = &tname; } } /* * We could add an "else" clause here and * log that we're ignoring this rdataset. */ } /* * If wanted_chaining is true, we've done * some chaining as the result of processing * this node, and thus we need to set * chaining to true. * * We don't set chaining inside of the * rdataset loop because doing that would * cause us to ignore the signatures of * CNAMEs. */ if (wanted_chaining) chaining = ISC_TRUE; } else { dns_rdataset_t *dnameset = NULL; /* * Look for a DNAME (or its SIG). Anything else is * ignored. */ wanted_chaining = ISC_FALSE; for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { /* * Only pass DNAME or RRSIG(DNAME). */ if (rdataset->type != dns_rdatatype_dname && (rdataset->type != dns_rdatatype_rrsig || rdataset->covers != dns_rdatatype_dname)) continue; /* * If we're not chaining, then the DNAME and * its signature should not be external. */ if (!chaining && external) { char qbuf[DNS_NAME_FORMATSIZE]; char obuf[DNS_NAME_FORMATSIZE]; dns_name_format(name, qbuf, sizeof(qbuf)); dns_name_format(&fctx->domain, obuf, sizeof(obuf)); log_formerr(fctx, "external DNAME or " "RRSIG covering DNAME " "in answer: %s is " "not in %s", qbuf, obuf); return (DNS_R_FORMERR); } - if (namereln != dns_namereln_subdomain) { + if (dnamereln != dns_namereln_subdomain) { char qbuf[DNS_NAME_FORMATSIZE]; char obuf[DNS_NAME_FORMATSIZE]; - dns_name_format(qname, qbuf, + dns_name_format(dqname, qbuf, sizeof(qbuf)); dns_name_format(name, obuf, sizeof(obuf)); log_formerr(fctx, "unrelated DNAME " "in answer: %s is " "not in %s", qbuf, obuf); return (DNS_R_FORMERR); } aflag = 0; if (rdataset->type == dns_rdatatype_dname) { want_chaining = ISC_TRUE; POST(want_chaining); aflag = DNS_RDATASETATTR_ANSWER; - result = dname_target(rdataset, qname, + result = dname_target(rdataset, dqname, nlabels, &fdname); if (result == ISC_R_NOSPACE) { /* * We can't construct the * DNAME target. Do not * try to continue. */ want_chaining = ISC_FALSE; POST(want_chaining); } else if (result != ISC_R_SUCCESS) return (result); else dnameset = rdataset; dname = dns_fixedname_name(&fdname); if (!is_answertarget_allowed(view, - qname, rdataset->type, - dname, &fctx->domain)) { + dqname, rdataset->type, + dname, &fctx->domain)) + { return (DNS_R_SERVFAIL); } + dqname = dns_fixedname_name(&fqdname); + dns_name_copy(dname, dqname, NULL); } else { /* * We've found a signature that * covers the DNAME. */ aflag = DNS_RDATASETATTR_ANSWERSIG; } /* * We've found an answer to our * question. */ name->attributes |= DNS_NAMEATTR_CACHE; rdataset->attributes |= DNS_RDATASETATTR_CACHE; rdataset->trust = dns_trust_answer; if (!chaining) { /* * This data is "the" answer to * our question only if we're * not chaining. */ INSIST(!external); if (aflag == DNS_RDATASETATTR_ANSWER) { have_answer = ISC_TRUE; + found_dname = ISC_TRUE; + if (cname != NULL) + cname->attributes &= + ~DNS_NAMEATTR_ANSWER; name->attributes |= DNS_NAMEATTR_ANSWER; } rdataset->attributes |= aflag; if (aa) rdataset->trust = dns_trust_authanswer; } else if (external) { rdataset->attributes |= DNS_RDATASETATTR_EXTERNAL; } } /* * DNAME chaining. */ if (dnameset != NULL) { /* * Copy the dname into the qname fixed name. * * Although we check for failure of the copy * operation, in practice it should never fail * since we already know that the result fits * in a fixedname. */ dns_fixedname_init(&fqname); qname = dns_fixedname_name(&fqname); result = dns_name_copy(dname, qname, NULL); if (result != ISC_R_SUCCESS) return (result); wanted_chaining = ISC_TRUE; name->attributes |= DNS_NAMEATTR_CHAINING; dnameset->attributes |= DNS_RDATASETATTR_CHAINING; } if (wanted_chaining) chaining = ISC_TRUE; } result = dns_message_nextname(message, DNS_SECTION_ANSWER); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; if (result != ISC_R_SUCCESS) return (result); /* * We should have found an answer. */ if (!have_answer) { log_formerr(fctx, "reply has no answer"); return (DNS_R_FORMERR); } /* * This response is now potentially cacheable. */ fctx->attributes |= FCTX_ATTR_WANTCACHE; /* * Did chaining end before we got the final answer? */ if (chaining) { /* * Yes. This may be a negative reply, so hand off * authority section processing to the noanswer code. * If it isn't a noanswer response, no harm will be * done. */ return (noanswer_response(fctx, qname, 0)); } /* * We didn't end with an incomplete chain, so the rcode should be * "no error". */ if (message->rcode != dns_rcode_noerror) { log_formerr(fctx, "CNAME/DNAME chain complete, but RCODE " "indicates error"); return (DNS_R_FORMERR); } /* * Examine the authority section (if there is one). * * We expect there to be only one owner name for all the rdatasets * in this section, and we expect that it is not external. */ done = ISC_FALSE; ns_name = NULL; ns_rdataset = NULL; result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); while (!done && result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); if (!external) { /* * We expect to find NS or SIG NS rdatasets, and * nothing else. */ for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { if (rdataset->type == dns_rdatatype_ns || (rdataset->type == dns_rdatatype_rrsig && rdataset->covers == dns_rdatatype_ns)) { name->attributes |= DNS_NAMEATTR_CACHE; rdataset->attributes |= DNS_RDATASETATTR_CACHE; if (aa && !chaining) rdataset->trust = dns_trust_authauthority; else rdataset->trust = dns_trust_additional; if (rdataset->type == dns_rdatatype_ns) { ns_name = name; ns_rdataset = rdataset; } /* * Mark any additional data related * to this rdataset. */ (void)dns_rdataset_additionaldata( rdataset, check_related, fctx); done = ISC_TRUE; } } } result = dns_message_nextname(message, DNS_SECTION_AUTHORITY); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; log_ns_ttl(fctx, "answer_response"); if (ns_rdataset != NULL && dns_name_equal(&fctx->domain, ns_name) && !dns_name_equal(ns_name, dns_rootname)) trim_ns_ttl(fctx, ns_name, ns_rdataset); return (result); } static isc_boolean_t fctx_decreference(fetchctx_t *fctx) { isc_boolean_t bucket_empty = ISC_FALSE; INSIST(fctx->references > 0); fctx->references--; if (fctx->references == 0) { /* * No one cares about the result of this fetch anymore. */ if (fctx->pending == 0 && fctx->nqueries == 0 && ISC_LIST_EMPTY(fctx->validators) && SHUTTINGDOWN(fctx)) { /* * This fctx is already shutdown; we were just * waiting for the last reference to go away. */ bucket_empty = fctx_unlink(fctx); fctx_destroy(fctx); } else { /* * Initiate shutdown. */ fctx_shutdown(fctx); } } return (bucket_empty); } static void resume_dslookup(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *fevent; dns_resolver_t *res; fetchctx_t *fctx; isc_result_t result; isc_boolean_t bucket_empty; isc_boolean_t locked = ISC_FALSE; unsigned int bucketnum; dns_rdataset_t nameservers; dns_fixedname_t fixed; dns_name_t *domain; REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); fevent = (dns_fetchevent_t *)event; fctx = event->ev_arg; REQUIRE(VALID_FCTX(fctx)); res = fctx->res; UNUSED(task); FCTXTRACE("resume_dslookup"); if (fevent->node != NULL) dns_db_detachnode(fevent->db, &fevent->node); if (fevent->db != NULL) dns_db_detach(&fevent->db); dns_rdataset_init(&nameservers); bucketnum = fctx->bucketnum; if (fevent->result == ISC_R_CANCELED) { dns_resolver_destroyfetch(&fctx->nsfetch); fctx_done(fctx, ISC_R_CANCELED, __LINE__); } else if (fevent->result == ISC_R_SUCCESS) { FCTXTRACE("resuming DS lookup"); dns_resolver_destroyfetch(&fctx->nsfetch); if (dns_rdataset_isassociated(&fctx->nameservers)) dns_rdataset_disassociate(&fctx->nameservers); dns_rdataset_clone(fevent->rdataset, &fctx->nameservers); fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = ISC_TRUE; log_ns_ttl(fctx, "resume_dslookup"); dns_name_free(&fctx->domain, fctx->mctx); dns_name_init(&fctx->domain, NULL); result = dns_name_dup(&fctx->nsname, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); goto cleanup; } /* * Try again. */ fctx_try(fctx, ISC_TRUE, ISC_FALSE); } else { unsigned int n; dns_rdataset_t *nsrdataset = NULL; /* * Retrieve state from fctx->nsfetch before we destroy it. */ dns_fixedname_init(&fixed); domain = dns_fixedname_name(&fixed); dns_name_copy(&fctx->nsfetch->private->domain, domain, NULL); if (dns_name_equal(&fctx->nsname, domain)) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); dns_resolver_destroyfetch(&fctx->nsfetch); goto cleanup; } if (dns_rdataset_isassociated( &fctx->nsfetch->private->nameservers)) { dns_rdataset_clone( &fctx->nsfetch->private->nameservers, &nameservers); nsrdataset = &nameservers; } else domain = NULL; dns_resolver_destroyfetch(&fctx->nsfetch); n = dns_name_countlabels(&fctx->nsname); dns_name_getlabelsequence(&fctx->nsname, 1, n - 1, &fctx->nsname); if (dns_rdataset_isassociated(fevent->rdataset)) dns_rdataset_disassociate(fevent->rdataset); FCTXTRACE("continuing to look for parent's NS records"); result = dns_resolver_createfetch(fctx->res, &fctx->nsname, dns_rdatatype_ns, domain, nsrdataset, NULL, 0, task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); else { LOCK(&res->buckets[bucketnum].lock); locked = ISC_TRUE; fctx->references++; } } cleanup: if (dns_rdataset_isassociated(&nameservers)) dns_rdataset_disassociate(&nameservers); if (dns_rdataset_isassociated(fevent->rdataset)) dns_rdataset_disassociate(fevent->rdataset); INSIST(fevent->sigrdataset == NULL); isc_event_free(&event); if (!locked) LOCK(&res->buckets[bucketnum].lock); bucket_empty = fctx_decreference(fctx); UNLOCK(&res->buckets[bucketnum].lock); if (bucket_empty) empty_bucket(res); } static inline void checknamessection(dns_message_t *message, dns_section_t section) { isc_result_t result; dns_name_t *name; dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_t *rdataset; for (result = dns_message_firstname(message, section); result == ISC_R_SUCCESS; result = dns_message_nextname(message, section)) { name = NULL; dns_message_currentname(message, section, &name); for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(rdataset)) { dns_rdataset_current(rdataset, &rdata); if (!dns_rdata_checkowner(name, rdata.rdclass, rdata.type, ISC_FALSE) || !dns_rdata_checknames(&rdata, name, NULL)) { rdataset->attributes |= DNS_RDATASETATTR_CHECKNAMES; } dns_rdata_reset(&rdata); } } } } static void checknames(dns_message_t *message) { checknamessection(message, DNS_SECTION_ANSWER); checknamessection(message, DNS_SECTION_AUTHORITY); checknamessection(message, DNS_SECTION_ADDITIONAL); } /* * Log server NSID at log level 'level' */ static void log_nsid(isc_buffer_t *opt, size_t nsid_len, resquery_t *query, int level, isc_mem_t *mctx) { static const char hex[17] = "0123456789abcdef"; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; isc_uint16_t buflen, i; unsigned char *p, *buf, *nsid; /* Allocate buffer for storing hex version of the NSID */ buflen = (isc_uint16_t)nsid_len * 2 + 1; buf = isc_mem_get(mctx, buflen); if (buf == NULL) return; /* Convert to hex */ p = buf; nsid = isc_buffer_current(opt); for (i = 0; i < nsid_len; i++) { *p++ = hex[(nsid[0] >> 4) & 0xf]; *p++ = hex[nsid[0] & 0xf]; nsid++; } *p = '\0'; isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, level, "received NSID '%s' from %s", buf, addrbuf); /* Clean up */ isc_mem_put(mctx, buf, buflen); return; } static void log_packet(dns_message_t *message, int level, isc_mem_t *mctx) { isc_buffer_t buffer; char *buf = NULL; int len = 1024; isc_result_t result; if (! isc_log_wouldlog(dns_lctx, level)) return; /* * Note that these are multiline debug messages. We want a newline * to appear in the log after each message. */ do { buf = isc_mem_get(mctx, len); if (buf == NULL) break; isc_buffer_init(&buffer, buf, len); result = dns_message_totext(message, &dns_master_style_debug, 0, &buffer); if (result == ISC_R_NOSPACE) { isc_mem_put(mctx, buf, len); len += 1024; } else if (result == ISC_R_SUCCESS) isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, level, "received packet:\n%.*s", (int)isc_buffer_usedlength(&buffer), buf); } while (result == ISC_R_NOSPACE); if (buf != NULL) isc_mem_put(mctx, buf, len); } static isc_boolean_t iscname(fetchctx_t *fctx) { isc_result_t result; result = dns_message_findname(fctx->rmessage, DNS_SECTION_ANSWER, &fctx->name, dns_rdatatype_cname, 0, NULL, NULL); return (result == ISC_R_SUCCESS ? ISC_TRUE : ISC_FALSE); } static isc_boolean_t betterreferral(fetchctx_t *fctx) { isc_result_t result; dns_name_t *name; dns_rdataset_t *rdataset; dns_message_t *message = fctx->rmessage; for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); result == ISC_R_SUCCESS; result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) { name = NULL; dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); if (!isstrictsubdomain(name, &fctx->domain)) continue; for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) if (rdataset->type == dns_rdatatype_ns) return (ISC_TRUE); } return (ISC_FALSE); } static void process_opt(resquery_t *query, dns_rdataset_t *opt) { dns_rdata_t rdata; isc_buffer_t optbuf; isc_result_t result; isc_uint16_t optcode; isc_uint16_t optlen; result = dns_rdataset_first(opt); if (result == ISC_R_SUCCESS) { dns_rdata_init(&rdata); dns_rdataset_current(opt, &rdata); isc_buffer_init(&optbuf, rdata.data, rdata.length); isc_buffer_add(&optbuf, rdata.length); while (isc_buffer_remaininglength(&optbuf) >= 4) { optcode = isc_buffer_getuint16(&optbuf); optlen = isc_buffer_getuint16(&optbuf); INSIST(optlen <= isc_buffer_remaininglength(&optbuf)); switch (optcode) { case DNS_OPT_NSID: if (query->options & DNS_FETCHOPT_WANTNSID) log_nsid(&optbuf, optlen, query, ISC_LOG_INFO, query->fctx->res->mctx); isc_buffer_forward(&optbuf, optlen); break; default: isc_buffer_forward(&optbuf, optlen); break; } } INSIST(isc_buffer_remaininglength(&optbuf) == 0U); } } static void resquery_response(isc_task_t *task, isc_event_t *event) { isc_result_t result = ISC_R_SUCCESS; resquery_t *query = event->ev_arg; dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; isc_boolean_t keep_trying, get_nameservers, resend; isc_boolean_t truncated; dns_message_t *message; dns_rdataset_t *opt; fetchctx_t *fctx; dns_name_t *fname; dns_fixedname_t foundname; isc_stdtime_t now; isc_time_t tnow, *finish; dns_adbaddrinfo_t *addrinfo; unsigned int options; unsigned int findoptions; isc_result_t broken_server; badnstype_t broken_type = badns_response; isc_boolean_t no_response; REQUIRE(VALID_QUERY(query)); fctx = query->fctx; options = query->options; REQUIRE(VALID_FCTX(fctx)); REQUIRE(event->ev_type == DNS_EVENT_DISPATCH); QTRACE("response"); if (isc_sockaddr_pf(&query->addrinfo->sockaddr) == PF_INET) inc_stats(fctx->res, dns_resstatscounter_responsev4); else inc_stats(fctx->res, dns_resstatscounter_responsev6); (void)isc_timer_touch(fctx->timer); keep_trying = ISC_FALSE; broken_server = ISC_R_SUCCESS; get_nameservers = ISC_FALSE; resend = ISC_FALSE; truncated = ISC_FALSE; finish = NULL; no_response = ISC_FALSE; if (fctx->res->exiting) { result = ISC_R_SHUTTINGDOWN; goto done; } fctx->timeouts = 0; fctx->timeout = ISC_FALSE; fctx->addrinfo = query->addrinfo; /* * XXXRTH We should really get the current time just once. We * need a routine to convert from an isc_time_t to an * isc_stdtime_t. */ TIME_NOW(&tnow); finish = &tnow; isc_stdtime_get(&now); /* * Did the dispatcher have a problem? */ if (devent->result != ISC_R_SUCCESS) { if (devent->result == ISC_R_EOF && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { /* * The problem might be that they * don't understand EDNS0. Turn it * off and try again. */ options |= DNS_FETCHOPT_NOEDNS0; resend = ISC_TRUE; add_bad_edns(fctx, &query->addrinfo->sockaddr); } else { /* * There's no hope for this query. */ keep_trying = ISC_TRUE; /* * If this is a network error on an exclusive query * socket, mark the server as bad so that we won't try * it for this fetch again. Also adjust finish and * no_response so that we penalize this address in SRTT * adjustment later. */ if (query->exclusivesocket && (devent->result == ISC_R_HOSTUNREACH || devent->result == ISC_R_NETUNREACH || devent->result == ISC_R_CONNREFUSED || devent->result == ISC_R_CANCELED)) { broken_server = devent->result; broken_type = badns_unreachable; finish = NULL; no_response = ISC_TRUE; } } goto done; } message = fctx->rmessage; if (query->tsig != NULL) { result = dns_message_setquerytsig(message, query->tsig); if (result != ISC_R_SUCCESS) goto done; } if (query->tsigkey) { result = dns_message_settsigkey(message, query->tsigkey); if (result != ISC_R_SUCCESS) goto done; } dns_message_setclass(message, fctx->res->rdclass); result = dns_message_parse(message, &devent->buffer, 0); if (result != ISC_R_SUCCESS) { switch (result) { case ISC_R_UNEXPECTEDEND: if (!message->question_ok || (message->flags & DNS_MESSAGEFLAG_TC) == 0 || (options & DNS_FETCHOPT_TCP) != 0) { /* * Either the message ended prematurely, * and/or wasn't marked as being truncated, * and/or this is a response to a query we * sent over TCP. In all of these cases, * something is wrong with the remote * server and we don't want to retry using * TCP. */ if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { /* * The problem might be that they * don't understand EDNS0. Turn it * off and try again. */ options |= DNS_FETCHOPT_NOEDNS0; resend = ISC_TRUE; add_bad_edns(fctx, &query->addrinfo->sockaddr); inc_stats(fctx->res, dns_resstatscounter_edns0fail); } else { broken_server = result; keep_trying = ISC_TRUE; } goto done; } /* * We defer retrying via TCP for a bit so we can * check out this message further. */ truncated = ISC_TRUE; break; case DNS_R_FORMERR: if ((query->options & DNS_FETCHOPT_NOEDNS0) == 0) { /* * The problem might be that they * don't understand EDNS0. Turn it * off and try again. */ options |= DNS_FETCHOPT_NOEDNS0; resend = ISC_TRUE; add_bad_edns(fctx, &query->addrinfo->sockaddr); inc_stats(fctx->res, dns_resstatscounter_edns0fail); } else { broken_server = DNS_R_UNEXPECTEDRCODE; keep_trying = ISC_TRUE; } goto done; default: /* * Something bad has happened. */ goto done; } } /* * Log the incoming packet. */ log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx); if (message->rdclass != fctx->res->rdclass) { resend = ISC_TRUE; FCTXTRACE("bad class"); goto done; } /* * Process receive opt record. */ opt = dns_message_getopt(message); if (opt != NULL) process_opt(query, opt); /* * If the message is signed, check the signature. If not, this * returns success anyway. */ result = dns_message_checksig(message, fctx->res->view); if (result != ISC_R_SUCCESS) goto done; /* * The dispatcher should ensure we only get responses with QR set. */ INSIST((message->flags & DNS_MESSAGEFLAG_QR) != 0); /* * INSIST() that the message comes from the place we sent it to, * since the dispatch code should ensure this. * * INSIST() that the message id is correct (this should also be * ensured by the dispatch code). */ /* * We have an affirmative response to the query and we have * previously got a response from this server which indicated * EDNS may not be supported so we can now cache the lack of * EDNS support. */ if (opt == NULL && (message->rcode == dns_rcode_noerror || message->rcode == dns_rcode_nxdomain || message->rcode == dns_rcode_refused || message->rcode == dns_rcode_yxdomain) && bad_edns(fctx, &query->addrinfo->sockaddr)) { char addrbuf[ISC_SOCKADDR_FORMATSIZE]; isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); dns_adb_changeflags(fctx->adb, query->addrinfo, DNS_FETCHOPT_NOEDNS0, DNS_FETCHOPT_NOEDNS0); } /* * Deal with truncated responses by retrying using TCP. */ if ((message->flags & DNS_MESSAGEFLAG_TC) != 0) truncated = ISC_TRUE; if (truncated) { inc_stats(fctx->res, dns_resstatscounter_truncated); if ((options & DNS_FETCHOPT_TCP) != 0) { broken_server = DNS_R_TRUNCATEDTCP; keep_trying = ISC_TRUE; } else { options |= DNS_FETCHOPT_TCP; resend = ISC_TRUE; } goto done; } /* * Is it a query response? */ if (message->opcode != dns_opcode_query) { /* XXXRTH Log */ broken_server = DNS_R_UNEXPECTEDOPCODE; keep_trying = ISC_TRUE; goto done; } /* * Update statistics about erroneous responses. */ if (message->rcode != dns_rcode_noerror) { switch (message->rcode) { case dns_rcode_nxdomain: inc_stats(fctx->res, dns_resstatscounter_nxdomain); break; case dns_rcode_servfail: inc_stats(fctx->res, dns_resstatscounter_servfail); break; case dns_rcode_formerr: inc_stats(fctx->res, dns_resstatscounter_formerr); break; default: inc_stats(fctx->res, dns_resstatscounter_othererror); break; } } /* * Is the remote server broken, or does it dislike us? */ if (message->rcode != dns_rcode_noerror && message->rcode != dns_rcode_nxdomain) { if (((message->rcode == dns_rcode_formerr || message->rcode == dns_rcode_notimp) || (message->rcode == dns_rcode_servfail && dns_message_getopt(message) == NULL)) && (query->options & DNS_FETCHOPT_NOEDNS0) == 0) { /* * It's very likely they don't like EDNS0. * If the response code is SERVFAIL, also check if the * response contains an OPT RR and don't cache the * failure since it can be returned for various other * reasons. * * XXXRTH We should check if the question * we're asking requires EDNS0, and * if so, we should bail out. */ options |= DNS_FETCHOPT_NOEDNS0; resend = ISC_TRUE; /* * Remember that they may not like EDNS0. */ add_bad_edns(fctx, &query->addrinfo->sockaddr); inc_stats(fctx->res, dns_resstatscounter_edns0fail); } else if (message->rcode == dns_rcode_formerr) { if (ISFORWARDER(query->addrinfo)) { /* * This forwarder doesn't understand us, * but other forwarders might. Keep trying. */ broken_server = DNS_R_REMOTEFORMERR; keep_trying = ISC_TRUE; } else { /* * The server doesn't understand us. Since * all servers for a zone need similar * capabilities, we assume that we will get * FORMERR from all servers, and thus we * cannot make any more progress with this * fetch. */ log_formerr(fctx, "server sent FORMERR"); result = DNS_R_FORMERR; } } else if (message->rcode == dns_rcode_yxdomain) { /* * DNAME mapping failed because the new name * was too long. There's no chance of success * for this fetch. */ result = DNS_R_YXDOMAIN; } else if (message->rcode == dns_rcode_badvers) { unsigned int flags, mask; unsigned int version; resend = ISC_TRUE; INSIST(opt != NULL); version = (opt->ttl >> 16) & 0xff; flags = (version << DNS_FETCHOPT_EDNSVERSIONSHIFT) | DNS_FETCHOPT_EDNSVERSIONSET; mask = DNS_FETCHOPT_EDNSVERSIONMASK | DNS_FETCHOPT_EDNSVERSIONSET; switch (version) { case 0: dns_adb_changeflags(fctx->adb, query->addrinfo, flags, mask); break; default: broken_server = DNS_R_BADVERS; keep_trying = ISC_TRUE; break; } } else { /* * XXXRTH log. */ broken_server = DNS_R_UNEXPECTEDRCODE; INSIST(broken_server != ISC_R_SUCCESS); keep_trying = ISC_TRUE; } goto done; } /* * Is the question the same as the one we asked? */ result = same_question(fctx); if (result != ISC_R_SUCCESS) { /* XXXRTH Log */ if (result == DNS_R_FORMERR) keep_trying = ISC_TRUE; goto done; } /* * Is the server lame? */ if (fctx->res->lame_ttl != 0 && !ISFORWARDER(query->addrinfo) && is_lame(fctx)) { inc_stats(fctx->res, dns_resstatscounter_lame); log_lame(fctx, query->addrinfo); result = dns_adb_marklame(fctx->adb, query->addrinfo, &fctx->name, fctx->type, now + fctx->res->lame_ttl); if (result != ISC_R_SUCCESS) isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_ERROR, "could not mark server as lame: %s", isc_result_totext(result)); broken_server = DNS_R_LAME; keep_trying = ISC_TRUE; goto done; } /* * Enforce delegations only zones like NET and COM. */ if (!ISFORWARDER(query->addrinfo) && dns_view_isdelegationonly(fctx->res->view, &fctx->domain) && !dns_name_equal(&fctx->domain, &fctx->name) && fix_mustbedelegationornxdomain(message, fctx)) { char namebuf[DNS_NAME_FORMATSIZE]; char domainbuf[DNS_NAME_FORMATSIZE]; char addrbuf[ISC_SOCKADDR_FORMATSIZE]; char classbuf[64]; char typebuf[64]; dns_name_format(&fctx->name, namebuf, sizeof(namebuf)); dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); dns_rdatatype_format(fctx->type, typebuf, sizeof(typebuf)); dns_rdataclass_format(fctx->res->rdclass, classbuf, sizeof(classbuf)); isc_sockaddr_format(&query->addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DELEGATION_ONLY, DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, "enforced delegation-only for '%s' (%s/%s/%s) " "from %s", domainbuf, namebuf, typebuf, classbuf, addrbuf); } if ((fctx->res->options & DNS_RESOLVER_CHECKNAMES) != 0) checknames(message); /* * Clear cache bits. */ fctx->attributes &= ~(FCTX_ATTR_WANTNCACHE | FCTX_ATTR_WANTCACHE); /* * Did we get any answers? */ if (message->counts[DNS_SECTION_ANSWER] > 0 && (message->rcode == dns_rcode_noerror || message->rcode == dns_rcode_nxdomain)) { /* * [normal case] * We've got answers. If it has an authoritative answer or an * answer from a forwarder, we're done. */ if ((message->flags & DNS_MESSAGEFLAG_AA) != 0 || ISFORWARDER(query->addrinfo)) result = answer_response(fctx); else if (iscname(fctx) && fctx->type != dns_rdatatype_any && fctx->type != dns_rdatatype_cname) { /* * A BIND8 server could return a non-authoritative * answer when a CNAME is followed. We should treat * it as a valid answer. */ result = answer_response(fctx); } else if (fctx->type != dns_rdatatype_ns && !betterreferral(fctx)) { /* * Lame response !!!. */ result = answer_response(fctx); } else { if (fctx->type == dns_rdatatype_ns) { /* * A BIND 8 server could incorrectly return a * non-authoritative answer to an NS query * instead of a referral. Since this answer * lacks the SIGs necessary to do DNSSEC * validation, we must invoke the following * special kludge to treat it as a referral. */ result = noanswer_response(fctx, NULL, LOOK_FOR_NS_IN_ANSWER); } else { /* * Some other servers may still somehow include * an answer when it should return a referral * with an empty answer. Check to see if we can * treat this as a referral by ignoring the * answer. Further more, there may be an * implementation that moves A/AAAA glue records * to the answer section for that type of * delegation when the query is for that glue * record. LOOK_FOR_GLUE_IN_ANSWER will handle * such a corner case. */ result = noanswer_response(fctx, NULL, LOOK_FOR_GLUE_IN_ANSWER); } if (result != DNS_R_DELEGATION) { /* * At this point, AA is not set, the response * is not a referral, and the server is not a * forwarder. It is technically lame and it's * easier to treat it as such than to figure out * some more elaborate course of action. */ broken_server = DNS_R_LAME; keep_trying = ISC_TRUE; goto done; } goto force_referral; } if (result != ISC_R_SUCCESS) { if (result == DNS_R_FORMERR) keep_trying = ISC_TRUE; goto done; } } else if (message->counts[DNS_SECTION_AUTHORITY] > 0 || message->rcode == dns_rcode_noerror || message->rcode == dns_rcode_nxdomain) { /* * NXDOMAIN, NXRDATASET, or referral. */ result = noanswer_response(fctx, NULL, 0); switch (result) { case ISC_R_SUCCESS: case DNS_R_CHASEDSSERVERS: break; case DNS_R_DELEGATION: force_referral: /* * We don't have the answer, but we know a better * place to look. */ get_nameservers = ISC_TRUE; keep_trying = ISC_TRUE; /* * We have a new set of name servers, and it * has not experienced any restarts yet. */ fctx->restarts = 0; /* * Update local statistics counters collected for each * new zone. */ fctx->referrals++; fctx->querysent = 0; fctx->lamecount = 0; fctx->neterr = 0; fctx->badresp = 0; fctx->adberr = 0; result = ISC_R_SUCCESS; break; default: /* * Something has gone wrong. */ if (result == DNS_R_FORMERR) keep_trying = ISC_TRUE; goto done; } } else { /* * The server is insane. */ /* XXXRTH Log */ broken_server = DNS_R_UNEXPECTEDRCODE; keep_trying = ISC_TRUE; goto done; } /* * Follow additional section data chains. */ chase_additional(fctx); /* * Cache the cacheable parts of the message. This may also cause * work to be queued to the DNSSEC validator. */ if (WANTCACHE(fctx)) { result = cache_message(fctx, query->addrinfo, now); if (result != ISC_R_SUCCESS) goto done; } /* * Ncache the negatively cacheable parts of the message. This may * also cause work to be queued to the DNSSEC validator. */ if (WANTNCACHE(fctx)) { dns_rdatatype_t covers; if (message->rcode == dns_rcode_nxdomain) covers = dns_rdatatype_any; else covers = fctx->type; /* * Cache any negative cache entries in the message. */ result = ncache_message(fctx, query->addrinfo, covers, now); } done: /* * Remember the query's addrinfo, in case we need to mark the * server as broken. */ addrinfo = query->addrinfo; /* * Cancel the query. * * XXXRTH Don't cancel the query if waiting for validation? */ fctx_cancelquery(&query, &devent, finish, no_response); if (keep_trying) { if (result == DNS_R_FORMERR) broken_server = DNS_R_FORMERR; if (broken_server != ISC_R_SUCCESS) { /* * Add this server to the list of bad servers for * this fctx. */ add_bad(fctx, addrinfo, broken_server, broken_type); } if (get_nameservers) { dns_name_t *name; dns_fixedname_init(&foundname); fname = dns_fixedname_name(&foundname); if (result != ISC_R_SUCCESS) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } findoptions = 0; if (dns_rdatatype_atparent(fctx->type)) findoptions |= DNS_DBFIND_NOEXACT; if ((options & DNS_FETCHOPT_UNSHARED) == 0) name = &fctx->name; else name = &fctx->domain; result = dns_view_findzonecut(fctx->res->view, name, fname, now, findoptions, ISC_TRUE, &fctx->nameservers, NULL); if (result != ISC_R_SUCCESS) { FCTXTRACE("couldn't find a zonecut"); fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } if (!dns_name_issubdomain(fname, &fctx->domain)) { /* * The best nameservers are now above our * QDOMAIN. */ FCTXTRACE("nameservers now above QDOMAIN"); fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } dns_name_free(&fctx->domain, fctx->mctx); dns_name_init(&fctx->domain, NULL); result = dns_name_dup(fname, fctx->mctx, &fctx->domain); if (result != ISC_R_SUCCESS) { fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); return; } fctx->ns_ttl = fctx->nameservers.ttl; fctx->ns_ttl_ok = ISC_TRUE; fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupaltfinds(fctx); fctx_cleanupforwaddrs(fctx); fctx_cleanupaltaddrs(fctx); } /* * Try again. */ fctx_try(fctx, !get_nameservers, ISC_FALSE); } else if (resend) { /* * Resend (probably with changed options). */ FCTXTRACE("resend"); inc_stats(fctx->res, dns_resstatscounter_retry); result = fctx_query(fctx, addrinfo, options); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); } else if (result == ISC_R_SUCCESS && !HAVE_ANSWER(fctx)) { /* * All has gone well so far, but we are waiting for the * DNSSEC validator to validate the answer. */ FCTXTRACE("wait for validator"); fctx_cancelqueries(fctx, ISC_TRUE); /* * We must not retransmit while the validator is working; * it has references to the current rmessage. */ result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); } else if (result == DNS_R_CHASEDSSERVERS) { unsigned int n; add_bad(fctx, addrinfo, result, broken_type); fctx_cancelqueries(fctx, ISC_TRUE); fctx_cleanupfinds(fctx); fctx_cleanupforwaddrs(fctx); n = dns_name_countlabels(&fctx->name); dns_name_getlabelsequence(&fctx->name, 1, n - 1, &fctx->nsname); FCTXTRACE("suspending DS lookup to find parent's NS records"); result = dns_resolver_createfetch(fctx->res, &fctx->nsname, dns_rdatatype_ns, NULL, NULL, NULL, 0, task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); else { LOCK(&fctx->res->buckets[fctx->bucketnum].lock); fctx->references++; UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); } } else { /* * We're done. */ fctx_done(fctx, result, __LINE__); } } /*** *** Resolver Methods ***/ static void destroy_badcache(dns_resolver_t *res) { dns_badcache_t *bad, *next; unsigned int i; if (res->badcache != NULL) { for (i = 0; i < res->badhash; i++) for (bad = res->badcache[i]; bad != NULL; bad = next) { next = bad->next; isc_mem_put(res->mctx, bad, sizeof(*bad) + bad->name.length); res->badcount--; } isc_mem_put(res->mctx, res->badcache, sizeof(*res->badcache) * res->badhash); res->badcache = NULL; res->badhash = 0; INSIST(res->badcount == 0); } } static void destroy(dns_resolver_t *res) { unsigned int i; alternate_t *a; REQUIRE(res->references == 0); REQUIRE(!res->priming); REQUIRE(res->primefetch == NULL); RTRACE("destroy"); INSIST(res->nfctx == 0); DESTROYLOCK(&res->primelock); DESTROYLOCK(&res->nlock); DESTROYLOCK(&res->lock); for (i = 0; i < res->nbuckets; i++) { INSIST(ISC_LIST_EMPTY(res->buckets[i].fctxs)); isc_task_shutdown(res->buckets[i].task); isc_task_detach(&res->buckets[i].task); DESTROYLOCK(&res->buckets[i].lock); isc_mem_detach(&res->buckets[i].mctx); } isc_mem_put(res->mctx, res->buckets, res->nbuckets * sizeof(fctxbucket_t)); if (res->dispatches4 != NULL) dns_dispatchset_destroy(&res->dispatches4); if (res->dispatches6 != NULL) dns_dispatchset_destroy(&res->dispatches6); while ((a = ISC_LIST_HEAD(res->alternates)) != NULL) { ISC_LIST_UNLINK(res->alternates, a, link); if (!a->isaddress) dns_name_free(&a->_u._n.name, res->mctx); isc_mem_put(res->mctx, a, sizeof(*a)); } dns_resolver_reset_algorithms(res); destroy_badcache(res); dns_resolver_resetmustbesecure(res); #if USE_ALGLOCK isc_rwlock_destroy(&res->alglock); #endif #if USE_MBSLOCK isc_rwlock_destroy(&res->mbslock); #endif isc_timer_detach(&res->spillattimer); res->magic = 0; isc_mem_put(res->mctx, res, sizeof(*res)); } static void send_shutdown_events(dns_resolver_t *res) { isc_event_t *event, *next_event; isc_task_t *etask; /* * Caller must be holding the resolver lock. */ for (event = ISC_LIST_HEAD(res->whenshutdown); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, ev_link); ISC_LIST_UNLINK(res->whenshutdown, event, ev_link); etask = event->ev_sender; event->ev_sender = res; isc_task_sendanddetach(&etask, &event); } } static void empty_bucket(dns_resolver_t *res) { RTRACE("empty_bucket"); LOCK(&res->lock); INSIST(res->activebuckets > 0); res->activebuckets--; if (res->activebuckets == 0) send_shutdown_events(res); UNLOCK(&res->lock); } static void spillattimer_countdown(isc_task_t *task, isc_event_t *event) { dns_resolver_t *res = event->ev_arg; isc_result_t result; unsigned int count; isc_boolean_t logit = ISC_FALSE; REQUIRE(VALID_RESOLVER(res)); UNUSED(task); LOCK(&res->lock); INSIST(!res->exiting); if (res->spillat > res->spillatmin) { res->spillat--; logit = ISC_TRUE; } if (res->spillat <= res->spillatmin) { result = isc_timer_reset(res->spillattimer, isc_timertype_inactive, NULL, NULL, ISC_TRUE); RUNTIME_CHECK(result == ISC_R_SUCCESS); } count = res->spillat; UNLOCK(&res->lock); if (logit) isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, "clients-per-query decreased to %u", count); isc_event_free(&event); } isc_result_t dns_resolver_create(dns_view_t *view, isc_taskmgr_t *taskmgr, unsigned int ntasks, unsigned int ndisp, isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr, unsigned int options, dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, dns_resolver_t **resp) { dns_resolver_t *res; isc_result_t result = ISC_R_SUCCESS; unsigned int i, buckets_created = 0; isc_task_t *task = NULL; char name[16]; unsigned dispattr; /* * Create a resolver. */ REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(ntasks > 0); REQUIRE(ndisp > 0); REQUIRE(resp != NULL && *resp == NULL); REQUIRE(dispatchmgr != NULL); REQUIRE(dispatchv4 != NULL || dispatchv6 != NULL); res = isc_mem_get(view->mctx, sizeof(*res)); if (res == NULL) return (ISC_R_NOMEMORY); RTRACE("create"); res->mctx = view->mctx; res->rdclass = view->rdclass; res->socketmgr = socketmgr; res->timermgr = timermgr; res->taskmgr = taskmgr; res->dispatchmgr = dispatchmgr; res->view = view; res->options = options; res->lame_ttl = 0; ISC_LIST_INIT(res->alternates); res->udpsize = RECV_BUFFER_SIZE; res->algorithms = NULL; res->badcache = NULL; res->badcount = 0; res->badhash = 0; res->badsweep = 0; res->mustbesecure = NULL; res->spillatmin = res->spillat = 10; res->spillatmax = 100; res->spillattimer = NULL; res->zero_no_soa_ttl = ISC_FALSE; res->query_timeout = DEFAULT_QUERY_TIMEOUT; res->maxdepth = DEFAULT_RECURSION_DEPTH; res->nbuckets = ntasks; res->activebuckets = ntasks; res->buckets = isc_mem_get(view->mctx, ntasks * sizeof(fctxbucket_t)); if (res->buckets == NULL) { result = ISC_R_NOMEMORY; goto cleanup_res; } for (i = 0; i < ntasks; i++) { result = isc_mutex_init(&res->buckets[i].lock); if (result != ISC_R_SUCCESS) goto cleanup_buckets; res->buckets[i].task = NULL; result = isc_task_create(taskmgr, 0, &res->buckets[i].task); if (result != ISC_R_SUCCESS) { DESTROYLOCK(&res->buckets[i].lock); goto cleanup_buckets; } res->buckets[i].mctx = NULL; snprintf(name, sizeof(name), "res%u", i); #ifdef ISC_PLATFORM_USETHREADS /* * Use a separate memory context for each bucket to reduce * contention among multiple threads. Do this only when * enabling threads because it will be require more memory. */ result = isc_mem_create(0, 0, &res->buckets[i].mctx); if (result != ISC_R_SUCCESS) { isc_task_detach(&res->buckets[i].task); DESTROYLOCK(&res->buckets[i].lock); goto cleanup_buckets; } isc_mem_setname(res->buckets[i].mctx, name, NULL); #else isc_mem_attach(view->mctx, &res->buckets[i].mctx); #endif isc_task_setname(res->buckets[i].task, name, res); ISC_LIST_INIT(res->buckets[i].fctxs); res->buckets[i].exiting = ISC_FALSE; buckets_created++; } res->dispatches4 = NULL; if (dispatchv4 != NULL) { dns_dispatchset_create(view->mctx, socketmgr, taskmgr, dispatchv4, &res->dispatches4, ndisp); dispattr = dns_dispatch_getattributes(dispatchv4); res->exclusivev4 = ISC_TF((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0); } res->dispatches6 = NULL; if (dispatchv6 != NULL) { dns_dispatchset_create(view->mctx, socketmgr, taskmgr, dispatchv6, &res->dispatches6, ndisp); dispattr = dns_dispatch_getattributes(dispatchv6); res->exclusivev6 = ISC_TF((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0); } res->references = 1; res->exiting = ISC_FALSE; res->frozen = ISC_FALSE; ISC_LIST_INIT(res->whenshutdown); res->priming = ISC_FALSE; res->primefetch = NULL; res->nfctx = 0; result = isc_mutex_init(&res->lock); if (result != ISC_R_SUCCESS) goto cleanup_dispatches; result = isc_mutex_init(&res->nlock); if (result != ISC_R_SUCCESS) goto cleanup_lock; result = isc_mutex_init(&res->primelock); if (result != ISC_R_SUCCESS) goto cleanup_nlock; task = NULL; result = isc_task_create(taskmgr, 0, &task); if (result != ISC_R_SUCCESS) goto cleanup_primelock; result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, task, spillattimer_countdown, res, &res->spillattimer); isc_task_detach(&task); if (result != ISC_R_SUCCESS) goto cleanup_primelock; #if USE_ALGLOCK result = isc_rwlock_init(&res->alglock, 0, 0); if (result != ISC_R_SUCCESS) goto cleanup_spillattimer; #endif #if USE_MBSLOCK result = isc_rwlock_init(&res->mbslock, 0, 0); if (result != ISC_R_SUCCESS) goto cleanup_alglock; #endif res->magic = RES_MAGIC; *resp = res; return (ISC_R_SUCCESS); #if USE_MBSLOCK cleanup_alglock: #if USE_ALGLOCK isc_rwlock_destroy(&res->alglock); #endif #endif #if USE_ALGLOCK || USE_MBSLOCK cleanup_spillattimer: isc_timer_detach(&res->spillattimer); #endif cleanup_primelock: DESTROYLOCK(&res->primelock); cleanup_nlock: DESTROYLOCK(&res->nlock); cleanup_lock: DESTROYLOCK(&res->lock); cleanup_dispatches: if (res->dispatches6 != NULL) dns_dispatchset_destroy(&res->dispatches6); if (res->dispatches4 != NULL) dns_dispatchset_destroy(&res->dispatches4); cleanup_buckets: for (i = 0; i < buckets_created; i++) { isc_mem_detach(&res->buckets[i].mctx); DESTROYLOCK(&res->buckets[i].lock); isc_task_shutdown(res->buckets[i].task); isc_task_detach(&res->buckets[i].task); } isc_mem_put(view->mctx, res->buckets, res->nbuckets * sizeof(fctxbucket_t)); cleanup_res: isc_mem_put(view->mctx, res, sizeof(*res)); return (result); } #ifdef BIND9 static void prime_done(isc_task_t *task, isc_event_t *event) { dns_resolver_t *res; dns_fetchevent_t *fevent; dns_fetch_t *fetch; dns_db_t *db = NULL; REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE); fevent = (dns_fetchevent_t *)event; res = event->ev_arg; REQUIRE(VALID_RESOLVER(res)); UNUSED(task); LOCK(&res->lock); INSIST(res->priming); res->priming = ISC_FALSE; LOCK(&res->primelock); fetch = res->primefetch; res->primefetch = NULL; UNLOCK(&res->primelock); UNLOCK(&res->lock); if (fevent->result == ISC_R_SUCCESS && res->view->cache != NULL && res->view->hints != NULL) { dns_cache_attachdb(res->view->cache, &db); dns_root_checkhints(res->view, res->view->hints, db); dns_db_detach(&db); } if (fevent->node != NULL) dns_db_detachnode(fevent->db, &fevent->node); if (fevent->db != NULL) dns_db_detach(&fevent->db); if (dns_rdataset_isassociated(fevent->rdataset)) dns_rdataset_disassociate(fevent->rdataset); INSIST(fevent->sigrdataset == NULL); isc_mem_put(res->mctx, fevent->rdataset, sizeof(*fevent->rdataset)); isc_event_free(&event); dns_resolver_destroyfetch(&fetch); } void dns_resolver_prime(dns_resolver_t *res) { isc_boolean_t want_priming = ISC_FALSE; dns_rdataset_t *rdataset; isc_result_t result; REQUIRE(VALID_RESOLVER(res)); REQUIRE(res->frozen); RTRACE("dns_resolver_prime"); LOCK(&res->lock); if (!res->exiting && !res->priming) { INSIST(res->primefetch == NULL); res->priming = ISC_TRUE; want_priming = ISC_TRUE; } UNLOCK(&res->lock); if (want_priming) { /* * To avoid any possible recursive locking problems, we * start the priming fetch like any other fetch, and holding * no resolver locks. No one else will try to start it * because we're the ones who set res->priming to true. * Any other callers of dns_resolver_prime() while we're * running will see that res->priming is already true and * do nothing. */ RTRACE("priming"); rdataset = isc_mem_get(res->mctx, sizeof(*rdataset)); if (rdataset == NULL) { LOCK(&res->lock); INSIST(res->priming); INSIST(res->primefetch == NULL); res->priming = ISC_FALSE; UNLOCK(&res->lock); return; } dns_rdataset_init(rdataset); LOCK(&res->primelock); result = dns_resolver_createfetch(res, dns_rootname, dns_rdatatype_ns, NULL, NULL, NULL, 0, res->buckets[0].task, prime_done, res, rdataset, NULL, &res->primefetch); UNLOCK(&res->primelock); if (result != ISC_R_SUCCESS) { LOCK(&res->lock); INSIST(res->priming); res->priming = ISC_FALSE; UNLOCK(&res->lock); } } } #endif /* BIND9 */ void dns_resolver_freeze(dns_resolver_t *res) { /* * Freeze resolver. */ REQUIRE(VALID_RESOLVER(res)); res->frozen = ISC_TRUE; } void dns_resolver_attach(dns_resolver_t *source, dns_resolver_t **targetp) { REQUIRE(VALID_RESOLVER(source)); REQUIRE(targetp != NULL && *targetp == NULL); RRTRACE(source, "attach"); LOCK(&source->lock); REQUIRE(!source->exiting); INSIST(source->references > 0); source->references++; INSIST(source->references != 0); UNLOCK(&source->lock); *targetp = source; } void dns_resolver_whenshutdown(dns_resolver_t *res, isc_task_t *task, isc_event_t **eventp) { isc_task_t *clone; isc_event_t *event; REQUIRE(VALID_RESOLVER(res)); REQUIRE(eventp != NULL); event = *eventp; *eventp = NULL; LOCK(&res->lock); if (res->exiting && res->activebuckets == 0) { /* * We're already shutdown. Send the event. */ event->ev_sender = res; isc_task_send(task, &event); } else { clone = NULL; isc_task_attach(task, &clone); event->ev_sender = clone; ISC_LIST_APPEND(res->whenshutdown, event, ev_link); } UNLOCK(&res->lock); } void dns_resolver_shutdown(dns_resolver_t *res) { unsigned int i; fetchctx_t *fctx; isc_result_t result; REQUIRE(VALID_RESOLVER(res)); RTRACE("shutdown"); LOCK(&res->lock); if (!res->exiting) { RTRACE("exiting"); res->exiting = ISC_TRUE; for (i = 0; i < res->nbuckets; i++) { LOCK(&res->buckets[i].lock); for (fctx = ISC_LIST_HEAD(res->buckets[i].fctxs); fctx != NULL; fctx = ISC_LIST_NEXT(fctx, link)) fctx_shutdown(fctx); if (res->dispatches4 != NULL && !res->exclusivev4) { dns_dispatchset_cancelall(res->dispatches4, res->buckets[i].task); } if (res->dispatches6 != NULL && !res->exclusivev6) { dns_dispatchset_cancelall(res->dispatches6, res->buckets[i].task); } res->buckets[i].exiting = ISC_TRUE; if (ISC_LIST_EMPTY(res->buckets[i].fctxs)) { INSIST(res->activebuckets > 0); res->activebuckets--; } UNLOCK(&res->buckets[i].lock); } if (res->activebuckets == 0) send_shutdown_events(res); result = isc_timer_reset(res->spillattimer, isc_timertype_inactive, NULL, NULL, ISC_TRUE); RUNTIME_CHECK(result == ISC_R_SUCCESS); } UNLOCK(&res->lock); } void dns_resolver_detach(dns_resolver_t **resp) { dns_resolver_t *res; isc_boolean_t need_destroy = ISC_FALSE; REQUIRE(resp != NULL); res = *resp; REQUIRE(VALID_RESOLVER(res)); RTRACE("detach"); LOCK(&res->lock); INSIST(res->references > 0); res->references--; if (res->references == 0) { INSIST(res->exiting && res->activebuckets == 0); need_destroy = ISC_TRUE; } UNLOCK(&res->lock); if (need_destroy) destroy(res); *resp = NULL; } static inline isc_boolean_t fctx_match(fetchctx_t *fctx, dns_name_t *name, dns_rdatatype_t type, unsigned int options) { /* * Don't match fetch contexts that are shutting down. */ if (fctx->cloned || fctx->state == fetchstate_done || ISC_LIST_EMPTY(fctx->events)) return (ISC_FALSE); if (fctx->type != type || fctx->options != options) return (ISC_FALSE); return (dns_name_equal(&fctx->name, name)); } static inline void log_fetch(dns_name_t *name, dns_rdatatype_t type) { char namebuf[DNS_NAME_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; int level = ISC_LOG_DEBUG(1); if (! isc_log_wouldlog(dns_lctx, level)) return; dns_name_format(name, namebuf, sizeof(namebuf)); dns_rdatatype_format(type, typebuf, sizeof(typebuf)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, DNS_LOGMODULE_RESOLVER, level, "createfetch: %s %s", namebuf, typebuf); } isc_result_t dns_resolver_createfetch(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_name_t *domain, dns_rdataset_t *nameservers, dns_forwarders_t *forwarders, unsigned int options, isc_task_t *task, isc_taskaction_t action, void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_fetch_t **fetchp) { return (dns_resolver_createfetch3(res, name, type, domain, nameservers, forwarders, NULL, 0, options, 0, task, action, arg, rdataset, sigrdataset, fetchp)); } isc_result_t dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_name_t *domain, dns_rdataset_t *nameservers, dns_forwarders_t *forwarders, isc_sockaddr_t *client, dns_messageid_t id, unsigned int options, isc_task_t *task, isc_taskaction_t action, void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_fetch_t **fetchp) { return (dns_resolver_createfetch3(res, name, type, domain, nameservers, forwarders, client, id, options, 0, task, action, arg, rdataset, sigrdataset, fetchp)); } isc_result_t dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, dns_name_t *domain, dns_rdataset_t *nameservers, dns_forwarders_t *forwarders, isc_sockaddr_t *client, dns_messageid_t id, unsigned int options, unsigned int depth, isc_task_t *task, isc_taskaction_t action, void *arg, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, dns_fetch_t **fetchp) { dns_fetch_t *fetch; fetchctx_t *fctx = NULL; isc_result_t result = ISC_R_SUCCESS; unsigned int bucketnum; isc_boolean_t new_fctx = ISC_FALSE; isc_event_t *event; unsigned int count = 0; unsigned int spillat; unsigned int spillatmin; isc_boolean_t destroy = ISC_FALSE; UNUSED(forwarders); REQUIRE(VALID_RESOLVER(res)); REQUIRE(res->frozen); /* XXXRTH Check for meta type */ if (domain != NULL) { REQUIRE(DNS_RDATASET_VALID(nameservers)); REQUIRE(nameservers->type == dns_rdatatype_ns); } else REQUIRE(nameservers == NULL); REQUIRE(forwarders == NULL); REQUIRE(!dns_rdataset_isassociated(rdataset)); REQUIRE(sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)); REQUIRE(fetchp != NULL && *fetchp == NULL); log_fetch(name, type); /* * XXXRTH use a mempool? */ fetch = isc_mem_get(res->mctx, sizeof(*fetch)); if (fetch == NULL) return (ISC_R_NOMEMORY); bucketnum = dns_name_fullhash(name, ISC_FALSE) % res->nbuckets; LOCK(&res->lock); spillat = res->spillat; spillatmin = res->spillatmin; UNLOCK(&res->lock); LOCK(&res->buckets[bucketnum].lock); if (res->buckets[bucketnum].exiting) { result = ISC_R_SHUTTINGDOWN; goto unlock; } if ((options & DNS_FETCHOPT_UNSHARED) == 0) { for (fctx = ISC_LIST_HEAD(res->buckets[bucketnum].fctxs); fctx != NULL; fctx = ISC_LIST_NEXT(fctx, link)) { if (fctx_match(fctx, name, type, options)) break; } } /* * Is this a duplicate? */ if (fctx != NULL && client != NULL) { dns_fetchevent_t *fevent; for (fevent = ISC_LIST_HEAD(fctx->events); fevent != NULL; fevent = ISC_LIST_NEXT(fevent, ev_link)) { if (fevent->client != NULL && fevent->id == id && isc_sockaddr_equal(fevent->client, client)) { result = DNS_R_DUPLICATE; goto unlock; } count++; } } if (count >= spillatmin && spillatmin != 0) { INSIST(fctx != NULL); if (count >= spillat) fctx->spilled = ISC_TRUE; if (fctx->spilled) { result = DNS_R_DROP; goto unlock; } } if (fctx == NULL) { result = fctx_create(res, name, type, domain, nameservers, options, bucketnum, depth, &fctx); if (result != ISC_R_SUCCESS) goto unlock; new_fctx = ISC_TRUE; } else if (fctx->depth > depth) fctx->depth = depth; result = fctx_join(fctx, task, client, id, action, arg, rdataset, sigrdataset, fetch); if (new_fctx) { if (result == ISC_R_SUCCESS) { /* * Launch this fctx. */ event = &fctx->control_event; ISC_EVENT_INIT(event, sizeof(*event), 0, NULL, DNS_EVENT_FETCHCONTROL, fctx_start, fctx, NULL, NULL, NULL); isc_task_send(res->buckets[bucketnum].task, &event); } else { /* * We don't care about the result of fctx_unlink() * since we know we're not exiting. */ (void)fctx_unlink(fctx); destroy = ISC_TRUE; } } unlock: UNLOCK(&res->buckets[bucketnum].lock); if (destroy) fctx_destroy(fctx); if (result == ISC_R_SUCCESS) { FTRACE("created"); *fetchp = fetch; } else isc_mem_put(res->mctx, fetch, sizeof(*fetch)); return (result); } void dns_resolver_cancelfetch(dns_fetch_t *fetch) { fetchctx_t *fctx; dns_resolver_t *res; dns_fetchevent_t *event, *next_event; isc_task_t *etask; REQUIRE(DNS_FETCH_VALID(fetch)); fctx = fetch->private; REQUIRE(VALID_FCTX(fctx)); res = fctx->res; FTRACE("cancelfetch"); LOCK(&res->buckets[fctx->bucketnum].lock); /* * Find the completion event for this fetch (as opposed * to those for other fetches that have joined the same * fctx) and send it with result = ISC_R_CANCELED. */ event = NULL; if (fctx->state != fetchstate_done) { for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, ev_link); if (event->fetch == fetch) { ISC_LIST_UNLINK(fctx->events, event, ev_link); break; } } } if (event != NULL) { etask = event->ev_sender; event->ev_sender = fctx; event->result = ISC_R_CANCELED; isc_task_sendanddetach(&etask, ISC_EVENT_PTR(&event)); } /* * The fctx continues running even if no fetches remain; * the answer is still cached. */ UNLOCK(&res->buckets[fctx->bucketnum].lock); } void dns_resolver_destroyfetch(dns_fetch_t **fetchp) { dns_fetch_t *fetch; dns_resolver_t *res; dns_fetchevent_t *event, *next_event; fetchctx_t *fctx; unsigned int bucketnum; isc_boolean_t bucket_empty; REQUIRE(fetchp != NULL); fetch = *fetchp; REQUIRE(DNS_FETCH_VALID(fetch)); fctx = fetch->private; REQUIRE(VALID_FCTX(fctx)); res = fctx->res; FTRACE("destroyfetch"); bucketnum = fctx->bucketnum; LOCK(&res->buckets[bucketnum].lock); /* * Sanity check: the caller should have gotten its event before * trying to destroy the fetch. */ event = NULL; if (fctx->state != fetchstate_done) { for (event = ISC_LIST_HEAD(fctx->events); event != NULL; event = next_event) { next_event = ISC_LIST_NEXT(event, ev_link); RUNTIME_CHECK(event->fetch != fetch); } } bucket_empty = fctx_decreference(fctx); UNLOCK(&res->buckets[bucketnum].lock); isc_mem_put(res->mctx, fetch, sizeof(*fetch)); *fetchp = NULL; if (bucket_empty) empty_bucket(res); } void dns_resolver_logfetch(dns_fetch_t *fetch, isc_log_t *lctx, isc_logcategory_t *category, isc_logmodule_t *module, int level, isc_boolean_t duplicateok) { fetchctx_t *fctx; dns_resolver_t *res; char domainbuf[DNS_NAME_FORMATSIZE]; REQUIRE(DNS_FETCH_VALID(fetch)); fctx = fetch->private; REQUIRE(VALID_FCTX(fctx)); res = fctx->res; LOCK(&res->buckets[fctx->bucketnum].lock); INSIST(fctx->exitline >= 0); if (!fctx->logged || duplicateok) { dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); isc_log_write(lctx, category, module, level, "fetch completed at %s:%d for %s in " "%" ISC_PRINT_QUADFORMAT "u." "%06" ISC_PRINT_QUADFORMAT "u: %s/%s " "[domain:%s,referral:%u,restart:%u,qrysent:%u," "timeout:%u,lame:%u,neterr:%u,badresp:%u," "adberr:%u,findfail:%u,valfail:%u]", __FILE__, fctx->exitline, fctx->info, fctx->duration / US_PER_SEC, fctx->duration % US_PER_SEC, isc_result_totext(fctx->result), isc_result_totext(fctx->vresult), domainbuf, fctx->referrals, fctx->restarts, fctx->querysent, fctx->timeouts, fctx->lamecount, fctx->neterr, fctx->badresp, fctx->adberr, fctx->findfail, fctx->valfail); fctx->logged = ISC_TRUE; } UNLOCK(&res->buckets[fctx->bucketnum].lock); } dns_dispatchmgr_t * dns_resolver_dispatchmgr(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->dispatchmgr); } dns_dispatch_t * dns_resolver_dispatchv4(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (dns_dispatchset_get(resolver->dispatches4)); } dns_dispatch_t * dns_resolver_dispatchv6(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (dns_dispatchset_get(resolver->dispatches6)); } isc_socketmgr_t * dns_resolver_socketmgr(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->socketmgr); } isc_taskmgr_t * dns_resolver_taskmgr(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->taskmgr); } isc_uint32_t dns_resolver_getlamettl(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->lame_ttl); } void dns_resolver_setlamettl(dns_resolver_t *resolver, isc_uint32_t lame_ttl) { REQUIRE(VALID_RESOLVER(resolver)); resolver->lame_ttl = lame_ttl; } unsigned int dns_resolver_nrunning(dns_resolver_t *resolver) { unsigned int n; LOCK(&resolver->nlock); n = resolver->nfctx; UNLOCK(&resolver->nlock); return (n); } isc_result_t dns_resolver_addalternate(dns_resolver_t *resolver, isc_sockaddr_t *alt, dns_name_t *name, in_port_t port) { alternate_t *a; isc_result_t result; REQUIRE(VALID_RESOLVER(resolver)); REQUIRE(!resolver->frozen); REQUIRE((alt == NULL) ^ (name == NULL)); a = isc_mem_get(resolver->mctx, sizeof(*a)); if (a == NULL) return (ISC_R_NOMEMORY); if (alt != NULL) { a->isaddress = ISC_TRUE; a->_u.addr = *alt; } else { a->isaddress = ISC_FALSE; a->_u._n.port = port; dns_name_init(&a->_u._n.name, NULL); result = dns_name_dup(name, resolver->mctx, &a->_u._n.name); if (result != ISC_R_SUCCESS) { isc_mem_put(resolver->mctx, a, sizeof(*a)); return (result); } } ISC_LINK_INIT(a, link); ISC_LIST_APPEND(resolver->alternates, a, link); return (ISC_R_SUCCESS); } void dns_resolver_setudpsize(dns_resolver_t *resolver, isc_uint16_t udpsize) { REQUIRE(VALID_RESOLVER(resolver)); resolver->udpsize = udpsize; } isc_uint16_t dns_resolver_getudpsize(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->udpsize); } void dns_resolver_flushbadcache(dns_resolver_t *resolver, dns_name_t *name) { unsigned int i; dns_badcache_t *bad, *prev, *next; REQUIRE(VALID_RESOLVER(resolver)); LOCK(&resolver->lock); if (resolver->badcache == NULL) goto unlock; if (name != NULL) { isc_time_t now; isc_result_t result; result = isc_time_now(&now); if (result != ISC_R_SUCCESS) isc_time_settoepoch(&now); i = dns_name_hash(name, ISC_FALSE) % resolver->badhash; prev = NULL; for (bad = resolver->badcache[i]; bad != NULL; bad = next) { int n; next = bad->next; n = isc_time_compare(&bad->expire, &now); if (n < 0 || dns_name_equal(name, &bad->name)) { if (prev == NULL) resolver->badcache[i] = bad->next; else prev->next = bad->next; isc_mem_put(resolver->mctx, bad, sizeof(*bad) + bad->name.length); resolver->badcount--; } else prev = bad; } } else destroy_badcache(resolver); unlock: UNLOCK(&resolver->lock); } static void resizehash(dns_resolver_t *resolver, isc_time_t *now, isc_boolean_t grow) { unsigned int newsize; dns_badcache_t **new, *bad, *next; unsigned int i; if (grow) newsize = resolver->badhash * 2 + 1; else newsize = (resolver->badhash - 1) / 2; new = isc_mem_get(resolver->mctx, sizeof(*resolver->badcache) * newsize); if (new == NULL) return; memset(new, 0, sizeof(*resolver->badcache) * newsize); for (i = 0; i < resolver->badhash; i++) { for (bad = resolver->badcache[i]; bad != NULL; bad = next) { next = bad->next; if (isc_time_compare(&bad->expire, now) < 0) { isc_mem_put(resolver->mctx, bad, sizeof(*bad) + bad->name.length); resolver->badcount--; } else { bad->next = new[bad->hashval % newsize]; new[bad->hashval % newsize] = bad; } } } isc_mem_put(resolver->mctx, resolver->badcache, sizeof(*resolver->badcache) * resolver->badhash); resolver->badhash = newsize; resolver->badcache = new; } void dns_resolver_addbadcache(dns_resolver_t *resolver, dns_name_t *name, dns_rdatatype_t type, isc_time_t *expire) { isc_time_t now; isc_result_t result = ISC_R_SUCCESS; unsigned int i, hashval; dns_badcache_t *bad, *prev, *next; REQUIRE(VALID_RESOLVER(resolver)); LOCK(&resolver->lock); if (resolver->badcache == NULL) { resolver->badcache = isc_mem_get(resolver->mctx, sizeof(*resolver->badcache) * DNS_BADCACHE_SIZE); if (resolver->badcache == NULL) goto cleanup; resolver->badhash = DNS_BADCACHE_SIZE; memset(resolver->badcache, 0, sizeof(*resolver->badcache) * resolver->badhash); } result = isc_time_now(&now); if (result != ISC_R_SUCCESS) isc_time_settoepoch(&now); hashval = dns_name_hash(name, ISC_FALSE); i = hashval % resolver->badhash; prev = NULL; for (bad = resolver->badcache[i]; bad != NULL; bad = next) { next = bad->next; if (bad->type == type && dns_name_equal(name, &bad->name)) break; if (isc_time_compare(&bad->expire, &now) < 0) { if (prev == NULL) resolver->badcache[i] = bad->next; else prev->next = bad->next; isc_mem_put(resolver->mctx, bad, sizeof(*bad) + bad->name.length); resolver->badcount--; } else prev = bad; } if (bad == NULL) { isc_buffer_t buffer; bad = isc_mem_get(resolver->mctx, sizeof(*bad) + name->length); if (bad == NULL) goto cleanup; bad->type = type; bad->hashval = hashval; bad->expire = *expire; isc_buffer_init(&buffer, bad + 1, name->length); dns_name_init(&bad->name, NULL); dns_name_copy(name, &bad->name, &buffer); bad->next = resolver->badcache[i]; resolver->badcache[i] = bad; resolver->badcount++; if (resolver->badcount > resolver->badhash * 8) resizehash(resolver, &now, ISC_TRUE); if (resolver->badcount < resolver->badhash * 2 && resolver->badhash > DNS_BADCACHE_SIZE) resizehash(resolver, &now, ISC_FALSE); } else bad->expire = *expire; cleanup: UNLOCK(&resolver->lock); } isc_boolean_t dns_resolver_getbadcache(dns_resolver_t *resolver, dns_name_t *name, dns_rdatatype_t type, isc_time_t *now) { dns_badcache_t *bad, *prev, *next; isc_boolean_t answer = ISC_FALSE; unsigned int i; REQUIRE(VALID_RESOLVER(resolver)); LOCK(&resolver->lock); if (resolver->badcache == NULL) goto unlock; i = dns_name_hash(name, ISC_FALSE) % resolver->badhash; prev = NULL; for (bad = resolver->badcache[i]; bad != NULL; bad = next) { next = bad->next; /* * Search the hash list. Clean out expired records as we go. */ if (isc_time_compare(&bad->expire, now) < 0) { if (prev != NULL) prev->next = bad->next; else resolver->badcache[i] = bad->next; isc_mem_put(resolver->mctx, bad, sizeof(*bad) + bad->name.length); resolver->badcount--; continue; } if (bad->type == type && dns_name_equal(name, &bad->name)) { answer = ISC_TRUE; break; } prev = bad; } /* * Slow sweep to clean out stale records. */ i = resolver->badsweep++ % resolver->badhash; bad = resolver->badcache[i]; if (bad != NULL && isc_time_compare(&bad->expire, now) < 0) { resolver->badcache[i] = bad->next; isc_mem_put(resolver->mctx, bad, sizeof(*bad) + bad->name.length); resolver->badcount--; } unlock: UNLOCK(&resolver->lock); return (answer); } void dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp) { char namebuf[DNS_NAME_FORMATSIZE]; char typebuf[DNS_RDATATYPE_FORMATSIZE]; dns_badcache_t *bad, *next, *prev; isc_time_t now; unsigned int i; isc_uint64_t t; LOCK(&resolver->lock); fprintf(fp, ";\n; Bad cache\n;\n"); if (resolver->badcache == NULL) goto unlock; TIME_NOW(&now); for (i = 0; i < resolver->badhash; i++) { prev = NULL; for (bad = resolver->badcache[i]; bad != NULL; bad = next) { next = bad->next; if (isc_time_compare(&bad->expire, &now) < 0) { if (prev != NULL) prev->next = bad->next; else resolver->badcache[i] = bad->next; isc_mem_put(resolver->mctx, bad, sizeof(*bad) + bad->name.length); resolver->badcount--; continue; } prev = bad; dns_name_format(&bad->name, namebuf, sizeof(namebuf)); dns_rdatatype_format(bad->type, typebuf, sizeof(typebuf)); t = isc_time_microdiff(&bad->expire, &now); t /= 1000; fprintf(fp, "; %s/%s [ttl " "%" ISC_PLATFORM_QUADFORMAT "u]\n", namebuf, typebuf, t); } } unlock: UNLOCK(&resolver->lock); } static void free_algorithm(void *node, void *arg) { unsigned char *algorithms = node; isc_mem_t *mctx = arg; isc_mem_put(mctx, algorithms, *algorithms); } void dns_resolver_reset_algorithms(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); #if USE_ALGLOCK RWLOCK(&resolver->alglock, isc_rwlocktype_write); #endif if (resolver->algorithms != NULL) dns_rbt_destroy(&resolver->algorithms); #if USE_ALGLOCK RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); #endif } isc_result_t dns_resolver_disable_algorithm(dns_resolver_t *resolver, dns_name_t *name, unsigned int alg) { unsigned int len, mask; unsigned char *new; unsigned char *algorithms; isc_result_t result; dns_rbtnode_t *node = NULL; REQUIRE(VALID_RESOLVER(resolver)); if (alg > 255) return (ISC_R_RANGE); #if USE_ALGLOCK RWLOCK(&resolver->alglock, isc_rwlocktype_write); #endif if (resolver->algorithms == NULL) { result = dns_rbt_create(resolver->mctx, free_algorithm, resolver->mctx, &resolver->algorithms); if (result != ISC_R_SUCCESS) goto cleanup; } len = alg/8 + 2; mask = 1 << (alg%8); result = dns_rbt_addnode(resolver->algorithms, name, &node); if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) { algorithms = node->data; if (algorithms == NULL || len > *algorithms) { new = isc_mem_get(resolver->mctx, len); if (new == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } memset(new, 0, len); if (algorithms != NULL) memmove(new, algorithms, *algorithms); new[len-1] |= mask; *new = len; node->data = new; if (algorithms != NULL) isc_mem_put(resolver->mctx, algorithms, *algorithms); } else algorithms[len-1] |= mask; } result = ISC_R_SUCCESS; cleanup: #if USE_ALGLOCK RWUNLOCK(&resolver->alglock, isc_rwlocktype_write); #endif return (result); } isc_boolean_t dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name, unsigned int alg) { unsigned int len, mask; unsigned char *algorithms; void *data = NULL; isc_result_t result; isc_boolean_t found = ISC_FALSE; REQUIRE(VALID_RESOLVER(resolver)); /* * DH is unsupported for DNSKEYs, see RFC 4034 sec. A.1. */ if ((alg == DST_ALG_DH) || (alg == DST_ALG_INDIRECT)) return (ISC_FALSE); #if USE_ALGLOCK RWLOCK(&resolver->alglock, isc_rwlocktype_read); #endif if (resolver->algorithms == NULL) goto unlock; result = dns_rbt_findname(resolver->algorithms, name, 0, NULL, &data); if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { len = alg/8 + 2; mask = 1 << (alg%8); algorithms = data; if (len <= *algorithms && (algorithms[len-1] & mask) != 0) found = ISC_TRUE; } unlock: #if USE_ALGLOCK RWUNLOCK(&resolver->alglock, isc_rwlocktype_read); #endif if (found) return (ISC_FALSE); return (dst_algorithm_supported(alg)); } isc_boolean_t dns_resolver_digest_supported(dns_resolver_t *resolver, unsigned int digest) { UNUSED(resolver); return (dns_ds_digest_supported(digest)); } void dns_resolver_resetmustbesecure(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); #if USE_MBSLOCK RWLOCK(&resolver->mbslock, isc_rwlocktype_write); #endif if (resolver->mustbesecure != NULL) dns_rbt_destroy(&resolver->mustbesecure); #if USE_MBSLOCK RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write); #endif } static isc_boolean_t yes = ISC_TRUE, no = ISC_FALSE; isc_result_t dns_resolver_setmustbesecure(dns_resolver_t *resolver, dns_name_t *name, isc_boolean_t value) { isc_result_t result; REQUIRE(VALID_RESOLVER(resolver)); #if USE_MBSLOCK RWLOCK(&resolver->mbslock, isc_rwlocktype_write); #endif if (resolver->mustbesecure == NULL) { result = dns_rbt_create(resolver->mctx, NULL, NULL, &resolver->mustbesecure); if (result != ISC_R_SUCCESS) goto cleanup; } result = dns_rbt_addname(resolver->mustbesecure, name, value ? &yes : &no); cleanup: #if USE_MBSLOCK RWUNLOCK(&resolver->mbslock, isc_rwlocktype_write); #endif return (result); } isc_boolean_t dns_resolver_getmustbesecure(dns_resolver_t *resolver, dns_name_t *name) { void *data = NULL; isc_boolean_t value = ISC_FALSE; isc_result_t result; REQUIRE(VALID_RESOLVER(resolver)); #if USE_MBSLOCK RWLOCK(&resolver->mbslock, isc_rwlocktype_read); #endif if (resolver->mustbesecure == NULL) goto unlock; result = dns_rbt_findname(resolver->mustbesecure, name, 0, NULL, &data); if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) value = *(isc_boolean_t*)data; unlock: #if USE_MBSLOCK RWUNLOCK(&resolver->mbslock, isc_rwlocktype_read); #endif return (value); } void dns_resolver_getclientsperquery(dns_resolver_t *resolver, isc_uint32_t *cur, isc_uint32_t *min, isc_uint32_t *max) { REQUIRE(VALID_RESOLVER(resolver)); LOCK(&resolver->lock); if (cur != NULL) *cur = resolver->spillat; if (min != NULL) *min = resolver->spillatmin; if (max != NULL) *max = resolver->spillatmax; UNLOCK(&resolver->lock); } void dns_resolver_setclientsperquery(dns_resolver_t *resolver, isc_uint32_t min, isc_uint32_t max) { REQUIRE(VALID_RESOLVER(resolver)); LOCK(&resolver->lock); resolver->spillatmin = resolver->spillat = min; resolver->spillatmax = max; UNLOCK(&resolver->lock); } isc_boolean_t dns_resolver_getzeronosoattl(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->zero_no_soa_ttl); } void dns_resolver_setzeronosoattl(dns_resolver_t *resolver, isc_boolean_t state) { REQUIRE(VALID_RESOLVER(resolver)); resolver->zero_no_soa_ttl = state; } unsigned int dns_resolver_getoptions(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->options); } unsigned int dns_resolver_gettimeout(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->query_timeout); } void dns_resolver_settimeout(dns_resolver_t *resolver, unsigned int seconds) { REQUIRE(VALID_RESOLVER(resolver)); if (seconds == 0) seconds = DEFAULT_QUERY_TIMEOUT; if (seconds > MAXIMUM_QUERY_TIMEOUT) seconds = MAXIMUM_QUERY_TIMEOUT; if (seconds < MINIMUM_QUERY_TIMEOUT) seconds = MINIMUM_QUERY_TIMEOUT; resolver->query_timeout = seconds; } void dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth) { REQUIRE(VALID_RESOLVER(resolver)); resolver->maxdepth = maxdepth; } unsigned int dns_resolver_getmaxdepth(dns_resolver_t *resolver) { REQUIRE(VALID_RESOLVER(resolver)); return (resolver->maxdepth); } Index: releng/9.3/crypto/openssl/ssl/d1_pkt.c =================================================================== --- releng/9.3/crypto/openssl/ssl/d1_pkt.c (revision 308204) +++ releng/9.3/crypto/openssl/ssl/d1_pkt.c (revision 308205) @@ -1,1864 +1,1879 @@ /* ssl/d1_pkt.c */ /* * DTLS implementation written by Nagendra Modadugu * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. */ /* ==================================================================== * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include #define USE_SOCKETS #include "ssl_locl.h" #include #include #include #include static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, int len, int peek); static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap); static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap); static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch); #if 0 static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority, unsigned long *offset); #endif static int dtls1_buffer_record(SSL *s, record_pqueue *q, PQ_64BIT * priority); static int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap); #if PQ_64BIT_IS_INTEGER static PQ_64BIT bytes_to_long_long(unsigned char *bytes, PQ_64BIT * num); #endif /* copy buffered record into SSL structure */ static int dtls1_copy_record(SSL *s, pitem *item) { DTLS1_RECORD_DATA *rdata; rdata = (DTLS1_RECORD_DATA *)item->data; if (s->s3->rbuf.buf != NULL) OPENSSL_free(s->s3->rbuf.buf); s->packet = rdata->packet; s->packet_length = rdata->packet_length; memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER)); memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD)); /* Set proper sequence number for mac calculation */ memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6); return (1); } static int dtls1_buffer_record(SSL *s, record_pqueue *queue, PQ_64BIT * priority) { DTLS1_RECORD_DATA *rdata; pitem *item; /* Limit the size of the queue to prevent DOS attacks */ if (pqueue_size(queue->q) >= 100) return 0; rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA)); item = pitem_new(*priority, rdata); if (rdata == NULL || item == NULL) { if (rdata != NULL) OPENSSL_free(rdata); if (item != NULL) pitem_free(item); SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); return (0); } rdata->packet = s->packet; rdata->packet_length = s->packet_length; memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER)); memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD)); item->data = rdata; /* insert should not fail, since duplicates are dropped */ if (pqueue_insert(queue->q, item) == NULL) { OPENSSL_free(rdata); pitem_free(item); return (0); } s->packet = NULL; s->packet_length = 0; memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER)); memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD)); if (!ssl3_setup_buffers(s)) { SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); OPENSSL_free(rdata); pitem_free(item); return (0); } return (1); } static int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue) { pitem *item; item = pqueue_pop(queue->q); if (item) { dtls1_copy_record(s, item); OPENSSL_free(item->data); pitem_free(item); return (1); } return (0); } /* * retrieve a buffered record that belongs to the new epoch, i.e., not * processed yet */ #define dtls1_get_unprocessed_record(s) \ dtls1_retrieve_buffered_record((s), \ &((s)->d1->unprocessed_rcds)) /* * retrieve a buffered record that belongs to the current epoch, ie, * processed */ #define dtls1_get_processed_record(s) \ dtls1_retrieve_buffered_record((s), \ &((s)->d1->processed_rcds)) static int dtls1_process_buffered_records(SSL *s) { pitem *item; SSL3_BUFFER *rb; SSL3_RECORD *rr; DTLS1_BITMAP *bitmap; unsigned int is_next_epoch; int replayok = 1; item = pqueue_peek(s->d1->unprocessed_rcds.q); if (item) { /* Check if epoch is current. */ if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch) return 1; /* Nothing to do. */ rr = &s->s3->rrec; rb = &s->s3->rbuf; if (rb->left > 0) { /* * We've still got data from the current packet to read. There could * be a record from the new epoch in it - so don't overwrite it * with the unprocessed records yet (we'll do it when we've * finished reading the current packet). */ return 1; } /* Process all the records. */ while (pqueue_peek(s->d1->unprocessed_rcds.q)) { dtls1_get_unprocessed_record(s); bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); if (bitmap == NULL) { /* * Should not happen. This will only ever be NULL when the * current record is from a different epoch. But that cannot * be the case because we already checked the epoch above */ SSLerr(SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS, ERR_R_INTERNAL_ERROR); return 0; } { /* * Check whether this is a repeat, or aged record. We did this * check once already when we first received the record - but * we might have updated the window since then due to * records we subsequently processed. */ replayok = dtls1_record_replay_check(s, bitmap); } if (!replayok || !dtls1_process_record(s, bitmap)) { /* dump this record */ rr->length = 0; s->packet_length = 0; continue; } if (dtls1_buffer_record(s, &(s->d1->processed_rcds), &s->s3->rrec.seq_num) < 0) return 0; } } /* * sync epoch numbers once all the unprocessed records have been * processed */ s->d1->processed_rcds.epoch = s->d1->r_epoch; s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1; return 1; } #if 0 static int dtls1_get_buffered_record(SSL *s) { pitem *item; PQ_64BIT priority = (((PQ_64BIT) s->d1->handshake_read_seq) << 32) | ((PQ_64BIT) s->d1->r_msg_hdr.frag_off); /* if we're not (re)negotiating, nothing buffered */ if (!SSL_in_init(s)) return 0; item = pqueue_peek(s->d1->rcvd_records); if (item && item->priority == priority) { /* * Check if we've received the record of interest. It must be a * handshake record, since data records as passed up without * buffering */ DTLS1_RECORD_DATA *rdata; item = pqueue_pop(s->d1->rcvd_records); rdata = (DTLS1_RECORD_DATA *)item->data; if (s->s3->rbuf.buf != NULL) OPENSSL_free(s->s3->rbuf.buf); s->packet = rdata->packet; s->packet_length = rdata->packet_length; memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER)); memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD)); OPENSSL_free(item->data); pitem_free(item); /* s->d1->next_expected_seq_num++; */ return (1); } return 0; } #endif static int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap) { int i, al; int enc_err; SSL_SESSION *sess; SSL3_RECORD *rr; unsigned int mac_size, orig_len; unsigned char md[EVP_MAX_MD_SIZE]; rr = &(s->s3->rrec); sess = s->session; /* * At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, * and we have that many bytes in s->packet */ rr->input = &(s->packet[DTLS1_RT_HEADER_LENGTH]); /* * ok, we can now read from 's->packet' data into 'rr' rr->input points * at rr->length bytes, which need to be copied into rr->data by either * the decryption or by the decompression When the data is 'copied' into * the rr->data buffer, rr->input will be pointed at the new buffer */ /* * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length * bytes of encrypted compressed stuff. */ /* check is not needed I believe */ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { al = SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); goto f_err; } /* decrypt in place in 'rr->input' */ rr->data = rr->input; enc_err = s->method->ssl3_enc->enc(s, 0); /*- * enc_err is: * 0: (in non-constant time) if the record is publically invalid. * 1: if the padding is valid * -1: if the padding is invalid */ if (enc_err == 0) { /* For DTLS we simply ignore bad packets. */ rr->length = 0; s->packet_length = 0; goto err; } #ifdef TLS_DEBUG printf("dec %d\n", rr->length); { unsigned int z; for (z = 0; z < rr->length; z++) printf("%02X%c", rr->data[z], ((z + 1) % 16) ? ' ' : '\n'); } printf("\n"); #endif /* r->length is now the compressed data plus mac */ if ((sess != NULL) && (s->enc_read_ctx != NULL) && (s->read_hash != NULL)) { /* s->read_hash != NULL => mac_size != -1 */ unsigned char *mac = NULL; unsigned char mac_tmp[EVP_MAX_MD_SIZE]; mac_size = EVP_MD_size(s->read_hash); OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); /* * kludge: *_cbc_remove_padding passes padding length in rr->type */ orig_len = rr->length + ((unsigned int)rr->type >> 8); /* * orig_len is the length of the record before any padding was * removed. This is public information, as is the MAC in use, * therefore we can safely process the record in a different amount * of time if it's too short to possibly contain a MAC. */ if (orig_len < mac_size || /* CBC records must have a padding length byte too. */ (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE && orig_len < mac_size + 1)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_LENGTH_TOO_SHORT); goto f_err; } if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) { /* * We update the length so that the TLS header bytes can be * constructed correctly but we need to extract the MAC in * constant time from within the record, without leaking the * contents of the padding bytes. */ mac = mac_tmp; ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len); rr->length -= mac_size; } else { /* * In this case there's no padding, so |orig_len| equals * |rec->length| and we checked that there's enough bytes for * |mac_size| above. */ rr->length -= mac_size; mac = &rr->data[rr->length]; } i = s->method->ssl3_enc->mac(s, md, 0 /* not send */ ); if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) enc_err = -1; if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) enc_err = -1; } if (enc_err < 0) { /* decryption failed, silently discard message */ rr->length = 0; s->packet_length = 0; goto err; } /* r->length is now just compressed */ if (s->expand != NULL) { if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) { al = SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_COMPRESSED_LENGTH_TOO_LONG); goto f_err; } if (!ssl3_do_uncompress(s)) { al = SSL_AD_DECOMPRESSION_FAILURE; SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_BAD_DECOMPRESSION); goto f_err; } } if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) { al = SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_DATA_LENGTH_TOO_LONG); goto f_err; } rr->off = 0; /*- * So at this point the following is true * ssl->s3->rrec.type is the type of record * ssl->s3->rrec.length == number of bytes in record * ssl->s3->rrec.off == offset to first valid byte * ssl->s3->rrec.data == where to take bytes from, increment * after use :-). */ /* we have pulled in a full packet so zero things */ s->packet_length = 0; /* Mark receipt of record. */ dtls1_record_bitmap_update(s, bitmap); return (1); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); err: return (0); } /*- * Call this to get a new input record. * It will return <= 0 if more data is needed, normally due to an error * or non-blocking IO. * When it finishes, one packet has been decoded and can be found in * ssl->s3->rrec.type - is the type of record * ssl->s3->rrec.data, - data * ssl->s3->rrec.length, - number of bytes */ /* used only by dtls1_read_bytes */ int dtls1_get_record(SSL *s) { int ssl_major, ssl_minor; int i, n; SSL3_RECORD *rr; unsigned char *p = NULL; unsigned short version; DTLS1_BITMAP *bitmap; unsigned int is_next_epoch; rr = &(s->s3->rrec); again: /* * The epoch may have changed. If so, process all the pending records. * This is a non-blocking operation. */ dtls1_process_buffered_records(s); /* if we're renegotiating, then there may be buffered records */ if (dtls1_get_processed_record(s)) return 1; /* get something from the wire */ /* check if we have the header */ if ((s->rstate != SSL_ST_READ_BODY) || (s->packet_length < DTLS1_RT_HEADER_LENGTH)) { n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0); /* read timeout is handled by dtls1_read_bytes */ if (n <= 0) return (n); /* error or non-blocking */ /* this packet contained a partial record, dump it */ if (s->packet_length != DTLS1_RT_HEADER_LENGTH) { s->packet_length = 0; goto again; } s->rstate = SSL_ST_READ_BODY; p = s->packet; /* Pull apart the header into the DTLS1_RECORD */ rr->type = *(p++); ssl_major = *(p++); ssl_minor = *(p++); version = (ssl_major << 8) | ssl_minor; /* sequence number is 64 bits, with top 2 bytes = epoch */ n2s(p, rr->epoch); memcpy(&(s->s3->read_sequence[2]), p, 6); p += 6; n2s(p, rr->length); /* Lets check version */ if (!s->first_packet) { if (version != s->version && version != DTLS1_BAD_VER) { /* unexpected version, silently discard */ rr->length = 0; s->packet_length = 0; goto again; } } if ((version & 0xff00) != (DTLS1_VERSION & 0xff00) && (version & 0xff00) != (DTLS1_BAD_VER & 0xff00)) { /* wrong version, silently discard record */ rr->length = 0; s->packet_length = 0; goto again; } if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { /* record too long, silently discard it */ rr->length = 0; s->packet_length = 0; goto again; } s->client_version = version; /* now s->rstate == SSL_ST_READ_BODY */ } /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ if (rr->length > s->packet_length - DTLS1_RT_HEADER_LENGTH) { /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */ i = rr->length; n = ssl3_read_n(s, i, i, 1); /* this packet contained a partial record, dump it */ if (n != i) { rr->length = 0; s->packet_length = 0; goto again; } /* * now n == rr->length, and s->packet_length == * DTLS1_RT_HEADER_LENGTH + rr->length */ } s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ /* match epochs. NULL means the packet is dropped on the floor */ bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); if (bitmap == NULL) { rr->length = 0; s->packet_length = 0; /* dump this record */ goto again; /* get another record */ } /* * Check whether this is a repeat, or aged record. Don't check if we're * listening and this message is a ClientHello. They can look as if * they're replayed, since they arrive from different connections and * would be dropped unnecessarily. */ if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE && s->packet_length > DTLS1_RT_HEADER_LENGTH && s->packet[DTLS1_RT_HEADER_LENGTH] == SSL3_MT_CLIENT_HELLO) && !dtls1_record_replay_check(s, bitmap)) { rr->length = 0; s->packet_length = 0; /* dump this record */ goto again; /* get another record */ } /* just read a 0 length packet */ if (rr->length == 0) goto again; /* * If this record is from the next epoch (either HM or ALERT), and a * handshake is currently in progress, buffer it since it cannot be * processed at this time. However, do not buffer anything while * listening. */ if (is_next_epoch) { if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) { if (dtls1_buffer_record (s, &(s->d1->unprocessed_rcds), &rr->seq_num) < 0) return -1; } rr->length = 0; s->packet_length = 0; goto again; } if (!dtls1_process_record(s, bitmap)) { rr->length = 0; s->packet_length = 0; /* dump this record */ goto again; /* get another record */ } return (1); } /*- * Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: * * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) * - 0 (during a shutdown, no data has to be returned) * * If we don't have stored data to work from, read a SSL/TLS record first * (possibly multiple records if we still don't have anything to return). * * This function must handle any surprises the peer may have for us, such as * Alert records (e.g. close_notify), ChangeCipherSpec records (not really * a surprise, but handled as if it were), or renegotiation requests. * Also if record payloads contain fragments too small to process, we store * them until there is enough for the respective protocol (the record protocol * may use arbitrary fragmentation and even interleaving): * Change cipher spec protocol * just 1 byte needed, no need for keeping anything stored * Alert protocol * 2 bytes needed (AlertLevel, AlertDescription) * Handshake protocol * 4 bytes needed (HandshakeType, uint24 length) -- we just have * to detect unexpected Client Hello and Hello Request messages * here, anything else is handled by higher layers * Application data protocol * none of our business */ int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) { int al, i, j, ret; unsigned int n; SSL3_RECORD *rr; void (*cb) (const SSL *ssl, int type2, int val) = NULL; if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ if (!ssl3_setup_buffers(s)) return (-1); /* XXX: check what the second '&& type' is about */ if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE) && type) || (peek && (type != SSL3_RT_APPLICATION_DATA))) { SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } /* * check whether there's a handshake message (client hello?) waiting */ if ((ret = have_handshake_fragment(s, type, buf, len, peek))) return ret; /* * Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */ if (!s->in_handshake && SSL_in_init(s)) { /* type == SSL3_RT_APPLICATION_DATA */ i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } } start: s->rwstate = SSL_NOTHING; /*- * s->s3->rrec.type - is the type of record * s->s3->rrec.data, - data * s->s3->rrec.off, - offset into 'data' for next read * s->s3->rrec.length, - number of bytes. */ rr = &(s->s3->rrec); /* * We are not handshaking and have no data yet, so process data buffered * during the last handshake in advance, if any. */ if (s->state == SSL_ST_OK && rr->length == 0) { pitem *item; item = pqueue_pop(s->d1->buffered_app_data.q); if (item) { dtls1_copy_record(s, item); OPENSSL_free(item->data); pitem_free(item); } } /* Check for timeout */ if (dtls1_handle_timeout(s) > 0) goto start; /* get new packet if necessary */ if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY)) { ret = dtls1_get_record(s); if (ret <= 0) { ret = dtls1_read_failed(s, ret); /* anything other than a timeout is an error */ if (ret <= 0) return (ret); else goto start; } } if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE) { rr->length = 0; goto start; } + /* + * Reset the count of consecutive warning alerts if we've got a non-empty + * record that isn't an alert. + */ + if (rr->type != SSL3_RT_ALERT && rr->length != 0) + s->s3->alert_count = 0; + /* we now have a packet which can be read and processed */ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, * reset by ssl3_get_finished */ && (rr->type != SSL3_RT_HANDSHAKE)) { /* * We now have application data between CCS and Finished. Most likely * the packets were reordered on their way, so buffer the application * data for later processing rather than dropping the connection. */ dtls1_buffer_record(s, &(s->d1->buffered_app_data), &rr->seq_num); rr->length = 0; goto start; } /* * If the other end has shut down, throw anything we read away (even in * 'peek' mode) */ if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { rr->length = 0; s->rwstate = SSL_NOTHING; return (0); } if (type == rr->type) { /* SSL3_RT_APPLICATION_DATA or * SSL3_RT_HANDSHAKE */ /* * make sure that we are not getting application data when we are * doing a handshake for the first time */ if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) && (s->enc_read_ctx == NULL)) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_APP_DATA_IN_HANDSHAKE); goto f_err; } if (len <= 0) return (len); if ((unsigned int)len > rr->length) n = rr->length; else n = (unsigned int)len; memcpy(buf, &(rr->data[rr->off]), n); if (!peek) { rr->length -= n; rr->off += n; if (rr->length == 0) { s->rstate = SSL_ST_READ_HEADER; rr->off = 0; } } return (n); } /* * If we get here, then type != rr->type; if we have a handshake message, * then it was unexpected (Hello Request or Client Hello). */ /* * In case of record types for which we have 'fragment' storage, fill * that so that we can process the data at a fixed place. */ { unsigned int k, dest_maxlen = 0; unsigned char *dest = NULL; unsigned int *dest_len = NULL; if (rr->type == SSL3_RT_HANDSHAKE) { dest_maxlen = sizeof s->d1->handshake_fragment; dest = s->d1->handshake_fragment; dest_len = &s->d1->handshake_fragment_len; } else if (rr->type == SSL3_RT_ALERT) { dest_maxlen = sizeof(s->d1->alert_fragment); dest = s->d1->alert_fragment; dest_len = &s->d1->alert_fragment_len; } /* else it's a CCS message, or application data or wrong */ else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { /* * Application data while renegotiating is allowed. Try again * reading. */ if (rr->type == SSL3_RT_APPLICATION_DATA) { BIO *bio; s->s3->in_read_app_data = 2; bio = SSL_get_rbio(s); s->rwstate = SSL_READING; BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } /* Not certain if this is the right error handling */ al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; } if (dest_maxlen > 0) { /* * XDTLS: In a pathalogical case, the Client Hello may be * fragmented--don't always expect dest_maxlen bytes */ if (rr->length < dest_maxlen) { #ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE /* * for normal alerts rr->length is 2, while * dest_maxlen is 7 if we were to handle this * non-existing alert... */ FIX ME #endif s->rstate = SSL_ST_READ_HEADER; rr->length = 0; goto start; } /* now move 'n' bytes: */ for (k = 0; k < dest_maxlen; k++) { dest[k] = rr->data[rr->off++]; rr->length--; } *dest_len = dest_maxlen; } } /*- * s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE; * s->d1->alert_fragment_len == 7 iff rr->type == SSL3_RT_ALERT. * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ /* If we are a client, check for an incoming 'Hello Request': */ if ((!s->server) && (s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && (s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && (s->session != NULL) && (s->session->cipher != NULL)) { s->d1->handshake_fragment_len = 0; if ((s->d1->handshake_fragment[1] != 0) || (s->d1->handshake_fragment[2] != 0) || (s->d1->handshake_fragment[3] != 0)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_HELLO_REQUEST); goto err; } /* * no need to check sequence number on HELLO REQUEST messages */ if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->d1->handshake_fragment, 4, s, s->msg_callback_arg); if (SSL_is_init_finished(s) && !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && !s->s3->renegotiate) { s->d1->handshake_read_seq++; ssl3_renegotiate(s); if (ssl3_renegotiate_check(s)) { i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (s->s3->rbuf.left == 0) { /* no read-ahead left? */ BIO *bio; /* * In the case where we try to read application data, * but we trigger an SSL handshake, we return -1 with * the retry option set. Otherwise renegotiation may * cause nasty problems in the blocking world */ s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } } } } /* * we either finished a handshake or ignored the request, now try * again to obtain the (application) data we were asked for */ goto start; } if (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) { int alert_level = s->d1->alert_fragment[0]; int alert_descr = s->d1->alert_fragment[1]; s->d1->alert_fragment_len = 0; if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_ALERT, s->d1->alert_fragment, 2, s, s->msg_callback_arg); if (s->info_callback != NULL) cb = s->info_callback; else if (s->ctx->info_callback != NULL) cb = s->ctx->info_callback; if (cb != NULL) { j = (alert_level << 8) | alert_descr; cb(s, SSL_CB_READ_ALERT, j); } if (alert_level == 1) { /* warning */ s->s3->warn_alert = alert_descr; + + s->s3->alert_count++; + if (s->s3->alert_count == MAX_WARN_ALERT_COUNT) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS); + goto f_err; + } + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { s->shutdown |= SSL_RECEIVED_SHUTDOWN; return (0); } #if 0 /* XXX: this is a possible improvement in the future */ /* now check if it's a missing record */ if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) { unsigned short seq; unsigned int frag_off; unsigned char *p = &(s->d1->alert_fragment[2]); n2s(p, seq); n2l3(p, frag_off); dtls1_retransmit_message(s, dtls1_get_queue_priority (frag->msg_header.seq, 0), frag_off, &found); if (!found && SSL_in_init(s)) { /* * fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */ /* * requested a message not yet sent, send an alert * ourselves */ ssl3_send_alert(s, SSL3_AL_WARNING, DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); } } #endif } else if (alert_level == 2) { /* fatal */ char tmp[16]; s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; SSL_CTX_remove_session(s->ctx, s->session); return (0); } else { al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); goto f_err; } goto start; } if (s->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a * shutdown */ s->rwstate = SSL_NOTHING; rr->length = 0; return (0); } if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { struct ccs_header_st ccs_hdr; unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH; dtls1_get_ccs_header(rr->data, &ccs_hdr); /* * 'Change Cipher Spec' is just a single byte, so we know exactly * what the record payload has to look like */ /* XDTLS: check that epoch is consistent */ if (s->client_version == DTLS1_BAD_VER || s->version == DTLS1_BAD_VER) ccs_hdr_len = 3; if ((rr->length != ccs_hdr_len) || (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS)) { i = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_CHANGE_CIPHER_SPEC); goto err; } rr->length = 0; if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg); /* * We can't process a CCS now, because previous handshake messages * are still missing, so just drop it. */ if (!s->d1->change_cipher_spec_ok) { goto start; } s->d1->change_cipher_spec_ok = 0; s->s3->change_cipher_spec = 1; if (!ssl3_do_change_cipher_spec(s)) goto err; /* do this whenever CCS is processed */ dtls1_reset_seq_numbers(s, SSL3_CC_READ); if (s->client_version == DTLS1_BAD_VER) s->d1->handshake_read_seq++; goto start; } /* * Unexpected handshake message (Client Hello, or protocol violation) */ if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && !s->in_handshake) { struct hm_header_st msg_hdr; /* this may just be a stale retransmit */ dtls1_get_message_header(rr->data, &msg_hdr); if (rr->epoch != s->d1->r_epoch) { rr->length = 0; goto start; } /* * If we are server, we may have a repeated FINISHED of the client * here, then retransmit our CCS and FINISHED. */ if (msg_hdr.type == SSL3_MT_FINISHED) { if (dtls1_check_timeout_num(s) < 0) return -1; dtls1_retransmit_buffered_messages(s); rr->length = 0; goto start; } if (((s->state & SSL_ST_MASK) == SSL_ST_OK) && !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { #if 0 /* worked only because C operator preferences * are not as expected (and because this is * not really needed for clients except for * detecting protocol violations): */ s->state = SSL_ST_BEFORE | (s->server) ? SSL_ST_ACCEPT : SSL_ST_CONNECT; #else s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; #endif s->new_session = 1; } i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (s->s3->rbuf.left == 0) { /* no read-ahead left? */ BIO *bio; /* * In the case where we try to read application data, but we * trigger an SSL handshake, we return -1 with the retry * option set. Otherwise renegotiation may cause nasty * problems in the blocking world */ s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } } goto start; } switch (rr->type) { default: #ifndef OPENSSL_NO_TLS /* TLS just ignores unknown message types */ if (s->version == TLS1_VERSION) { rr->length = 0; goto start; } #endif al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; case SSL3_RT_CHANGE_CIPHER_SPEC: case SSL3_RT_ALERT: case SSL3_RT_HANDSHAKE: /* * we already handled all of these, with the possible exception of * SSL3_RT_HANDSHAKE when s->in_handshake is set, but that should not * happen when type != rr->type */ al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); goto f_err; case SSL3_RT_APPLICATION_DATA: /* * At this point, we were expecting handshake data, but have * application data. If the library was running inside ssl3_read() * (i.e. in_read_app_data is set) and it makes sense to read * application data at this point (session renegotiation not yet * started), we will indulge it. */ if (s->s3->in_read_app_data && (s->s3->total_renegotiations != 0) && (((s->state & SSL_ST_CONNECT) && (s->state >= SSL3_ST_CW_CLNT_HELLO_A) && (s->state <= SSL3_ST_CR_SRVR_HELLO_A) ) || ((s->state & SSL_ST_ACCEPT) && (s->state <= SSL3_ST_SW_HELLO_REQ_A) && (s->state >= SSL3_ST_SR_CLNT_HELLO_A) ) )) { s->s3->in_read_app_data = 2; return (-1); } else { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; } } /* not reached */ f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); err: return (-1); } int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) { int i; if (SSL_in_init(s) && !s->in_handshake) { i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } if (len > SSL3_RT_MAX_PLAIN_LENGTH) { SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_DTLS_MESSAGE_TOO_BIG); return -1; } i = dtls1_write_bytes(s, type, buf_, len); return i; } /* * this only happens when a client hello is received and a handshake * is started. */ static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, int len, int peek) { if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0)) /* (partially) satisfy request from storage */ { unsigned char *src = s->d1->handshake_fragment; unsigned char *dst = buf; unsigned int k, n; /* peek == 0 */ n = 0; while ((len > 0) && (s->d1->handshake_fragment_len > 0)) { *dst++ = *src++; len--; s->d1->handshake_fragment_len--; n++; } /* move any remaining fragment bytes: */ for (k = 0; k < s->d1->handshake_fragment_len; k++) s->d1->handshake_fragment[k] = *src++; return n; } return 0; } /* * Call this to write data in records of type 'type' It will return <= 0 if * not all data has been sent or non-blocking IO. */ int dtls1_write_bytes(SSL *s, int type, const void *buf, int len) { int i; OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); s->rwstate = SSL_NOTHING; i = do_dtls1_write(s, type, buf, len, 0); return i; } int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment) { unsigned char *p, *pseq; int i, mac_size, clear = 0; int prefix_len = 0; SSL3_RECORD *wr; SSL3_BUFFER *wb; SSL_SESSION *sess; int bs; /* * first check if there is a SSL3_BUFFER still being written out. This * will happen with non blocking IO */ if (s->s3->wbuf.left != 0) { OPENSSL_assert(0); /* XDTLS: want to see if we ever get here */ return (ssl3_write_pending(s, type, buf, len)); } /* If we have an alert to send, lets send it */ if (s->s3->alert_dispatch) { i = s->method->ssl_dispatch_alert(s); if (i <= 0) return (i); /* if it went, fall through and send more stuff */ } if (len == 0 && !create_empty_fragment) return 0; wr = &(s->s3->wrec); wb = &(s->s3->wbuf); sess = s->session; if ((sess == NULL) || (s->enc_write_ctx == NULL) || (s->write_hash == NULL)) clear = 1; if (clear) mac_size = 0; else mac_size = EVP_MD_size(s->write_hash); /* DTLS implements explicit IV, so no need for empty fragments */ #if 0 /* * 'create_empty_fragment' is true only when this function calls itself */ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) { /* * countermeasure against known-IV weakness in CBC ciphersuites (see * http://www.openssl.org/~bodo/tls-cbc.txt) */ if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA) { /* * recursive function call with 'create_empty_fragment' set; this * prepares and buffers the data for an empty fragment (these * 'prefix_len' bytes are sent out later together with the actual * payload) */ prefix_len = s->method->do_ssl_write(s, type, buf, 0, 1); if (prefix_len <= 0) goto err; if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE) { /* insufficient space */ SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR); goto err; } } s->s3->empty_fragment_done = 1; } #endif p = wb->buf + prefix_len; /* write the header */ *(p++) = type & 0xff; wr->type = type; if (s->client_version == DTLS1_BAD_VER) *(p++) = DTLS1_BAD_VER >> 8, *(p++) = DTLS1_BAD_VER & 0xff; else *(p++) = (s->version >> 8), *(p++) = s->version & 0xff; /* field where we are to write out packet epoch, seq num and len */ pseq = p; p += 10; /* lets setup the record stuff. */ /* * Make space for the explicit IV in case of CBC. (this is a bit of a * boundary violation, but what the heck). */ if (s->enc_write_ctx && (EVP_CIPHER_mode(s->enc_write_ctx->cipher) & EVP_CIPH_CBC_MODE)) bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher); else bs = 0; wr->data = p + bs; /* make room for IV in case of CBC */ wr->length = (int)len; wr->input = (unsigned char *)buf; /* * we now 'read' from wr->input, wr->length bytes into wr->data */ /* first we compress */ if (s->compress != NULL) { if (!ssl3_do_compress(s)) { SSLerr(SSL_F_DO_DTLS1_WRITE, SSL_R_COMPRESSION_FAILURE); goto err; } } else { memcpy(wr->data, wr->input, wr->length); wr->input = wr->data; } /* * we should still have the output to wr->data and the input from * wr->input. Length should be wr->length. wr->data still points in the * wb->buf */ if (mac_size != 0) { s->method->ssl3_enc->mac(s, &(p[wr->length + bs]), 1); wr->length += mac_size; } /* this is true regardless of mac size */ wr->input = p; wr->data = p; /* ssl3_enc can only have an error on read */ if (bs) { /* bs != 0 in case of CBC */ RAND_pseudo_bytes(p, bs); /* * master IV and last CBC residue stand for the rest of randomness */ wr->length += bs; } s->method->ssl3_enc->enc(s, 1); /* record length after mac and block padding */ /* * if (type == SSL3_RT_APPLICATION_DATA || (type == SSL3_RT_ALERT && ! * SSL_in_init(s))) */ /* there's only one epoch between handshake and app data */ s2n(s->d1->w_epoch, pseq); /* XDTLS: ?? */ /* * else s2n(s->d1->handshake_epoch, pseq); */ memcpy(pseq, &(s->s3->write_sequence[2]), 6); pseq += 6; s2n(wr->length, pseq); /* * we should now have wr->data pointing to the encrypted data, which is * wr->length long */ wr->type = type; /* not needed but helps for debugging */ wr->length += DTLS1_RT_HEADER_LENGTH; #if 0 /* this is now done at the message layer */ /* buffer the record, making it easy to handle retransmits */ if (type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC) dtls1_buffer_record(s, wr->data, wr->length, *((PQ_64BIT *) & (s->s3->write_sequence[0]))); #endif ssl3_record_sequence_update(&(s->s3->write_sequence[0])); if (create_empty_fragment) { /* * we are in a recursive call; just return the length, don't write * out anything here */ return wr->length; } /* now let's set up wb */ wb->left = prefix_len + wr->length; wb->offset = 0; /* * memorize arguments so that ssl3_write_pending can detect bad write * retries later */ s->s3->wpend_tot = len; s->s3->wpend_buf = buf; s->s3->wpend_type = type; s->s3->wpend_ret = len; /* we now just need to write the buffer */ return ssl3_write_pending(s, type, buf, len); err: return -1; } static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap) { #if PQ_64BIT_IS_INTEGER PQ_64BIT mask = 0x0000000000000001L; #endif PQ_64BIT rcd_num, tmp; pq_64bit_init(&rcd_num); pq_64bit_init(&tmp); /* this is the sequence number for the record just read */ pq_64bit_bin2num(&rcd_num, s->s3->read_sequence, 8); if (pq_64bit_gt(&rcd_num, &(bitmap->max_seq_num)) || pq_64bit_eq(&rcd_num, &(bitmap->max_seq_num))) { pq_64bit_assign(&s->s3->rrec.seq_num, &rcd_num); pq_64bit_free(&rcd_num); pq_64bit_free(&tmp); return 1; /* this record is new */ } pq_64bit_sub(&tmp, &(bitmap->max_seq_num), &rcd_num); if (pq_64bit_get_word(&tmp) > bitmap->length) { pq_64bit_free(&rcd_num); pq_64bit_free(&tmp); return 0; /* stale, outside the window */ } #if PQ_64BIT_IS_BIGNUM { int offset; pq_64bit_sub(&tmp, &(bitmap->max_seq_num), &rcd_num); pq_64bit_sub_word(&tmp, 1); offset = pq_64bit_get_word(&tmp); if (pq_64bit_is_bit_set(&(bitmap->map), offset)) { pq_64bit_free(&rcd_num); pq_64bit_free(&tmp); return 0; } } #else mask <<= (bitmap->max_seq_num - rcd_num - 1); if (bitmap->map & mask) return 0; /* record previously received */ #endif pq_64bit_assign(&s->s3->rrec.seq_num, &rcd_num); pq_64bit_free(&rcd_num); pq_64bit_free(&tmp); return 1; } static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap) { unsigned int shift; PQ_64BIT rcd_num; PQ_64BIT tmp; PQ_64BIT_CTX *ctx; pq_64bit_init(&rcd_num); pq_64bit_init(&tmp); pq_64bit_bin2num(&rcd_num, s->s3->read_sequence, 8); /* * unfortunate code complexity due to 64-bit manipulation support on * 32-bit machines */ if (pq_64bit_gt(&rcd_num, &(bitmap->max_seq_num)) || pq_64bit_eq(&rcd_num, &(bitmap->max_seq_num))) { pq_64bit_sub(&tmp, &rcd_num, &(bitmap->max_seq_num)); pq_64bit_add_word(&tmp, 1); shift = (unsigned int)pq_64bit_get_word(&tmp); pq_64bit_lshift(&(tmp), &(bitmap->map), shift); pq_64bit_assign(&(bitmap->map), &tmp); pq_64bit_set_bit(&(bitmap->map), 0); pq_64bit_add_word(&rcd_num, 1); pq_64bit_assign(&(bitmap->max_seq_num), &rcd_num); pq_64bit_assign_word(&tmp, 1); pq_64bit_lshift(&tmp, &tmp, bitmap->length); ctx = pq_64bit_ctx_new(&ctx); pq_64bit_mod(&(bitmap->map), &(bitmap->map), &tmp, ctx); pq_64bit_ctx_free(ctx); } else { pq_64bit_sub(&tmp, &(bitmap->max_seq_num), &rcd_num); pq_64bit_sub_word(&tmp, 1); shift = (unsigned int)pq_64bit_get_word(&tmp); pq_64bit_set_bit(&(bitmap->map), shift); } pq_64bit_free(&rcd_num); pq_64bit_free(&tmp); } int dtls1_dispatch_alert(SSL *s) { int i, j; void (*cb) (const SSL *ssl, int type, int val) = NULL; unsigned char buf[DTLS1_AL_HEADER_LENGTH]; unsigned char *ptr = &buf[0]; s->s3->alert_dispatch = 0; memset(buf, 0x00, sizeof(buf)); *ptr++ = s->s3->send_alert[0]; *ptr++ = s->s3->send_alert[1]; #ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) { s2n(s->d1->handshake_read_seq, ptr); # if 0 if (s->d1->r_msg_hdr.frag_off == 0) /* * waiting for a new msg */ else s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */ # endif # if 0 fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n", s->d1->handshake_read_seq, s->d1->r_msg_hdr.seq); # endif l2n3(s->d1->r_msg_hdr.frag_off, ptr); } #endif i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0); if (i <= 0) { s->s3->alert_dispatch = 1; /* fprintf( stderr, "not done with alert\n" ); */ } else { if (s->s3->send_alert[0] == SSL3_AL_FATAL #ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE #endif ) (void)BIO_flush(s->wbio); if (s->msg_callback) s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 2, s, s->msg_callback_arg); if (s->info_callback != NULL) cb = s->info_callback; else if (s->ctx->info_callback != NULL) cb = s->ctx->info_callback; if (cb != NULL) { j = (s->s3->send_alert[0] << 8) | s->s3->send_alert[1]; cb(s, SSL_CB_WRITE_ALERT, j); } } return (i); } static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, unsigned int *is_next_epoch) { *is_next_epoch = 0; /* In current epoch, accept HM, CCS, DATA, & ALERT */ if (rr->epoch == s->d1->r_epoch) return &s->d1->bitmap; /* * Only HM and ALERT messages can be from the next epoch and only if we * have already processed all of the unprocessed records from the last * epoch */ else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) && s->d1->unprocessed_rcds.epoch != s->d1->r_epoch && (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) { *is_next_epoch = 1; return &s->d1->next_bitmap; } return NULL; } #if 0 static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, unsigned short *priority, unsigned long *offset) { /* alerts are passed up immediately */ if (rr->type == SSL3_RT_APPLICATION_DATA || rr->type == SSL3_RT_ALERT) return 0; /* * Only need to buffer if a handshake is underway. (this implies that * Hello Request and Client Hello are passed up immediately) */ if (SSL_in_init(s)) { unsigned char *data = rr->data; /* need to extract the HM/CCS sequence number here */ if (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { unsigned short seq_num; struct hm_header_st msg_hdr; struct ccs_header_st ccs_hdr; if (rr->type == SSL3_RT_HANDSHAKE) { dtls1_get_message_header(data, &msg_hdr); seq_num = msg_hdr.seq; *offset = msg_hdr.frag_off; } else { dtls1_get_ccs_header(data, &ccs_hdr); seq_num = ccs_hdr.seq; *offset = 0; } /* * this is either a record we're waiting for, or a retransmit of * something we happened to previously receive (higher layers * will drop the repeat silently */ if (seq_num < s->d1->handshake_read_seq) return 0; if (rr->type == SSL3_RT_HANDSHAKE && seq_num == s->d1->handshake_read_seq && msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off) return 0; else if (seq_num == s->d1->handshake_read_seq && (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC || msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off)) return 0; else { *priority = seq_num; return 1; } } else /* unknown record type */ return 0; } return 0; } #endif void dtls1_reset_seq_numbers(SSL *s, int rw) { unsigned char *seq; unsigned int seq_bytes = sizeof(s->s3->read_sequence); if (rw & SSL3_CC_READ) { seq = s->s3->read_sequence; s->d1->r_epoch++; pq_64bit_assign(&(s->d1->bitmap.map), &(s->d1->next_bitmap.map)); s->d1->bitmap.length = s->d1->next_bitmap.length; pq_64bit_assign(&(s->d1->bitmap.max_seq_num), &(s->d1->next_bitmap.max_seq_num)); pq_64bit_free(&(s->d1->next_bitmap.map)); pq_64bit_free(&(s->d1->next_bitmap.max_seq_num)); memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP)); pq_64bit_init(&(s->d1->next_bitmap.map)); pq_64bit_init(&(s->d1->next_bitmap.max_seq_num)); /* * We must not use any buffered messages received from the previous * epoch */ dtls1_clear_received_buffer(s); } else { seq = s->s3->write_sequence; memcpy(s->d1->last_write_sequence, seq, sizeof(s->s3->write_sequence)); s->d1->w_epoch++; } memset(seq, 0x00, seq_bytes); } #if PQ_64BIT_IS_INTEGER static PQ_64BIT bytes_to_long_long(unsigned char *bytes, PQ_64BIT * num) { PQ_64BIT _num; _num = (((PQ_64BIT) bytes[0]) << 56) | (((PQ_64BIT) bytes[1]) << 48) | (((PQ_64BIT) bytes[2]) << 40) | (((PQ_64BIT) bytes[3]) << 32) | (((PQ_64BIT) bytes[4]) << 24) | (((PQ_64BIT) bytes[5]) << 16) | (((PQ_64BIT) bytes[6]) << 8) | (((PQ_64BIT) bytes[7])); *num = _num; return _num; } #endif Index: releng/9.3/crypto/openssl/ssl/s3_pkt.c =================================================================== --- releng/9.3/crypto/openssl/ssl/s3_pkt.c (revision 308204) +++ releng/9.3/crypto/openssl/ssl/s3_pkt.c (revision 308205) @@ -1,1418 +1,1433 @@ /* ssl/s3_pkt.c */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ #include #include #include #define USE_SOCKETS #include "ssl_locl.h" #include #include static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment); static int ssl3_get_record(SSL *s); int ssl3_read_n(SSL *s, int n, int max, int extend) { /* * If extend == 0, obtain new n-byte packet; if extend == 1, increase * packet by another n bytes. The packet will be in the sub-array of * s->s3->rbuf.buf specified by s->packet and s->packet_length. (If * s->read_ahead is set, 'max' bytes may be stored in rbuf [plus * s->packet_length bytes if extend == 1].) */ int i, off, newb; if (!extend) { /* start with empty packet ... */ if (s->s3->rbuf.left == 0) s->s3->rbuf.offset = 0; s->packet = s->s3->rbuf.buf + s->s3->rbuf.offset; s->packet_length = 0; /* ... now we can act as if 'extend' was set */ } /* * For DTLS/UDP reads should not span multiple packets because the read * operation returns the whole packet at once (as long as it fits into * the buffer). */ if (SSL_version(s) == DTLS1_VERSION) { if (s->s3->rbuf.left == 0 && extend) return 0; if (s->s3->rbuf.left > 0 && n > s->s3->rbuf.left) n = s->s3->rbuf.left; } /* if there is enough in the buffer from a previous read, take some */ if (s->s3->rbuf.left >= (int)n) { s->packet_length += n; s->s3->rbuf.left -= n; s->s3->rbuf.offset += n; return (n); } /* else we need to read more data */ if (!s->read_ahead) max = n; { /* avoid buffer overflow */ int max_max = s->s3->rbuf.len - s->packet_length; if (max > max_max) max = max_max; } if (n > max) { /* does not happen */ SSLerr(SSL_F_SSL3_READ_N, ERR_R_INTERNAL_ERROR); return -1; } off = s->packet_length; newb = s->s3->rbuf.left; /* * Move any available bytes to front of buffer: 'off' bytes already * pointed to by 'packet', 'newb' extra ones at the end */ if (s->packet != s->s3->rbuf.buf) { /* off > 0 */ memmove(s->s3->rbuf.buf, s->packet, off + newb); s->packet = s->s3->rbuf.buf; } while (newb < n) { /* * Now we have off+newb bytes at the front of s->s3->rbuf.buf and * need to read in more until we have off+n (up to off+max if * possible) */ clear_sys_error(); if (s->rbio != NULL) { s->rwstate = SSL_READING; i = BIO_read(s->rbio, &(s->s3->rbuf.buf[off + newb]), max - newb); } else { SSLerr(SSL_F_SSL3_READ_N, SSL_R_READ_BIO_NOT_SET); i = -1; } if (i <= 0) { s->s3->rbuf.left = newb; return (i); } newb += i; /* * reads should *never* span multiple packets for DTLS because the * underlying transport protocol is message oriented as opposed to * byte oriented as in the TLS case. */ if (SSL_version(s) == DTLS1_VERSION) { if (n > newb) n = newb; /* makes the while condition false */ } } /* done reading, now the book-keeping */ s->s3->rbuf.offset = off + n; s->s3->rbuf.left = newb - n; s->packet_length += n; s->rwstate = SSL_NOTHING; return (n); } /* * MAX_EMPTY_RECORDS defines the number of consecutive, empty records that * will be processed per call to ssl3_get_record. Without this limit an * attacker could send empty records at a faster rate than we can process and * cause ssl3_get_record to loop forever. */ #define MAX_EMPTY_RECORDS 32 /*- * Call this to get a new input record. * It will return <= 0 if more data is needed, normally due to an error * or non-blocking IO. * When it finishes, one packet has been decoded and can be found in * ssl->s3->rrec.type - is the type of record * ssl->s3->rrec.data, - data * ssl->s3->rrec.length, - number of bytes */ /* used only by ssl3_read_bytes */ static int ssl3_get_record(SSL *s) { int ssl_major, ssl_minor, al; int enc_err, n, i, ret = -1; SSL3_RECORD *rr; SSL_SESSION *sess; unsigned char *p; unsigned char md[EVP_MAX_MD_SIZE]; short version; unsigned mac_size, orig_len; size_t extra; unsigned empty_record_count = 0; rr = &(s->s3->rrec); sess = s->session; if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) extra = SSL3_RT_MAX_EXTRA; else extra = 0; if (extra != s->s3->rbuf.len - SSL3_RT_MAX_PACKET_SIZE) { /* * actually likely an application error: * SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER set after ssl3_setup_buffers() * was done */ SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR); return -1; } again: /* check if we have the header */ if ((s->rstate != SSL_ST_READ_BODY) || (s->packet_length < SSL3_RT_HEADER_LENGTH)) { n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0); if (n <= 0) return (n); /* error or non-blocking */ s->rstate = SSL_ST_READ_BODY; p = s->packet; /* Pull apart the header into the SSL3_RECORD */ rr->type = *(p++); ssl_major = *(p++); ssl_minor = *(p++); version = (ssl_major << 8) | ssl_minor; n2s(p, rr->length); /* Lets check version */ if (!s->first_packet) { if (version != s->version) { SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER); if ((s->version & 0xFF00) == (version & 0xFF00)) /* * Send back error using their minor version number :-) */ s->version = (unsigned short)version; al = SSL_AD_PROTOCOL_VERSION; goto f_err; } } if ((version >> 8) != SSL3_VERSION_MAJOR) { SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER); goto err; } if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH + extra) { al = SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_PACKET_LENGTH_TOO_LONG); goto f_err; } /* now s->rstate == SSL_ST_READ_BODY */ } /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ if (rr->length > s->packet_length - SSL3_RT_HEADER_LENGTH) { /* now s->packet_length == SSL3_RT_HEADER_LENGTH */ i = rr->length; n = ssl3_read_n(s, i, i, 1); if (n <= 0) return (n); /* error or non-blocking io */ /* * now n == rr->length, and s->packet_length == SSL3_RT_HEADER_LENGTH * + rr->length */ } s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ /* * At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, * and we have that many bytes in s->packet */ rr->input = &(s->packet[SSL3_RT_HEADER_LENGTH]); /* * ok, we can now read from 's->packet' data into 'rr' rr->input points * at rr->length bytes, which need to be copied into rr->data by either * the decryption or by the decompression When the data is 'copied' into * the rr->data buffer, rr->input will be pointed at the new buffer */ /* * We now have - encrypted [ MAC [ compressed [ plain ] ] ] rr->length * bytes of encrypted compressed stuff. */ /* check is not needed I believe */ if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH + extra) { al = SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); goto f_err; } /* decrypt in place in 'rr->input' */ rr->data = rr->input; enc_err = s->method->ssl3_enc->enc(s, 0); /*- * enc_err is: * 0: (in non-constant time) if the record is publically invalid. * 1: if the padding is valid * -1: if the padding is invalid */ if (enc_err == 0) { al = SSL_AD_DECRYPTION_FAILED; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); goto f_err; } #ifdef TLS_DEBUG printf("dec %d\n", rr->length); { unsigned int z; for (z = 0; z < rr->length; z++) printf("%02X%c", rr->data[z], ((z + 1) % 16) ? ' ' : '\n'); } printf("\n"); #endif /* r->length is now the compressed data plus mac */ if ((sess != NULL) && (s->enc_read_ctx != NULL) && (s->read_hash != NULL)) { /* s->read_hash != NULL => mac_size != -1 */ unsigned char *mac = NULL; unsigned char mac_tmp[EVP_MAX_MD_SIZE]; mac_size = EVP_MD_size(s->read_hash); OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); /* * kludge: *_cbc_remove_padding passes padding length in rr->type */ orig_len = rr->length + ((unsigned int)rr->type >> 8); /* * orig_len is the length of the record before any padding was * removed. This is public information, as is the MAC in use, * therefore we can safely process the record in a different amount * of time if it's too short to possibly contain a MAC. */ if (orig_len < mac_size || /* CBC records must have a padding length byte too. */ (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE && orig_len < mac_size + 1)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT); goto f_err; } if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) { /* * We update the length so that the TLS header bytes can be * constructed correctly but we need to extract the MAC in * constant time from within the record, without leaking the * contents of the padding bytes. */ mac = mac_tmp; ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len); rr->length -= mac_size; } else { /* * In this case there's no padding, so |orig_len| equals * |rec->length| and we checked that there's enough bytes for * |mac_size| above. */ rr->length -= mac_size; mac = &rr->data[rr->length]; } i = s->method->ssl3_enc->mac(s, md, 0 /* not send */ ); if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) enc_err = -1; if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + extra + mac_size) enc_err = -1; } if (enc_err < 0) { /* * A separate 'decryption_failed' alert was introduced with TLS 1.0, * SSL 3.0 only has 'bad_record_mac'. But unless a decryption * failure is directly visible from the ciphertext anyway, we should * not reveal which kind of error occured -- this might become * visible to an attacker (e.g. via a logfile) */ al = SSL_AD_BAD_RECORD_MAC; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); goto f_err; } /* r->length is now just compressed */ if (s->expand != NULL) { if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + extra) { al = SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_COMPRESSED_LENGTH_TOO_LONG); goto f_err; } if (!ssl3_do_uncompress(s)) { al = SSL_AD_DECOMPRESSION_FAILURE; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_DECOMPRESSION); goto f_err; } } if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH + extra) { al = SSL_AD_RECORD_OVERFLOW; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_DATA_LENGTH_TOO_LONG); goto f_err; } rr->off = 0; /*- * So at this point the following is true * ssl->s3->rrec.type is the type of record * ssl->s3->rrec.length == number of bytes in record * ssl->s3->rrec.off == offset to first valid byte * ssl->s3->rrec.data == where to take bytes from, increment * after use :-). */ /* we have pulled in a full packet so zero things */ s->packet_length = 0; /* just read a 0 length packet */ if (rr->length == 0) { empty_record_count++; if (empty_record_count > MAX_EMPTY_RECORDS) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_RECORD_TOO_SMALL); goto f_err; } goto again; } return (1); f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); err: return (ret); } int ssl3_do_uncompress(SSL *ssl) { #ifndef OPENSSL_NO_COMP int i; SSL3_RECORD *rr; rr = &(ssl->s3->rrec); i = COMP_expand_block(ssl->expand, rr->comp, SSL3_RT_MAX_PLAIN_LENGTH, rr->data, (int)rr->length); if (i < 0) return (0); else rr->length = i; rr->data = rr->comp; #endif return (1); } int ssl3_do_compress(SSL *ssl) { #ifndef OPENSSL_NO_COMP int i; SSL3_RECORD *wr; wr = &(ssl->s3->wrec); i = COMP_compress_block(ssl->compress, wr->data, SSL3_RT_MAX_COMPRESSED_LENGTH, wr->input, (int)wr->length); if (i < 0) return (0); else wr->length = i; wr->input = wr->data; #endif return (1); } /* * Call this to write data in records of type 'type' It will return <= 0 if * not all data has been sent or non-blocking IO. */ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) { const unsigned char *buf = buf_; unsigned int n, nw; int i, tot; s->rwstate = SSL_NOTHING; OPENSSL_assert(s->s3->wnum <= INT_MAX); tot = s->s3->wnum; s->s3->wnum = 0; if (SSL_in_init(s) && !s->in_handshake) { i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return -1; } } /* * ensure that if we end up with a smaller value of data to write out * than the the original len from a write which didn't complete for * non-blocking I/O and also somehow ended up avoiding the check for * this in ssl3_write_pending/SSL_R_BAD_WRITE_RETRY as it must never be * possible to end up with (len-tot) as a large number that will then * promptly send beyond the end of the users buffer ... so we trap and * report the error in a way the user will notice */ if (len < tot) { SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_BAD_LENGTH); return (-1); } n = (len - tot); for (;;) { if (n > SSL3_RT_MAX_PLAIN_LENGTH) nw = SSL3_RT_MAX_PLAIN_LENGTH; else nw = n; i = do_ssl3_write(s, type, &(buf[tot]), nw, 0); if (i <= 0) { s->s3->wnum = tot; return i; } if ((i == (int)n) || (type == SSL3_RT_APPLICATION_DATA && (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) { /* * next chunk of data should get another prepended empty fragment * in ciphersuites with known-IV weakness: */ s->s3->empty_fragment_done = 0; return tot + i; } n -= i; tot += i; } } static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment) { unsigned char *p, *plen; int i, mac_size, clear = 0; int prefix_len = 0; SSL3_RECORD *wr; SSL3_BUFFER *wb; SSL_SESSION *sess; /* * first check if there is a SSL3_BUFFER still being written out. This * will happen with non blocking IO */ if (s->s3->wbuf.left != 0) return (ssl3_write_pending(s, type, buf, len)); /* If we have an alert to send, lets send it */ if (s->s3->alert_dispatch) { i = s->method->ssl_dispatch_alert(s); if (i <= 0) return (i); /* if it went, fall through and send more stuff */ } if (len == 0 && !create_empty_fragment) return 0; wr = &(s->s3->wrec); wb = &(s->s3->wbuf); sess = s->session; if ((sess == NULL) || (s->enc_write_ctx == NULL) || (s->write_hash == NULL)) clear = 1; if (clear) mac_size = 0; else mac_size = EVP_MD_size(s->write_hash); /* * 'create_empty_fragment' is true only when this function calls itself */ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done) { /* * countermeasure against known-IV weakness in CBC ciphersuites (see * http://www.openssl.org/~bodo/tls-cbc.txt) */ if (s->s3->need_empty_fragments && type == SSL3_RT_APPLICATION_DATA) { /* * recursive function call with 'create_empty_fragment' set; this * prepares and buffers the data for an empty fragment (these * 'prefix_len' bytes are sent out later together with the actual * payload) */ prefix_len = do_ssl3_write(s, type, buf, 0, 1); if (prefix_len <= 0) goto err; if (s->s3->wbuf.len < (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE) { /* insufficient space */ SSLerr(SSL_F_DO_SSL3_WRITE, ERR_R_INTERNAL_ERROR); goto err; } } s->s3->empty_fragment_done = 1; } p = wb->buf + prefix_len; /* write the header */ *(p++) = type & 0xff; wr->type = type; *(p++) = (s->version >> 8); *(p++) = s->version & 0xff; /* field where we are to write out packet length */ plen = p; p += 2; /* lets setup the record stuff. */ wr->data = p; wr->length = (int)len; wr->input = (unsigned char *)buf; /* * we now 'read' from wr->input, wr->length bytes into wr->data */ /* first we compress */ if (s->compress != NULL) { if (!ssl3_do_compress(s)) { SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_COMPRESSION_FAILURE); goto err; } } else { memcpy(wr->data, wr->input, wr->length); wr->input = wr->data; } /* * we should still have the output to wr->data and the input from * wr->input. Length should be wr->length. wr->data still points in the * wb->buf */ if (mac_size != 0) { s->method->ssl3_enc->mac(s, &(p[wr->length]), 1); wr->length += mac_size; wr->input = p; wr->data = p; } /* ssl3_enc can only have an error on read */ s->method->ssl3_enc->enc(s, 1); /* record length after mac and block padding */ s2n(wr->length, plen); /* * we should now have wr->data pointing to the encrypted data, which is * wr->length long */ wr->type = type; /* not needed but helps for debugging */ wr->length += SSL3_RT_HEADER_LENGTH; if (create_empty_fragment) { /* * we are in a recursive call; just return the length, don't write * out anything here */ return wr->length; } /* now let's set up wb */ wb->left = prefix_len + wr->length; wb->offset = 0; /* * memorize arguments so that ssl3_write_pending can detect bad write * retries later */ s->s3->wpend_tot = len; s->s3->wpend_buf = buf; s->s3->wpend_type = type; s->s3->wpend_ret = len; /* we now just need to write the buffer */ return ssl3_write_pending(s, type, buf, len); err: return -1; } /* if s->s3->wbuf.left != 0, we need to call this */ int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, unsigned int len) { int i; /* XXXX */ if ((s->s3->wpend_tot > (int)len) || ((s->s3->wpend_buf != buf) && !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) || (s->s3->wpend_type != type)) { SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY); return (-1); } for (;;) { clear_sys_error(); if (s->wbio != NULL) { s->rwstate = SSL_WRITING; i = BIO_write(s->wbio, (char *)&(s->s3->wbuf.buf[s->s3->wbuf.offset]), (unsigned int)s->s3->wbuf.left); } else { SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET); i = -1; } if (i == s->s3->wbuf.left) { s->s3->wbuf.left = 0; s->rwstate = SSL_NOTHING; return (s->s3->wpend_ret); } else if (i <= 0) { if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) { /* * For DTLS, just drop it. That's kind of the whole point in * using a datagram service */ s->s3->wbuf.left = 0; } return (i); } s->s3->wbuf.offset += i; s->s3->wbuf.left -= i; } } /*- * Return up to 'len' payload bytes received in 'type' records. * 'type' is one of the following: * * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) * - 0 (during a shutdown, no data has to be returned) * * If we don't have stored data to work from, read a SSL/TLS record first * (possibly multiple records if we still don't have anything to return). * * This function must handle any surprises the peer may have for us, such as * Alert records (e.g. close_notify), ChangeCipherSpec records (not really * a surprise, but handled as if it were), or renegotiation requests. * Also if record payloads contain fragments too small to process, we store * them until there is enough for the respective protocol (the record protocol * may use arbitrary fragmentation and even interleaving): * Change cipher spec protocol * just 1 byte needed, no need for keeping anything stored * Alert protocol * 2 bytes needed (AlertLevel, AlertDescription) * Handshake protocol * 4 bytes needed (HandshakeType, uint24 length) -- we just have * to detect unexpected Client Hello and Hello Request messages * here, anything else is handled by higher layers * Application data protocol * none of our business */ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) { int al, i, j, ret; unsigned int n; SSL3_RECORD *rr; void (*cb) (const SSL *ssl, int type2, int val) = NULL; if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ if (!ssl3_setup_buffers(s)) return (-1); if ((type && (type != SSL3_RT_APPLICATION_DATA) && (type != SSL3_RT_HANDSHAKE)) || (peek && (type != SSL3_RT_APPLICATION_DATA))) { SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); return -1; } if ((type == SSL3_RT_HANDSHAKE) && (s->s3->handshake_fragment_len > 0)) /* (partially) satisfy request from storage */ { unsigned char *src = s->s3->handshake_fragment; unsigned char *dst = buf; unsigned int k; /* peek == 0 */ n = 0; while ((len > 0) && (s->s3->handshake_fragment_len > 0)) { *dst++ = *src++; len--; s->s3->handshake_fragment_len--; n++; } /* move any remaining fragment bytes: */ for (k = 0; k < s->s3->handshake_fragment_len; k++) s->s3->handshake_fragment[k] = *src++; return n; } /* * Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. */ if (!s->in_handshake && SSL_in_init(s)) { /* type == SSL3_RT_APPLICATION_DATA */ i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } } start: s->rwstate = SSL_NOTHING; /*- * s->s3->rrec.type - is the type of record * s->s3->rrec.data, - data * s->s3->rrec.off, - offset into 'data' for next read * s->s3->rrec.length, - number of bytes. */ rr = &(s->s3->rrec); /* get new packet if necessary */ if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY)) { ret = ssl3_get_record(s); if (ret <= 0) return (ret); } + /* + * Reset the count of consecutive warning alerts if we've got a non-empty + * record that isn't an alert. + */ + if (rr->type != SSL3_RT_ALERT && rr->length != 0) + s->s3->alert_count = 0; + /* we now have a packet which can be read and processed */ if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, * reset by ssl3_get_finished */ && (rr->type != SSL3_RT_HANDSHAKE)) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); goto f_err; } /* * If the other end has shut down, throw anything we read away (even in * 'peek' mode) */ if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { rr->length = 0; s->rwstate = SSL_NOTHING; return (0); } if (type == rr->type) { /* SSL3_RT_APPLICATION_DATA or * SSL3_RT_HANDSHAKE */ /* * make sure that we are not getting application data when we are * doing a handshake for the first time */ if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) && (s->enc_read_ctx == NULL)) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_APP_DATA_IN_HANDSHAKE); goto f_err; } if (len <= 0) return (len); if ((unsigned int)len > rr->length) n = rr->length; else n = (unsigned int)len; memcpy(buf, &(rr->data[rr->off]), n); if (!peek) { rr->length -= n; rr->off += n; if (rr->length == 0) { s->rstate = SSL_ST_READ_HEADER; rr->off = 0; } } return (n); } /* * If we get here, then type != rr->type; if we have a handshake message, * then it was unexpected (Hello Request or Client Hello). */ /* * In case of record types for which we have 'fragment' storage, fill * that so that we can process the data at a fixed place. */ { unsigned int dest_maxlen = 0; unsigned char *dest = NULL; unsigned int *dest_len = NULL; if (rr->type == SSL3_RT_HANDSHAKE) { dest_maxlen = sizeof s->s3->handshake_fragment; dest = s->s3->handshake_fragment; dest_len = &s->s3->handshake_fragment_len; } else if (rr->type == SSL3_RT_ALERT) { dest_maxlen = sizeof s->s3->alert_fragment; dest = s->s3->alert_fragment; dest_len = &s->s3->alert_fragment_len; } if (dest_maxlen > 0) { n = dest_maxlen - *dest_len; /* available space in 'dest' */ if (rr->length < n) n = rr->length; /* available bytes */ /* now move 'n' bytes: */ while (n-- > 0) { dest[(*dest_len)++] = rr->data[rr->off++]; rr->length--; } if (*dest_len < dest_maxlen) goto start; /* fragment was too small */ } } /*- * s->s3->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE; * s->s3->alert_fragment_len == 2 iff rr->type == SSL3_RT_ALERT. * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ /* If we are a client, check for an incoming 'Hello Request': */ if ((!s->server) && (s->s3->handshake_fragment_len >= 4) && (s->s3->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && (s->session != NULL) && (s->session->cipher != NULL)) { s->s3->handshake_fragment_len = 0; if ((s->s3->handshake_fragment[1] != 0) || (s->s3->handshake_fragment[2] != 0) || (s->s3->handshake_fragment[3] != 0)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_HELLO_REQUEST); goto f_err; } if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->s3->handshake_fragment, 4, s, s->msg_callback_arg); if (SSL_is_init_finished(s) && !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && !s->s3->renegotiate) { ssl3_renegotiate(s); if (ssl3_renegotiate_check(s)) { i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (s->s3->rbuf.left == 0) { /* no read-ahead left? */ BIO *bio; /* * In the case where we try to read application data, * but we trigger an SSL handshake, we return -1 with * the retry option set. Otherwise renegotiation may * cause nasty problems in the blocking world */ s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } } } } /* * we either finished a handshake or ignored the request, now try * again to obtain the (application) data we were asked for */ goto start; } /* * If we are a server and get a client hello when renegotiation isn't * allowed send back a no renegotiation alert and carry on. WARNING: * experimental code, needs reviewing (steve) */ if (s->server && SSL_is_init_finished(s) && !s->s3->send_connection_binding && (s->version > SSL3_VERSION) && (s->s3->handshake_fragment_len >= 4) && (s->s3->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) && (s->session != NULL) && (s->session->cipher != NULL) && !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { /* * s->s3->handshake_fragment_len = 0; */ rr->length = 0; ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION); goto start; } if (s->s3->alert_fragment_len >= 2) { int alert_level = s->s3->alert_fragment[0]; int alert_descr = s->s3->alert_fragment[1]; s->s3->alert_fragment_len = 0; if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_ALERT, s->s3->alert_fragment, 2, s, s->msg_callback_arg); if (s->info_callback != NULL) cb = s->info_callback; else if (s->ctx->info_callback != NULL) cb = s->ctx->info_callback; if (cb != NULL) { j = (alert_level << 8) | alert_descr; cb(s, SSL_CB_READ_ALERT, j); } if (alert_level == 1) { /* warning */ s->s3->warn_alert = alert_descr; + + s->s3->alert_count++; + if (s->s3->alert_count == MAX_WARN_ALERT_COUNT) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_TOO_MANY_WARN_ALERTS); + goto f_err; + } + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { s->shutdown |= SSL_RECEIVED_SHUTDOWN; return (0); } /* * This is a warning but we receive it if we requested * renegotiation and the peer denied it. Terminate with a fatal * alert because if application tried to renegotiatie it * presumably had a good reason and expects it to succeed. In * future we might have a renegotiation where we don't care if * the peer refused it where we carry on. */ else if (alert_descr == SSL_AD_NO_RENEGOTIATION) { al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_NO_RENEGOTIATION); goto f_err; } } else if (alert_level == 2) { /* fatal */ char tmp[16]; s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; SSL_CTX_remove_session(s->ctx, s->session); return (0); } else { al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); goto f_err; } goto start; } if (s->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a * shutdown */ s->rwstate = SSL_NOTHING; rr->length = 0; return (0); } if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { /* * 'Change Cipher Spec' is just a single byte, so we know exactly * what the record payload has to look like */ if ((rr->length != 1) || (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS)) { al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_CHANGE_CIPHER_SPEC); goto f_err; } /* Check we have a cipher to change to */ if (s->s3->tmp.new_cipher == NULL) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_CCS_RECEIVED_EARLY); goto f_err; } if (!(s->s3->flags & SSL3_FLAGS_CCS_OK)) { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_CCS_RECEIVED_EARLY); goto f_err; } s->s3->flags &= ~SSL3_FLAGS_CCS_OK; rr->length = 0; if (s->msg_callback) s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, s->msg_callback_arg); s->s3->change_cipher_spec = 1; if (!ssl3_do_change_cipher_spec(s)) goto err; else goto start; } /* * Unexpected handshake message (Client Hello, or protocol violation) */ if ((s->s3->handshake_fragment_len >= 4) && !s->in_handshake) { if (((s->state & SSL_ST_MASK) == SSL_ST_OK) && !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { #if 0 /* worked only because C operator preferences * are not as expected (and because this is * not really needed for clients except for * detecting protocol violations): */ s->state = SSL_ST_BEFORE | (s->server) ? SSL_ST_ACCEPT : SSL_ST_CONNECT; #else s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; #endif s->new_session = 1; } i = s->handshake_func(s); if (i < 0) return (i); if (i == 0) { SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); return (-1); } if (!(s->mode & SSL_MODE_AUTO_RETRY)) { if (s->s3->rbuf.left == 0) { /* no read-ahead left? */ BIO *bio; /* * In the case where we try to read application data, but we * trigger an SSL handshake, we return -1 with the retry * option set. Otherwise renegotiation may cause nasty * problems in the blocking world */ s->rwstate = SSL_READING; bio = SSL_get_rbio(s); BIO_clear_retry_flags(bio); BIO_set_retry_read(bio); return (-1); } } goto start; } switch (rr->type) { default: #ifndef OPENSSL_NO_TLS /* TLS just ignores unknown message types */ if (s->version == TLS1_VERSION) { rr->length = 0; goto start; } #endif al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; case SSL3_RT_CHANGE_CIPHER_SPEC: case SSL3_RT_ALERT: case SSL3_RT_HANDSHAKE: /* * we already handled all of these, with the possible exception of * SSL3_RT_HANDSHAKE when s->in_handshake is set, but that should not * happen when type != rr->type */ al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); goto f_err; case SSL3_RT_APPLICATION_DATA: /* * At this point, we were expecting handshake data, but have * application data. If the library was running inside ssl3_read() * (i.e. in_read_app_data is set) and it makes sense to read * application data at this point (session renegotiation not yet * started), we will indulge it. */ if (s->s3->in_read_app_data && (s->s3->total_renegotiations != 0) && (((s->state & SSL_ST_CONNECT) && (s->state >= SSL3_ST_CW_CLNT_HELLO_A) && (s->state <= SSL3_ST_CR_SRVR_HELLO_A) ) || ((s->state & SSL_ST_ACCEPT) && (s->state <= SSL3_ST_SW_HELLO_REQ_A) && (s->state >= SSL3_ST_SR_CLNT_HELLO_A) ) )) { s->s3->in_read_app_data = 2; return (-1); } else { al = SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD); goto f_err; } } /* not reached */ f_err: ssl3_send_alert(s, SSL3_AL_FATAL, al); err: return (-1); } int ssl3_do_change_cipher_spec(SSL *s) { int i; const char *sender; int slen; if (s->state & SSL_ST_ACCEPT) i = SSL3_CHANGE_CIPHER_SERVER_READ; else i = SSL3_CHANGE_CIPHER_CLIENT_READ; if (s->s3->tmp.key_block == NULL) { if (s->session == NULL || s->session->master_key_length == 0) { /* might happen if dtls1_read_bytes() calls this */ SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, SSL_R_CCS_RECEIVED_EARLY); return (0); } s->session->cipher = s->s3->tmp.new_cipher; if (!s->method->ssl3_enc->setup_key_block(s)) return (0); } if (!s->method->ssl3_enc->change_cipher_state(s, i)) return (0); /* * we have to record the message digest at this point so we can get it * before we read the finished message */ if (s->state & SSL_ST_CONNECT) { sender = s->method->ssl3_enc->server_finished_label; slen = s->method->ssl3_enc->server_finished_label_len; } else { sender = s->method->ssl3_enc->client_finished_label; slen = s->method->ssl3_enc->client_finished_label_len; } s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s, & (s->s3->finish_dgst1), & (s->s3->finish_dgst2), sender, slen, s->s3->tmp.peer_finish_md); return (1); } int ssl3_send_alert(SSL *s, int level, int desc) { /* Map tls/ssl alert value to correct one */ desc = s->method->ssl3_enc->alert_value(desc); if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION) desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have * protocol_version alerts */ if (desc < 0) return -1; /* If a fatal one, remove from cache */ if ((level == 2) && (s->session != NULL)) SSL_CTX_remove_session(s->ctx, s->session); s->s3->alert_dispatch = 1; s->s3->send_alert[0] = level; s->s3->send_alert[1] = desc; if (s->s3->wbuf.left == 0) /* data still being written out? */ return s->method->ssl_dispatch_alert(s); /* * else data is still being written out, we will get written some time in * the future */ return -1; } int ssl3_dispatch_alert(SSL *s) { int i, j; void (*cb) (const SSL *ssl, int type, int val) = NULL; s->s3->alert_dispatch = 0; i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0); if (i <= 0) { s->s3->alert_dispatch = 1; } else { /* * Alert sent to BIO. If it is important, flush it now. If the * message does not get sent due to non-blocking IO, we will not * worry too much. */ if (s->s3->send_alert[0] == SSL3_AL_FATAL) (void)BIO_flush(s->wbio); if (s->msg_callback) s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, 2, s, s->msg_callback_arg); if (s->info_callback != NULL) cb = s->info_callback; else if (s->ctx->info_callback != NULL) cb = s->ctx->info_callback; if (cb != NULL) { j = (s->s3->send_alert[0] << 8) | s->s3->send_alert[1]; cb(s, SSL_CB_WRITE_ALERT, j); } } return (i); } Index: releng/9.3/crypto/openssl/ssl/ssl.h =================================================================== --- releng/9.3/crypto/openssl/ssl/ssl.h (revision 308204) +++ releng/9.3/crypto/openssl/ssl/ssl.h (revision 308205) @@ -1,2245 +1,2246 @@ /* ssl/ssl.h */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ /* ==================================================================== * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ /* ==================================================================== * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * ECC cipher suite support in OpenSSL originally developed by * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ #ifndef HEADER_SSL_H # define HEADER_SSL_H # include # ifndef OPENSSL_NO_COMP # include # endif # ifndef OPENSSL_NO_BIO # include # endif # ifndef OPENSSL_NO_DEPRECATED # ifndef OPENSSL_NO_X509 # include # endif # include # include # include # endif # include # include # include # include # include #ifdef __cplusplus extern "C" { #endif /* SSLeay version number for ASN.1 encoding of the session information */ /*- * Version 0 - initial version * Version 1 - added the optional peer certificate */ # define SSL_SESSION_ASN1_VERSION 0x0001 /* text strings for the ciphers */ # define SSL_TXT_NULL_WITH_MD5 SSL2_TXT_NULL_WITH_MD5 # define SSL_TXT_RC4_128_WITH_MD5 SSL2_TXT_RC4_128_WITH_MD5 # define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5 # define SSL_TXT_RC2_128_CBC_WITH_MD5 SSL2_TXT_RC2_128_CBC_WITH_MD5 # define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 # define SSL_TXT_IDEA_128_CBC_WITH_MD5 SSL2_TXT_IDEA_128_CBC_WITH_MD5 # define SSL_TXT_DES_64_CBC_WITH_MD5 SSL2_TXT_DES_64_CBC_WITH_MD5 # define SSL_TXT_DES_64_CBC_WITH_SHA SSL2_TXT_DES_64_CBC_WITH_SHA # define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5 # define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA /* * VRS Additional Kerberos5 entries */ # define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA # define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA # define SSL_TXT_KRB5_RC4_128_SHA SSL3_TXT_KRB5_RC4_128_SHA # define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA # define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5 # define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5 # define SSL_TXT_KRB5_RC4_128_MD5 SSL3_TXT_KRB5_RC4_128_MD5 # define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5 # define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA # define SSL_TXT_KRB5_RC2_40_CBC_SHA SSL3_TXT_KRB5_RC2_40_CBC_SHA # define SSL_TXT_KRB5_RC4_40_SHA SSL3_TXT_KRB5_RC4_40_SHA # define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5 # define SSL_TXT_KRB5_RC2_40_CBC_MD5 SSL3_TXT_KRB5_RC2_40_CBC_MD5 # define SSL_TXT_KRB5_RC4_40_MD5 SSL3_TXT_KRB5_RC4_40_MD5 # define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA # define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5 # define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA # define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5 # define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA # define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5 # define SSL_MAX_KRB5_PRINCIPAL_LENGTH 256 # define SSL_MAX_SSL_SESSION_ID_LENGTH 32 # define SSL_MAX_SID_CTX_LENGTH 32 # define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES (512/8) # define SSL_MAX_KEY_ARG_LENGTH 8 # define SSL_MAX_MASTER_KEY_LENGTH 48 /* These are used to specify which ciphers to use and not to use */ # define SSL_TXT_LOW "LOW" # define SSL_TXT_MEDIUM "MEDIUM" # define SSL_TXT_HIGH "HIGH" # define SSL_TXT_FIPS "FIPS" # define SSL_TXT_kFZA "kFZA" # define SSL_TXT_aFZA "aFZA" # define SSL_TXT_eFZA "eFZA" # define SSL_TXT_FZA "FZA" # define SSL_TXT_aNULL "aNULL" # define SSL_TXT_eNULL "eNULL" # define SSL_TXT_NULL "NULL" # define SSL_TXT_kKRB5 "kKRB5" # define SSL_TXT_aKRB5 "aKRB5" # define SSL_TXT_KRB5 "KRB5" # define SSL_TXT_kRSA "kRSA" # define SSL_TXT_kDHr "kDHr" # define SSL_TXT_kDHd "kDHd" # define SSL_TXT_kEDH "kEDH" # define SSL_TXT_aRSA "aRSA" # define SSL_TXT_aDSS "aDSS" # define SSL_TXT_aDH "aDH" # define SSL_TXT_DSS "DSS" # define SSL_TXT_DH "DH" # define SSL_TXT_EDH "EDH" # define SSL_TXT_ADH "ADH" # define SSL_TXT_RSA "RSA" # define SSL_TXT_DES "DES" # define SSL_TXT_3DES "3DES" # define SSL_TXT_RC4 "RC4" # define SSL_TXT_RC2 "RC2" # define SSL_TXT_IDEA "IDEA" # define SSL_TXT_SEED "SEED" # define SSL_TXT_AES "AES" # define SSL_TXT_CAMELLIA "CAMELLIA" # define SSL_TXT_MD5 "MD5" # define SSL_TXT_SHA1 "SHA1" # define SSL_TXT_SHA "SHA" # define SSL_TXT_EXP "EXP" # define SSL_TXT_EXPORT "EXPORT" # define SSL_TXT_EXP40 "EXPORT40" # define SSL_TXT_EXP56 "EXPORT56" # define SSL_TXT_SSLV2 "SSLv2" # define SSL_TXT_SSLV3 "SSLv3" # define SSL_TXT_TLSV1 "TLSv1" # define SSL_TXT_ALL "ALL" # define SSL_TXT_ECC "ECCdraft"/* ECC ciphersuites are not yet * official */ /*- * COMPLEMENTOF* definitions. These identifiers are used to (de-select) * ciphers normally not being used. * Example: "RC4" will activate all ciphers using RC4 including ciphers * without authentication, which would normally disabled by DEFAULT (due * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT" * will make sure that it is also disabled in the specific selection. * COMPLEMENTOF* identifiers are portable between version, as adjustments * to the default cipher setup will also be included here. * * COMPLEMENTOFDEFAULT does not experience the same special treatment that * DEFAULT gets, as only selection is being done and no sorting as needed * for DEFAULT. */ # define SSL_TXT_CMPALL "COMPLEMENTOFALL" # define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" /* * The following cipher list is used by default. It also is substituted when * an application-defined cipher list string starts with 'DEFAULT'. */ # define SSL_DEFAULT_CIPHER_LIST "ALL:!EXPORT:!aNULL:!eNULL:!SSLv2:@STRENGTH" /* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ # define SSL_SENT_SHUTDOWN 1 # define SSL_RECEIVED_SHUTDOWN 2 #ifdef __cplusplus } #endif #ifdef __cplusplus extern "C" { #endif # if (defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_MD5)) && !defined(OPENSSL_NO_SSL2) # define OPENSSL_NO_SSL2 # endif # define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1 # define SSL_FILETYPE_PEM X509_FILETYPE_PEM /* * This is needed to stop compilers complaining about the 'struct ssl_st *' * function parameters used to prototype callbacks in SSL_CTX. */ typedef struct ssl_st *ssl_crock_st; /* used to hold info on the particular ciphers used */ typedef struct ssl_cipher_st { int valid; const char *name; /* text name */ unsigned long id; /* id, 4 bytes, first is version */ unsigned long algorithms; /* what ciphers are used */ unsigned long algo_strength; /* strength and export flags */ unsigned long algorithm2; /* Extra flags */ int strength_bits; /* Number of bits really used */ int alg_bits; /* Number of bits for algorithm */ unsigned long mask; /* used for matching */ unsigned long mask_strength; /* also used for matching */ } SSL_CIPHER; DECLARE_STACK_OF(SSL_CIPHER) /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ typedef struct ssl_method_st { int version; int (*ssl_new) (SSL *s); void (*ssl_clear) (SSL *s); void (*ssl_free) (SSL *s); int (*ssl_accept) (SSL *s); int (*ssl_connect) (SSL *s); int (*ssl_read) (SSL *s, void *buf, int len); int (*ssl_peek) (SSL *s, void *buf, int len); int (*ssl_write) (SSL *s, const void *buf, int len); int (*ssl_shutdown) (SSL *s); int (*ssl_renegotiate) (SSL *s); int (*ssl_renegotiate_check) (SSL *s); long (*ssl_get_message) (SSL *s, int st1, int stn, int mt, long max, int *ok); int (*ssl_read_bytes) (SSL *s, int type, unsigned char *buf, int len, int peek); int (*ssl_write_bytes) (SSL *s, int type, const void *buf_, int len); int (*ssl_dispatch_alert) (SSL *s); long (*ssl_ctrl) (SSL *s, int cmd, long larg, void *parg); long (*ssl_ctx_ctrl) (SSL_CTX *ctx, int cmd, long larg, void *parg); SSL_CIPHER *(*get_cipher_by_char) (const unsigned char *ptr); int (*put_cipher_by_char) (const SSL_CIPHER *cipher, unsigned char *ptr); int (*ssl_pending) (const SSL *s); int (*num_ciphers) (void); SSL_CIPHER *(*get_cipher) (unsigned ncipher); struct ssl_method_st *(*get_ssl_method) (int version); long (*get_timeout) (void); struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */ int (*ssl_version) (void); long (*ssl_callback_ctrl) (SSL *s, int cb_id, void (*fp) (void)); long (*ssl_ctx_callback_ctrl) (SSL_CTX *s, int cb_id, void (*fp) (void)); } SSL_METHOD; /*- * Lets make this into an ASN.1 type structure as follows * SSL_SESSION_ID ::= SEQUENCE { * version INTEGER, -- structure version number * SSLversion INTEGER, -- SSL version number * Cipher OCTET_STRING, -- the 3 byte cipher ID * Session_ID OCTET_STRING, -- the Session ID * Master_key OCTET_STRING, -- the master key * KRB5_principal OCTET_STRING -- optional Kerberos principal * Key_Arg [ 0 ] IMPLICIT OCTET_STRING, -- the optional Key argument * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate * Session_ID_context [ 4 ] EXPLICIT OCTET_STRING, -- the Session ID context * Verify_result [ 5 ] EXPLICIT INTEGER -- X509_V_... code for `Peer' * Compression [6] IMPLICIT ASN1_OBJECT -- compression OID XXXXX * } * Look in ssl/ssl_asn1.c for more details * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-). */ typedef struct ssl_session_st { int ssl_version; /* what ssl version session info is being * kept in here? */ /* only really used in SSLv2 */ unsigned int key_arg_length; unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH]; int master_key_length; unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; /* session_id - valid? */ unsigned int session_id_length; unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; /* * this is used to determine whether the session is being reused in the * appropriate context. It is up to the application to set this, via * SSL_new */ unsigned int sid_ctx_length; unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; # ifndef OPENSSL_NO_KRB5 unsigned int krb5_client_princ_len; unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH]; # endif /* OPENSSL_NO_KRB5 */ int not_resumable; /* The cert is the certificate used to establish this connection */ struct sess_cert_st /* SESS_CERT */ *sess_cert; /* * This is the cert for the other end. On clients, it will be the same as * sess_cert->peer_key->x509 (the latter is not enough as sess_cert is * not retained in the external representation of sessions, see * ssl_asn1.c). */ X509 *peer; /* * when app_verify_callback accepts a session where the peer's * certificate is not ok, we must remember the error for session reuse: */ long verify_result; /* only for servers */ int references; long timeout; long time; int compress_meth; /* Need to lookup the method */ SSL_CIPHER *cipher; unsigned long cipher_id; /* when ASN.1 loaded, this needs to be used * to load the 'cipher' structure */ STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */ CRYPTO_EX_DATA ex_data; /* application specific data */ /* * These are used to make removal of session-ids more efficient and to * implement a maximum cache size. */ struct ssl_session_st *prev, *next; # ifndef OPENSSL_NO_TLSEXT char *tlsext_hostname; /* RFC4507 info */ unsigned char *tlsext_tick; /* Session ticket */ size_t tlsext_ticklen; /* Session ticket length */ long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ # endif } SSL_SESSION; # define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L # define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L /* Allow initial connection to servers that don't support RI */ # define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L # define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L # define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L # define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L # define SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040L # define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L # define SSL_OP_TLS_D5_BUG 0x00000100L # define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L /* Hasn't done anything since OpenSSL 0.9.7h, retained for compatibility */ # define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x0 /* * Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added in * OpenSSL 0.9.6d. Usually (depending on the application protocol) the * workaround is not needed. Unfortunately some broken SSL/TLS * implementations cannot handle it at all, which is why we include it in * SSL_OP_ALL. */ /* added in 0.9.6e */ # define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800L /* * SSL_OP_ALL: various bug workarounds that should be rather harmless. This * used to be 0x000FFFFFL before 0.9.7. */ # define SSL_OP_ALL 0x00000FFFL /* DTLS options */ # define SSL_OP_NO_QUERY_MTU 0x00001000L /* Turn on Cookie Exchange (on relevant for servers) */ # define SSL_OP_COOKIE_EXCHANGE 0x00002000L /* Don't use RFC4507 ticket extension */ # define SSL_OP_NO_TICKET 0x00004000L /* Use Cisco's "speshul" version of DTLS_BAD_VER (as client) */ # define SSL_OP_CISCO_ANYCONNECT 0x00008000L /* As server, disallow session resumption on renegotiation */ # define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L /* Permit unsafe legacy renegotiation */ # define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L /* If set, always create a new key when using tmp_ecdh parameters */ # define SSL_OP_SINGLE_ECDH_USE 0x00080000L /* If set, always create a new key when using tmp_dh parameters */ # define SSL_OP_SINGLE_DH_USE 0x00100000L /* Does nothing: retained for compatibiity */ # define SSL_OP_EPHEMERAL_RSA 0x0 /* * Set on servers to choose the cipher according to the server's preferences */ # define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L /* * If set, a server will allow a client to issue a SSLv3.0 version number as * latest version supported in the premaster secret, even when TLSv1.0 * (version 3.1) was announced in the client hello. Normally this is * forbidden to prevent version rollback attacks. */ # define SSL_OP_TLS_ROLLBACK_BUG 0x00800000L # define SSL_OP_NO_SSLv2 0x01000000L # define SSL_OP_NO_SSLv3 0x02000000L # define SSL_OP_NO_TLSv1 0x04000000L /* * The next flag deliberately changes the ciphertest, this is a check for the * PKCS#1 attack */ # define SSL_OP_PKCS1_CHECK_1 0x08000000L # define SSL_OP_PKCS1_CHECK_2 0x10000000L # define SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000L # define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000L /* * Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success * when just a single record has been written): */ # define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L /* * Make it possible to retry SSL_write() with changed buffer location (buffer * contents must stay the same!); this is not the default to avoid the * misconception that non-blocking SSL_write() behaves like non-blocking * write(): */ # define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L /* * Never bother the application with retries if the transport is blocking: */ # define SSL_MODE_AUTO_RETRY 0x00000004L /* Don't attempt to automatically build certificate chain */ # define SSL_MODE_NO_AUTO_CHAIN 0x00000008L /* * Send TLS_FALLBACK_SCSV in the ClientHello. To be set only by applications * that reconnect with a downgraded protocol version; see * draft-ietf-tls-downgrade-scsv-00 for details. DO NOT ENABLE THIS if your * application attempts a normal handshake. Only use this in explicit * fallback retries, following the guidance in * draft-ietf-tls-downgrade-scsv-00. */ # define SSL_MODE_SEND_FALLBACK_SCSV 0x00000080L /* * Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, they * cannot be used to clear bits. */ # define SSL_CTX_set_options(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) # define SSL_CTX_clear_options(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL) # define SSL_CTX_get_options(ctx) \ SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL) # define SSL_set_options(ssl,op) \ SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL) # define SSL_clear_options(ssl,op) \ SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL) # define SSL_get_options(ssl) \ SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL) # define SSL_CTX_set_mode(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) # define SSL_CTX_clear_mode(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL) # define SSL_CTX_get_mode(ctx) \ SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL) # define SSL_clear_mode(ssl,op) \ SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL) # define SSL_set_mode(ssl,op) \ SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL) # define SSL_get_mode(ssl) \ SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL) # define SSL_set_mtu(ssl, mtu) \ SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL) # define SSL_get_secure_renegotiation_support(ssl) \ SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL) void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb) (int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)); void SSL_set_msg_callback(SSL *ssl, void (*cb) (int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)); # define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) # define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) # if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32) # define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */ # else # define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */ # endif # define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024*20) /* * This callback type is used inside SSL_CTX, SSL, and in the functions that * set them. It is used to override the generation of SSL/TLS session IDs in * a server. Return value should be zero on an error, non-zero to proceed. * Also, callbacks should themselves check if the id they generate is unique * otherwise the SSL handshake will fail with an error - callbacks can do * this using the 'ssl' value they're passed by; * SSL_has_matching_session_id(ssl, id, *id_len) The length value passed in * is set at the maximum size the session ID can be. In SSLv2 this is 16 * bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback can alter this * length to be less if desired, but under SSLv2 session IDs are supposed to * be fixed at 16 bytes so the id will be padded after the callback returns * in this case. It is also an error for the callback to set the size to * zero. */ typedef int (*GEN_SESSION_CB) (const SSL *ssl, unsigned char *id, unsigned int *id_len); typedef struct ssl_comp_st { int id; const char *name; # ifndef OPENSSL_NO_COMP COMP_METHOD *method; # else char *method; # endif } SSL_COMP; DECLARE_STACK_OF(SSL_COMP) struct ssl_ctx_st { SSL_METHOD *method; STACK_OF(SSL_CIPHER) *cipher_list; /* same as above but sorted for lookup */ STACK_OF(SSL_CIPHER) *cipher_list_by_id; struct x509_store_st /* X509_STORE */ *cert_store; struct lhash_st /* LHASH */ *sessions; /* a set of SSL_SESSIONs */ /* * Most session-ids that will be cached, default is * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */ unsigned long session_cache_size; struct ssl_session_st *session_cache_head; struct ssl_session_st *session_cache_tail; /* * This can have one of 2 values, ored together, SSL_SESS_CACHE_CLIENT, * SSL_SESS_CACHE_SERVER, Default is SSL_SESSION_CACHE_SERVER, which * means only SSL_accept which cache SSL_SESSIONS. */ int session_cache_mode; /* * If timeout is not 0, it is the default timeout value set when * SSL_new() is called. This has been put in to make life easier to set * things up */ long session_timeout; /* * If this callback is not null, it will be called each time a session id * is added to the cache. If this function returns 1, it means that the * callback will do a SSL_SESSION_free() when it has finished using it. * Otherwise, on 0, it means the callback has finished with it. If * remove_session_cb is not null, it will be called when a session-id is * removed from the cache. After the call, OpenSSL will * SSL_SESSION_free() it. */ int (*new_session_cb) (struct ssl_st *ssl, SSL_SESSION *sess); void (*remove_session_cb) (struct ssl_ctx_st *ctx, SSL_SESSION *sess); SSL_SESSION *(*get_session_cb) (struct ssl_st *ssl, unsigned char *data, int len, int *copy); struct { int sess_connect; /* SSL new conn - started */ int sess_connect_renegotiate; /* SSL reneg - requested */ int sess_connect_good; /* SSL new conne/reneg - finished */ int sess_accept; /* SSL new accept - started */ int sess_accept_renegotiate; /* SSL reneg - requested */ int sess_accept_good; /* SSL accept/reneg - finished */ int sess_miss; /* session lookup misses */ int sess_timeout; /* reuse attempt on timeouted session */ int sess_cache_full; /* session removed due to full cache */ int sess_hit; /* session reuse actually done */ int sess_cb_hit; /* session-id that was not in the cache was * passed back via the callback. This * indicates that the application is * supplying session-id's from other * processes - spooky :-) */ } stats; int references; /* if defined, these override the X509_verify_cert() calls */ int (*app_verify_callback) (X509_STORE_CTX *, void *); void *app_verify_arg; /* * before OpenSSL 0.9.7, 'app_verify_arg' was ignored * ('app_verify_callback' was called with just one argument) */ /* Default password callback. */ pem_password_cb *default_passwd_callback; /* Default password callback user data. */ void *default_passwd_callback_userdata; /* get client cert callback */ int (*client_cert_cb) (SSL *ssl, X509 **x509, EVP_PKEY **pkey); /* cookie generate callback */ int (*app_gen_cookie_cb) (SSL *ssl, unsigned char *cookie, unsigned int *cookie_len); /* verify cookie callback */ int (*app_verify_cookie_cb) (SSL *ssl, unsigned char *cookie, unsigned int cookie_len); CRYPTO_EX_DATA ex_data; const EVP_MD *rsa_md5; /* For SSLv2 - name is 'ssl2-md5' */ const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */ const EVP_MD *sha1; /* For SSLv3/TLSv1 'ssl3->sha1' */ STACK_OF(X509) *extra_certs; STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */ /* Default values used when no per-SSL value is defined follow */ /* used if SSL's info_callback is NULL */ void (*info_callback) (const SSL *ssl, int type, int val); /* what we put in client cert requests */ STACK_OF(X509_NAME) *client_CA; /* * Default values to use in SSL structures follow (these are copied by * SSL_new) */ unsigned long options; unsigned long mode; long max_cert_list; struct cert_st /* CERT */ *cert; int read_ahead; /* callback that allows applications to peek at protocol messages */ void (*msg_callback) (int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg); void *msg_callback_arg; int verify_mode; unsigned int sid_ctx_length; unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; /* called 'verify_callback' in the SSL */ int (*default_verify_callback) (int ok, X509_STORE_CTX *ctx); /* Default generate session ID callback. */ GEN_SESSION_CB generate_session_id; X509_VERIFY_PARAM *param; # if 0 int purpose; /* Purpose setting */ int trust; /* Trust setting */ # endif int quiet_shutdown; # ifndef OPENSSL_ENGINE /* * Engine to pass requests for client certs to */ ENGINE *client_cert_engine; # endif # ifndef OPENSSL_NO_TLSEXT /* TLS extensions servername callback */ int (*tlsext_servername_callback) (SSL *, int *, void *); void *tlsext_servername_arg; /* RFC 4507 session ticket keys */ unsigned char tlsext_tick_key_name[16]; unsigned char tlsext_tick_hmac_key[16]; unsigned char tlsext_tick_aes_key[16]; /* Callback to support customisation of ticket key setting */ int (*tlsext_ticket_key_cb) (SSL *ssl, unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); /* certificate status request info */ /* Callback for status request */ int (*tlsext_status_cb) (SSL *ssl, void *arg); void *tlsext_status_arg; # endif }; # define SSL_SESS_CACHE_OFF 0x0000 # define SSL_SESS_CACHE_CLIENT 0x0001 # define SSL_SESS_CACHE_SERVER 0x0002 # define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER) # define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080 /* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */ # define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100 # define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200 # define SSL_SESS_CACHE_NO_INTERNAL \ (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE) struct lhash_st *SSL_CTX_sessions(SSL_CTX *ctx); # define SSL_CTX_sess_number(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL) # define SSL_CTX_sess_connect(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL) # define SSL_CTX_sess_connect_good(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL) # define SSL_CTX_sess_connect_renegotiate(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL) # define SSL_CTX_sess_accept(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL) # define SSL_CTX_sess_accept_renegotiate(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL) # define SSL_CTX_sess_accept_good(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL) # define SSL_CTX_sess_hits(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL) # define SSL_CTX_sess_cb_hits(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL) # define SSL_CTX_sess_misses(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL) # define SSL_CTX_sess_timeouts(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL) # define SSL_CTX_sess_cache_full(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL) void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*new_session_cb) (struct ssl_st *ssl, SSL_SESSION *sess)); int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx)) (struct ssl_st *ssl, SSL_SESSION *sess); void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb) (struct ssl_ctx_st *ctx, SSL_SESSION *sess)); void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx)) (struct ssl_ctx_st *ctx, SSL_SESSION *sess); void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb) (struct ssl_st *ssl, unsigned char *data, int len, int *copy)); SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx)) (struct ssl_st *ssl, unsigned char *Data, int len, int *copy); void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb) (const SSL *ssl, int type, int val)); void (*SSL_CTX_get_info_callback(SSL_CTX *ctx)) (const SSL *ssl, int type, int val); void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb) (SSL *ssl, X509 **x509, EVP_PKEY **pkey)); int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx)) (SSL *ssl, X509 **x509, EVP_PKEY **pkey); # ifndef OPENSSL_NO_ENGINE int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e); # endif void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb) (SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)); void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb) (SSL *ssl, unsigned char *cookie, unsigned int cookie_len)); # define SSL_NOTHING 1 # define SSL_WRITING 2 # define SSL_READING 3 # define SSL_X509_LOOKUP 4 /* These will only be used when doing non-blocking IO */ # define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) # define SSL_want_read(s) (SSL_want(s) == SSL_READING) # define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) # define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP) struct ssl_st { /* * protocol version (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, * DTLS1_VERSION) */ int version; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */ int type; /* SSLv3 */ SSL_METHOD *method; /* * There are 2 BIO's even though they are normally both the same. This * is so data can be read and written to different handlers */ # ifndef OPENSSL_NO_BIO /* used by SSL_read */ BIO *rbio; /* used by SSL_write */ BIO *wbio; /* used during session-id reuse to concatenate messages */ BIO *bbio; # else /* used by SSL_read */ char *rbio; /* used by SSL_write */ char *wbio; char *bbio; # endif /* * This holds a variable that indicates what we were doing when a 0 or -1 * is returned. This is needed for non-blocking IO so we know what * request needs re-doing when in SSL_accept or SSL_connect */ int rwstate; /* true when we are actually in SSL_accept() or SSL_connect() */ int in_handshake; int (*handshake_func) (SSL *); /* * Imagine that here's a boolean member "init" that is switched as soon * as SSL_set_{accept/connect}_state is called for the first time, so * that "state" and "handshake_func" are properly initialized. But as * handshake_func is == 0 until then, we use this test instead of an * "init" member. */ /* are we the server side? - mostly used by SSL_clear */ int server; /* * 1 if we are to use a new session. * 2 if we are a server and are inside a handshake * (i.e. not just sending a HelloRequest) * NB: For servers, the 'new' session may actually be a previously * cached session or even the previous session unless * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */ int new_session; /* don't send shutdown packets */ int quiet_shutdown; /* we have shut things down, 0x01 sent, 0x02 for received */ int shutdown; /* where we are */ int state; /* where we are when reading */ int rstate; BUF_MEM *init_buf; /* buffer used during init */ void *init_msg; /* pointer to handshake message body, set by * ssl3_get_message() */ int init_num; /* amount read/written */ int init_off; /* amount read/written */ /* used internally to point at a raw packet */ unsigned char *packet; unsigned int packet_length; struct ssl2_state_st *s2; /* SSLv2 variables */ struct ssl3_state_st *s3; /* SSLv3 variables */ struct dtls1_state_st *d1; /* DTLSv1 variables */ int read_ahead; /* Read as many input bytes as possible (for * non-blocking reads) */ /* callback that allows applications to peek at protocol messages */ void (*msg_callback) (int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg); void *msg_callback_arg; int hit; /* reusing a previous session */ X509_VERIFY_PARAM *param; # if 0 int purpose; /* Purpose setting */ int trust; /* Trust setting */ # endif /* crypto */ STACK_OF(SSL_CIPHER) *cipher_list; STACK_OF(SSL_CIPHER) *cipher_list_by_id; /* * These are the ones being used, the ones in SSL_SESSION are the ones to * be 'copied' into these ones */ EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ const EVP_MD *read_hash; /* used for mac generation */ # ifndef OPENSSL_NO_COMP COMP_CTX *expand; /* uncompress */ # else char *expand; # endif EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */ const EVP_MD *write_hash; /* used for mac generation */ # ifndef OPENSSL_NO_COMP COMP_CTX *compress; /* compression */ # else char *compress; # endif /* session info */ /* client cert? */ /* This is used to hold the server certificate used */ struct cert_st /* CERT */ *cert; /* * the session_id_context is used to ensure sessions are only reused in * the appropriate context */ unsigned int sid_ctx_length; unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; /* This can also be in the session once a session is established */ SSL_SESSION *session; /* Default generate session ID callback. */ GEN_SESSION_CB generate_session_id; /* Used in SSL2 and SSL3 */ /* * 0 don't care about verify failure. * 1 fail if verify fails */ int verify_mode; /* fail if callback returns 0 */ int (*verify_callback) (int ok, X509_STORE_CTX *ctx); /* optional informational callback */ void (*info_callback) (const SSL *ssl, int type, int val); /* error bytes to be written */ int error; /* actual code */ int error_code; # ifndef OPENSSL_NO_KRB5 /* Kerberos 5 context */ KSSL_CTX *kssl_ctx; # endif /* OPENSSL_NO_KRB5 */ SSL_CTX *ctx; /* * set this flag to 1 and a sleep(1) is put into all SSL_read() and * SSL_write() calls, good for nbio debuging :-) */ int debug; /* extra application data */ long verify_result; CRYPTO_EX_DATA ex_data; /* for server side, keep the list of CA_dn we can use */ STACK_OF(X509_NAME) *client_CA; int references; /* protocol behaviour */ unsigned long options; /* API behaviour */ unsigned long mode; long max_cert_list; int first_packet; /* what was passed, used for SSLv3/TLS rollback check */ int client_version; # ifndef OPENSSL_NO_TLSEXT /* TLS extension debug callback */ void (*tlsext_debug_cb) (SSL *s, int client_server, int type, unsigned char *data, int len, void *arg); void *tlsext_debug_arg; char *tlsext_hostname; /*- * no further mod of servername * 0 : call the servername extension callback. * 1 : prepare 2, allow last ack just after in server callback. * 2 : don't call servername callback, no ack in server hello */ int servername_done; /* certificate status request info */ /* Status type or -1 if no status type */ int tlsext_status_type; /* Expect OCSP CertificateStatus message */ int tlsext_status_expected; /* OCSP status request only */ STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids; X509_EXTENSIONS *tlsext_ocsp_exts; /* OCSP response received or to be sent */ unsigned char *tlsext_ocsp_resp; int tlsext_ocsp_resplen; /* RFC4507 session ticket expected to be received or sent */ int tlsext_ticket_expected; SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */ # define session_ctx initial_ctx # else # define session_ctx ctx # endif }; #ifdef __cplusplus } #endif # include # include # include /* This is mostly sslv3 with a few tweaks */ # include /* Datagram TLS */ # include #ifdef __cplusplus extern "C" { #endif /* compatibility */ # define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg)) # define SSL_get_app_data(s) (SSL_get_ex_data(s,0)) # define SSL_SESSION_set_app_data(s,a) (SSL_SESSION_set_ex_data(s,0,(char *)a)) # define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s,0)) # define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx,0)) # define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg)) /* * The following are the possible values for ssl->state are are used to * indicate where we are up to in the SSL connection establishment. The * macros that follow are about the only things you should need to use and * even then, only when using non-blocking IO. It can also be useful to work * out where you were when the connection failed */ # define SSL_ST_CONNECT 0x1000 # define SSL_ST_ACCEPT 0x2000 # define SSL_ST_MASK 0x0FFF # define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT) # define SSL_ST_BEFORE 0x4000 # define SSL_ST_OK 0x03 # define SSL_ST_RENEGOTIATE (0x04|SSL_ST_INIT) # define SSL_CB_LOOP 0x01 # define SSL_CB_EXIT 0x02 # define SSL_CB_READ 0x04 # define SSL_CB_WRITE 0x08 # define SSL_CB_ALERT 0x4000/* used in callback */ # define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ) # define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE) # define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP) # define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT) # define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP) # define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT) # define SSL_CB_HANDSHAKE_START 0x10 # define SSL_CB_HANDSHAKE_DONE 0x20 /* Is the SSL_connection established? */ # define SSL_get_state(a) SSL_state(a) # define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK) # define SSL_in_init(a) (SSL_state(a)&SSL_ST_INIT) # define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE) # define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT) # define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT) /* * The following 2 states are kept in ssl->rstate when reads fail, you should * not need these */ # define SSL_ST_READ_HEADER 0xF0 # define SSL_ST_READ_BODY 0xF1 # define SSL_ST_READ_DONE 0xF2 /*- * Obtain latest Finished message * -- that we sent (SSL_get_finished) * -- that we expected from peer (SSL_get_peer_finished). * Returns length (0 == no Finished so far), copies up to 'count' bytes. */ size_t SSL_get_finished(const SSL *s, void *buf, size_t count); size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); /* * use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options are * 'ored' with SSL_VERIFY_PEER if they are desired */ # define SSL_VERIFY_NONE 0x00 # define SSL_VERIFY_PEER 0x01 # define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 # define SSL_VERIFY_CLIENT_ONCE 0x04 # define OpenSSL_add_ssl_algorithms() SSL_library_init() # define SSLeay_add_ssl_algorithms() SSL_library_init() /* this is for backward compatibility */ # if 0 /* NEW_SSLEAY */ # define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c) # define SSL_set_pref_cipher(c,n) SSL_set_cipher_list(c,n) # define SSL_add_session(a,b) SSL_CTX_add_session((a),(b)) # define SSL_remove_session(a,b) SSL_CTX_remove_session((a),(b)) # define SSL_flush_sessions(a,b) SSL_CTX_flush_sessions((a),(b)) # endif /* More backward compatibility */ # define SSL_get_cipher(s) \ SSL_CIPHER_get_name(SSL_get_current_cipher(s)) # define SSL_get_cipher_bits(s,np) \ SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np) # define SSL_get_cipher_version(s) \ SSL_CIPHER_get_version(SSL_get_current_cipher(s)) # define SSL_get_cipher_name(s) \ SSL_CIPHER_get_name(SSL_get_current_cipher(s)) # define SSL_get_time(a) SSL_SESSION_get_time(a) # define SSL_set_time(a,b) SSL_SESSION_set_time((a),(b)) # define SSL_get_timeout(a) SSL_SESSION_get_timeout(a) # define SSL_set_timeout(a,b) SSL_SESSION_set_timeout((a),(b)) # if 1 /* SSLEAY_MACROS */ # define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id) # define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id) # define PEM_read_SSL_SESSION(fp,x,cb,u) (SSL_SESSION *)PEM_ASN1_read( \ (char *(*)())d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,fp,(char **)x,cb,u) # define PEM_read_bio_SSL_SESSION(bp,x,cb,u) PEM_ASN1_read_bio_of(SSL_SESSION,d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,cb,u) # define PEM_write_SSL_SESSION(fp,x) \ PEM_ASN1_write((int (*)())i2d_SSL_SESSION, \ PEM_STRING_SSL_SESSION,fp, (char *)x, NULL,NULL,0,NULL,NULL) # define PEM_write_bio_SSL_SESSION(bp,x) \ PEM_ASN1_write_bio_of(SSL_SESSION,i2d_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,NULL,NULL,0,NULL,NULL) # endif # define SSL_AD_REASON_OFFSET 1000 /* These alert types are for SSLv3 and TLSv1 */ # define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY /* fatal */ # define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */ # define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC # define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED # define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW /* fatal */ # define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE /* fatal */ # define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE /* Not for TLS */ # define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE # define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE # define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE # define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED # define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED # define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN /* fatal */ # define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */ # define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */ # define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */ # define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR # define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR /* fatal */ # define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION /* fatal */ # define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */ # define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY /* fatal */ # define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR # define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED # define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION # define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION # define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE # define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME # define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE # define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE /* fatal */ # define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */ # define SSL_AD_INAPPROPRIATE_FALLBACK TLS1_AD_INAPPROPRIATE_FALLBACK # define SSL_ERROR_NONE 0 # define SSL_ERROR_SSL 1 # define SSL_ERROR_WANT_READ 2 # define SSL_ERROR_WANT_WRITE 3 # define SSL_ERROR_WANT_X509_LOOKUP 4 # define SSL_ERROR_SYSCALL 5/* look at error stack/return * value/errno */ # define SSL_ERROR_ZERO_RETURN 6 # define SSL_ERROR_WANT_CONNECT 7 # define SSL_ERROR_WANT_ACCEPT 8 # define SSL_CTRL_NEED_TMP_RSA 1 # define SSL_CTRL_SET_TMP_RSA 2 # define SSL_CTRL_SET_TMP_DH 3 # define SSL_CTRL_SET_TMP_ECDH 4 # define SSL_CTRL_SET_TMP_RSA_CB 5 # define SSL_CTRL_SET_TMP_DH_CB 6 # define SSL_CTRL_SET_TMP_ECDH_CB 7 # define SSL_CTRL_GET_SESSION_REUSED 8 # define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9 # define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10 # define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11 # define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12 # define SSL_CTRL_GET_FLAGS 13 # define SSL_CTRL_EXTRA_CHAIN_CERT 14 # define SSL_CTRL_SET_MSG_CALLBACK 15 # define SSL_CTRL_SET_MSG_CALLBACK_ARG 16 /* only applies to datagram connections */ # define SSL_CTRL_SET_MTU 17 /* Stats */ # define SSL_CTRL_SESS_NUMBER 20 # define SSL_CTRL_SESS_CONNECT 21 # define SSL_CTRL_SESS_CONNECT_GOOD 22 # define SSL_CTRL_SESS_CONNECT_RENEGOTIATE 23 # define SSL_CTRL_SESS_ACCEPT 24 # define SSL_CTRL_SESS_ACCEPT_GOOD 25 # define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE 26 # define SSL_CTRL_SESS_HIT 27 # define SSL_CTRL_SESS_CB_HIT 28 # define SSL_CTRL_SESS_MISSES 29 # define SSL_CTRL_SESS_TIMEOUTS 30 # define SSL_CTRL_SESS_CACHE_FULL 31 # define SSL_CTRL_OPTIONS 32 # define SSL_CTRL_MODE 33 # define SSL_CTRL_GET_READ_AHEAD 40 # define SSL_CTRL_SET_READ_AHEAD 41 # define SSL_CTRL_SET_SESS_CACHE_SIZE 42 # define SSL_CTRL_GET_SESS_CACHE_SIZE 43 # define SSL_CTRL_SET_SESS_CACHE_MODE 44 # define SSL_CTRL_GET_SESS_CACHE_MODE 45 # define SSL_CTRL_GET_MAX_CERT_LIST 50 # define SSL_CTRL_SET_MAX_CERT_LIST 51 /* see tls1.h for macros based on these */ # ifndef OPENSSL_NO_TLSEXT # define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53 # define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54 # define SSL_CTRL_SET_TLSEXT_HOSTNAME 55 # define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56 # define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57 # define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58 # define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59 # define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63 # define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64 # define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65 # define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66 # define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67 # define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68 # define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69 # define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70 # define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71 # define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72 # endif # define DTLS_CTRL_GET_TIMEOUT 73 # define DTLS_CTRL_HANDLE_TIMEOUT 74 # define DTLS_CTRL_LISTEN 75 # define SSL_CTRL_GET_RI_SUPPORT 76 # define SSL_CTRL_CLEAR_OPTIONS 77 # define SSL_CTRL_CLEAR_MODE 78 # define SSL_CTRL_CHECK_PROTO_VERSION 119 # define DTLSv1_get_timeout(ssl, arg) \ SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg) # define DTLSv1_handle_timeout(ssl) \ SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL) # define DTLSv1_listen(ssl, peer) \ SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer) # define SSL_session_reused(ssl) \ SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL) # define SSL_num_renegotiations(ssl) \ SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL) # define SSL_clear_num_renegotiations(ssl) \ SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL) # define SSL_total_renegotiations(ssl) \ SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL) # define SSL_CTX_need_tmp_RSA(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL) # define SSL_CTX_set_tmp_rsa(ctx,rsa) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) # define SSL_CTX_set_tmp_dh(ctx,dh) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh) # define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) # define SSL_need_tmp_RSA(ssl) \ SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL) # define SSL_set_tmp_rsa(ssl,rsa) \ SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) # define SSL_set_tmp_dh(ssl,dh) \ SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh) # define SSL_set_tmp_ecdh(ssl,ecdh) \ SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) # define SSL_CTX_add_extra_chain_cert(ctx,x509) \ SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509) # ifndef OPENSSL_NO_BIO BIO_METHOD *BIO_f_ssl(void); BIO *BIO_new_ssl(SSL_CTX *ctx, int client); BIO *BIO_new_ssl_connect(SSL_CTX *ctx); BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx); int BIO_ssl_copy_session_id(BIO *to, BIO *from); void BIO_ssl_shutdown(BIO *ssl_bio); # endif int SSL_CTX_set_cipher_list(SSL_CTX *, const char *str); SSL_CTX *SSL_CTX_new(SSL_METHOD *meth); void SSL_CTX_free(SSL_CTX *); long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); long SSL_CTX_get_timeout(const SSL_CTX *ctx); X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *); int SSL_want(const SSL *s); int SSL_clear(SSL *s); void SSL_CTX_flush_sessions(SSL_CTX *ctx, long tm); SSL_CIPHER *SSL_get_current_cipher(const SSL *s); int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits); char *SSL_CIPHER_get_version(const SSL_CIPHER *c); const char *SSL_CIPHER_get_name(const SSL_CIPHER *c); int SSL_get_fd(const SSL *s); int SSL_get_rfd(const SSL *s); int SSL_get_wfd(const SSL *s); const char *SSL_get_cipher_list(const SSL *s, int n); char *SSL_get_shared_ciphers(const SSL *s, char *buf, int len); int SSL_get_read_ahead(const SSL *s); int SSL_pending(const SSL *s); # ifndef OPENSSL_NO_SOCK int SSL_set_fd(SSL *s, int fd); int SSL_set_rfd(SSL *s, int fd); int SSL_set_wfd(SSL *s, int fd); # endif # ifndef OPENSSL_NO_BIO void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio); BIO *SSL_get_rbio(const SSL *s); BIO *SSL_get_wbio(const SSL *s); # endif int SSL_set_cipher_list(SSL *s, const char *str); void SSL_set_read_ahead(SSL *s, int yes); int SSL_get_verify_mode(const SSL *s); int SSL_get_verify_depth(const SSL *s); int (*SSL_get_verify_callback(const SSL *s)) (int, X509_STORE_CTX *); void SSL_set_verify(SSL *s, int mode, int (*callback) (int ok, X509_STORE_CTX *ctx)); void SSL_set_verify_depth(SSL *s, int depth); # ifndef OPENSSL_NO_RSA int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); # endif int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len); int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); int SSL_use_PrivateKey_ASN1(int pk, SSL *ssl, const unsigned char *d, long len); int SSL_use_certificate(SSL *ssl, X509 *x); int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len); # ifndef OPENSSL_NO_STDIO int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type); int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type); int SSL_use_certificate_file(SSL *ssl, const char *file, int type); int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); /* PEM type */ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, const char *file); # ifndef OPENSSL_SYS_VMS /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */ # ifndef OPENSSL_SYS_MACINTOSH_CLASSIC int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, const char *dir); # endif # endif # endif void SSL_load_error_strings(void); const char *SSL_state_string(const SSL *s); const char *SSL_rstate_string(const SSL *s); const char *SSL_state_string_long(const SSL *s); const char *SSL_rstate_string_long(const SSL *s); long SSL_SESSION_get_time(const SSL_SESSION *s); long SSL_SESSION_set_time(SSL_SESSION *s, long t); long SSL_SESSION_get_timeout(const SSL_SESSION *s); long SSL_SESSION_set_timeout(SSL_SESSION *s, long t); void SSL_copy_session_id(SSL *to, const SSL *from); SSL_SESSION *SSL_SESSION_new(void); unsigned long SSL_SESSION_hash(const SSL_SESSION *a); int SSL_SESSION_cmp(const SSL_SESSION *a, const SSL_SESSION *b); const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len); # ifndef OPENSSL_NO_FP_API int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *ses); # endif # ifndef OPENSSL_NO_BIO int SSL_SESSION_print(BIO *fp, const SSL_SESSION *ses); # endif void SSL_SESSION_free(SSL_SESSION *ses); int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp); int SSL_set_session(SSL *to, SSL_SESSION *session); int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); int SSL_CTX_remove_session(SSL_CTX *, SSL_SESSION *c); int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB); int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB); int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, unsigned int id_len); SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, long length); # ifdef HEADER_X509_H X509 *SSL_get_peer_certificate(const SSL *s); # endif STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s); int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx)) (int, X509_STORE_CTX *); void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*callback) (int, X509_STORE_CTX *)); void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb) (X509_STORE_CTX *, void *), void *arg); # ifndef OPENSSL_NO_RSA int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); # endif int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb); void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u); int SSL_CTX_check_private_key(const SSL_CTX *ctx); int SSL_check_private_key(const SSL *ctx); int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, unsigned int sid_ctx_len); SSL *SSL_new(SSL_CTX *ctx); int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx, unsigned int sid_ctx_len); int SSL_CTX_set_purpose(SSL_CTX *s, int purpose); int SSL_set_purpose(SSL *s, int purpose); int SSL_CTX_set_trust(SSL_CTX *s, int trust); int SSL_set_trust(SSL *s, int trust); void SSL_free(SSL *ssl); int SSL_accept(SSL *ssl); int SSL_connect(SSL *ssl); int SSL_read(SSL *ssl, void *buf, int num); int SSL_peek(SSL *ssl, void *buf, int num); int SSL_write(SSL *ssl, const void *buf, int num); long SSL_ctrl(SSL *ssl, int cmd, long larg, void *parg); long SSL_callback_ctrl(SSL *, int, void (*)(void)); long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void)); int SSL_get_error(const SSL *s, int ret_code); const char *SSL_get_version(const SSL *s); /* This sets the 'default' SSL version that SSL_new() will create */ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, SSL_METHOD *meth); SSL_METHOD *SSLv2_method(void); /* SSLv2 */ SSL_METHOD *SSLv2_server_method(void); /* SSLv2 */ SSL_METHOD *SSLv2_client_method(void); /* SSLv2 */ SSL_METHOD *SSLv3_method(void); /* SSLv3 */ SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */ SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */ SSL_METHOD *SSLv23_method(void); /* SSLv3 but can rollback to v2 */ SSL_METHOD *SSLv23_server_method(void); /* SSLv3 but can rollback to v2 */ SSL_METHOD *SSLv23_client_method(void); /* SSLv3 but can rollback to v2 */ SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */ SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */ SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */ SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */ SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */ SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s); int SSL_do_handshake(SSL *s); int SSL_renegotiate(SSL *s); int SSL_renegotiate_pending(SSL *s); int SSL_shutdown(SSL *s); SSL_METHOD *SSL_get_ssl_method(SSL *s); int SSL_set_ssl_method(SSL *s, SSL_METHOD *method); const char *SSL_alert_type_string_long(int value); const char *SSL_alert_type_string(int value); const char *SSL_alert_desc_string_long(int value); const char *SSL_alert_desc_string(int value); void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list); void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s); STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s); int SSL_add_client_CA(SSL *ssl, X509 *x); int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); void SSL_set_connect_state(SSL *s); void SSL_set_accept_state(SSL *s); long SSL_get_default_timeout(const SSL *s); int SSL_library_init(void); char *SSL_CIPHER_description(const SSL_CIPHER *, char *buf, int size); STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk); SSL *SSL_dup(SSL *ssl); X509 *SSL_get_certificate(const SSL *ssl); /* * EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(SSL *ssl); void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); void SSL_set_quiet_shutdown(SSL *ssl, int mode); int SSL_get_quiet_shutdown(const SSL *ssl); void SSL_set_shutdown(SSL *ssl, int mode); int SSL_get_shutdown(const SSL *ssl); int SSL_version(const SSL *ssl); int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath); # define SSL_get0_session SSL_get_session/* just peek at pointer */ SSL_SESSION *SSL_get_session(const SSL *ssl); SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx); void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)); void (*SSL_get_info_callback(const SSL *ssl)) (const SSL *ssl, int type, int val); int SSL_state(const SSL *ssl); void SSL_set_verify_result(SSL *ssl, long v); long SSL_get_verify_result(const SSL *ssl); int SSL_set_ex_data(SSL *ssl, int idx, void *data); void *SSL_get_ex_data(const SSL *ssl, int idx); int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); int SSL_SESSION_set_ex_data(SSL_SESSION *ss, int idx, void *data); void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss, int idx); int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); int SSL_CTX_set_ex_data(SSL_CTX *ssl, int idx, void *data); void *SSL_CTX_get_ex_data(const SSL_CTX *ssl, int idx); int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); int SSL_get_ex_data_X509_STORE_CTX_idx(void); # define SSL_CTX_sess_set_cache_size(ctx,t) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL) # define SSL_CTX_sess_get_cache_size(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL) # define SSL_CTX_set_session_cache_mode(ctx,m) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL) # define SSL_CTX_get_session_cache_mode(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL) # define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx) # define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m) # define SSL_CTX_get_read_ahead(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL) # define SSL_CTX_set_read_ahead(ctx,m) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL) # define SSL_CTX_get_max_cert_list(ctx) \ SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) # define SSL_CTX_set_max_cert_list(ctx,m) \ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) # define SSL_get_max_cert_list(ssl) \ SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) # define SSL_set_max_cert_list(ssl,m) \ SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) /* NB: the keylength is only applicable when is_export is true */ # ifndef OPENSSL_NO_RSA void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, RSA *(*cb) (SSL *ssl, int is_export, int keylength)); void SSL_set_tmp_rsa_callback(SSL *ssl, RSA *(*cb) (SSL *ssl, int is_export, int keylength)); # endif # ifndef OPENSSL_NO_DH void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx, DH *(*dh) (SSL *ssl, int is_export, int keylength)); void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*dh) (SSL *ssl, int is_export, int keylength)); # endif # ifndef OPENSSL_NO_ECDH void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx, EC_KEY *(*ecdh) (SSL *ssl, int is_export, int keylength)); void SSL_set_tmp_ecdh_callback(SSL *ssl, EC_KEY *(*ecdh) (SSL *ssl, int is_export, int keylength)); # endif # ifndef OPENSSL_NO_COMP const COMP_METHOD *SSL_get_current_compression(SSL *s); const COMP_METHOD *SSL_get_current_expansion(SSL *s); const char *SSL_COMP_get_name(const COMP_METHOD *comp); STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void); int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); # else const void *SSL_get_current_compression(SSL *s); const void *SSL_get_current_expansion(SSL *s); const char *SSL_COMP_get_name(const void *comp); void *SSL_COMP_get_compression_methods(void); int SSL_COMP_add_compression_method(int id, void *cm); # endif /* BEGIN ERROR CODES */ /* * The following lines are auto generated by the script mkerr.pl. Any changes * made after this point may be overwritten when the script is next run. */ void ERR_load_SSL_strings(void); /* Error codes for the SSL functions. */ /* Function codes. */ # define SSL_F_CLIENT_CERTIFICATE 100 # define SSL_F_CLIENT_FINISHED 167 # define SSL_F_CLIENT_HELLO 101 # define SSL_F_CLIENT_MASTER_KEY 102 # define SSL_F_D2I_SSL_SESSION 103 # define SSL_F_DO_DTLS1_WRITE 245 # define SSL_F_DO_SSL3_WRITE 104 # define SSL_F_DTLS1_ACCEPT 246 # define SSL_F_DTLS1_ADD_CERT_TO_BUF 280 # define SSL_F_DTLS1_BUFFER_RECORD 247 # define SSL_F_DTLS1_CHECK_TIMEOUT_NUM 293 # define SSL_F_DTLS1_CLIENT_HELLO 248 # define SSL_F_DTLS1_CONNECT 249 # define SSL_F_DTLS1_ENC 250 # define SSL_F_DTLS1_GET_HELLO_VERIFY 251 # define SSL_F_DTLS1_GET_MESSAGE 252 # define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253 # define SSL_F_DTLS1_GET_RECORD 254 # define SSL_F_DTLS1_HANDLE_TIMEOUT 282 # define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255 # define SSL_F_DTLS1_PREPROCESS_FRAGMENT 277 # define SSL_F_DTLS1_PROCESS_BUFFERED_RECORDS 424 # define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256 # define SSL_F_DTLS1_PROCESS_RECORD 257 # define SSL_F_DTLS1_READ_BYTES 258 # define SSL_F_DTLS1_READ_FAILED 259 # define SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST 260 # define SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE 261 # define SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE 262 # define SSL_F_DTLS1_SEND_CLIENT_VERIFY 263 # define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST 264 # define SSL_F_DTLS1_SEND_SERVER_CERTIFICATE 265 # define SSL_F_DTLS1_SEND_SERVER_HELLO 266 # define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE 267 # define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268 # define SSL_F_GET_CLIENT_FINISHED 105 # define SSL_F_GET_CLIENT_HELLO 106 # define SSL_F_GET_CLIENT_MASTER_KEY 107 # define SSL_F_GET_SERVER_FINISHED 108 # define SSL_F_GET_SERVER_HELLO 109 # define SSL_F_GET_SERVER_VERIFY 110 # define SSL_F_I2D_SSL_SESSION 111 # define SSL_F_READ_N 112 # define SSL_F_REQUEST_CERTIFICATE 113 # define SSL_F_SERVER_FINISH 239 # define SSL_F_SERVER_HELLO 114 # define SSL_F_SERVER_VERIFY 240 # define SSL_F_SSL23_ACCEPT 115 # define SSL_F_SSL23_CLIENT_HELLO 116 # define SSL_F_SSL23_CONNECT 117 # define SSL_F_SSL23_GET_CLIENT_HELLO 118 # define SSL_F_SSL23_GET_SERVER_HELLO 119 # define SSL_F_SSL23_PEEK 237 # define SSL_F_SSL23_READ 120 # define SSL_F_SSL23_WRITE 121 # define SSL_F_SSL2_ACCEPT 122 # define SSL_F_SSL2_CONNECT 123 # define SSL_F_SSL2_ENC_INIT 124 # define SSL_F_SSL2_GENERATE_KEY_MATERIAL 241 # define SSL_F_SSL2_PEEK 234 # define SSL_F_SSL2_READ 125 # define SSL_F_SSL2_READ_INTERNAL 236 # define SSL_F_SSL2_SET_CERTIFICATE 126 # define SSL_F_SSL2_WRITE 127 # define SSL_F_SSL3_ACCEPT 128 # define SSL_F_SSL3_ADD_CERT_TO_BUF 281 # define SSL_F_SSL3_CALLBACK_CTRL 233 # define SSL_F_SSL3_CHANGE_CIPHER_STATE 129 # define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130 # define SSL_F_SSL3_CHECK_CLIENT_HELLO 292 # define SSL_F_SSL3_CLIENT_HELLO 131 # define SSL_F_SSL3_CONNECT 132 # define SSL_F_SSL3_CTRL 213 # define SSL_F_SSL3_CTX_CTRL 133 # define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 279 # define SSL_F_SSL3_ENC 134 # define SSL_F_SSL3_GENERATE_KEY_BLOCK 238 # define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135 # define SSL_F_SSL3_GET_CERT_STATUS 288 # define SSL_F_SSL3_GET_CERT_VERIFY 136 # define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137 # define SSL_F_SSL3_GET_CLIENT_HELLO 138 # define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE 139 # define SSL_F_SSL3_GET_FINISHED 140 # define SSL_F_SSL3_GET_KEY_EXCHANGE 141 # define SSL_F_SSL3_GET_MESSAGE 142 # define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283 # define SSL_F_SSL3_GET_RECORD 143 # define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144 # define SSL_F_SSL3_GET_SERVER_DONE 145 # define SSL_F_SSL3_GET_SERVER_HELLO 146 # define SSL_F_SSL3_NEW_SESSION_TICKET 284 # define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147 # define SSL_F_SSL3_PEEK 235 # define SSL_F_SSL3_READ_BYTES 148 # define SSL_F_SSL3_READ_N 149 # define SSL_F_SSL3_SEND_CERTIFICATE_REQUEST 150 # define SSL_F_SSL3_SEND_CLIENT_CERTIFICATE 151 # define SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE 152 # define SSL_F_SSL3_SEND_CLIENT_VERIFY 153 # define SSL_F_SSL3_SEND_SERVER_CERTIFICATE 154 # define SSL_F_SSL3_SEND_SERVER_HELLO 242 # define SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE 155 # define SSL_F_SSL3_SETUP_BUFFERS 156 # define SSL_F_SSL3_SETUP_KEY_BLOCK 157 # define SSL_F_SSL3_WRITE_BYTES 158 # define SSL_F_SSL3_WRITE_PENDING 159 # define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 285 # define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 272 # define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215 # define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216 # define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 286 # define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 273 # define SSL_F_SSL_BAD_METHOD 160 # define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161 # define SSL_F_SSL_CERT_DUP 221 # define SSL_F_SSL_CERT_INST 222 # define SSL_F_SSL_CERT_INSTANTIATE 214 # define SSL_F_SSL_CERT_NEW 162 # define SSL_F_SSL_CHECK_PRIVATE_KEY 163 # define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 274 # define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230 # define SSL_F_SSL_CIPHER_STRENGTH_SORT 231 # define SSL_F_SSL_CLEAR 164 # define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD 165 # define SSL_F_SSL_CREATE_CIPHER_LIST 166 # define SSL_F_SSL_CTRL 232 # define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168 # define SSL_F_SSL_CTX_NEW 169 # define SSL_F_SSL_CTX_SET_CIPHER_LIST 269 # define SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE 278 # define SSL_F_SSL_CTX_SET_PURPOSE 226 # define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219 # define SSL_F_SSL_CTX_SET_SSL_VERSION 170 # define SSL_F_SSL_CTX_SET_TRUST 229 # define SSL_F_SSL_CTX_USE_CERTIFICATE 171 # define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172 # define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220 # define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173 # define SSL_F_SSL_CTX_USE_PRIVATEKEY 174 # define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175 # define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176 # define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177 # define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178 # define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179 # define SSL_F_SSL_DO_HANDSHAKE 180 # define SSL_F_SSL_GET_NEW_SESSION 181 # define SSL_F_SSL_GET_PREV_SESSION 217 # define SSL_F_SSL_GET_SERVER_SEND_CERT 182 # define SSL_F_SSL_GET_SERVER_SEND_PKEY 317 # define SSL_F_SSL_GET_SIGN_PKEY 183 # define SSL_F_SSL_INIT_WBIO_BUFFER 184 # define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 # define SSL_F_SSL_NEW 186 # define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 287 # define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 290 # define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 289 # define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 291 # define SSL_F_SSL_PEEK 270 # define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT 275 # define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT 276 # define SSL_F_SSL_READ 223 # define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187 # define SSL_F_SSL_RSA_PUBLIC_ENCRYPT 188 # define SSL_F_SSL_SESSION_DUP 348 # define SSL_F_SSL_SESSION_NEW 189 # define SSL_F_SSL_SESSION_PRINT_FP 190 # define SSL_F_SSL_SESS_CERT_NEW 225 # define SSL_F_SSL_SET_CERT 191 # define SSL_F_SSL_SET_CIPHER_LIST 271 # define SSL_F_SSL_SET_FD 192 # define SSL_F_SSL_SET_PKEY 193 # define SSL_F_SSL_SET_PURPOSE 227 # define SSL_F_SSL_SET_RFD 194 # define SSL_F_SSL_SET_SESSION 195 # define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218 # define SSL_F_SSL_SET_TRUST 228 # define SSL_F_SSL_SET_WFD 196 # define SSL_F_SSL_SHUTDOWN 224 # define SSL_F_SSL_UNDEFINED_CONST_FUNCTION 243 # define SSL_F_SSL_UNDEFINED_FUNCTION 197 # define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244 # define SSL_F_SSL_USE_CERTIFICATE 198 # define SSL_F_SSL_USE_CERTIFICATE_ASN1 199 # define SSL_F_SSL_USE_CERTIFICATE_FILE 200 # define SSL_F_SSL_USE_PRIVATEKEY 201 # define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202 # define SSL_F_SSL_USE_PRIVATEKEY_FILE 203 # define SSL_F_SSL_USE_RSAPRIVATEKEY 204 # define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205 # define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206 # define SSL_F_SSL_VERIFY_CERT_CHAIN 207 # define SSL_F_SSL_WRITE 208 # define SSL_F_TLS1_CHANGE_CIPHER_STATE 209 # define SSL_F_TLS1_ENC 210 # define SSL_F_TLS1_SETUP_KEY_BLOCK 211 # define SSL_F_WRITE_PENDING 212 /* Reason codes. */ # define SSL_R_APP_DATA_IN_HANDSHAKE 100 # define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272 # define SSL_R_BAD_ALERT_RECORD 101 # define SSL_R_BAD_AUTHENTICATION_TYPE 102 # define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 # define SSL_R_BAD_CHECKSUM 104 # define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 # define SSL_R_BAD_DECOMPRESSION 107 # define SSL_R_BAD_DH_G_LENGTH 108 # define SSL_R_BAD_DH_PUB_KEY_LENGTH 109 # define SSL_R_BAD_DH_P_LENGTH 110 # define SSL_R_BAD_DIGEST_LENGTH 111 # define SSL_R_BAD_DSA_SIGNATURE 112 # define SSL_R_BAD_ECC_CERT 304 # define SSL_R_BAD_ECDSA_SIGNATURE 305 # define SSL_R_BAD_ECPOINT 306 # define SSL_R_BAD_HELLO_REQUEST 105 # define SSL_R_BAD_LENGTH 271 # define SSL_R_BAD_MAC_DECODE 113 # define SSL_R_BAD_MESSAGE_TYPE 114 # define SSL_R_BAD_PACKET_LENGTH 115 # define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 116 # define SSL_R_BAD_RESPONSE_ARGUMENT 117 # define SSL_R_BAD_RSA_DECRYPT 118 # define SSL_R_BAD_RSA_ENCRYPT 119 # define SSL_R_BAD_RSA_E_LENGTH 120 # define SSL_R_BAD_RSA_MODULUS_LENGTH 121 # define SSL_R_BAD_RSA_SIGNATURE 122 # define SSL_R_BAD_SIGNATURE 123 # define SSL_R_BAD_SSL_FILETYPE 124 # define SSL_R_BAD_SSL_SESSION_ID_LENGTH 125 # define SSL_R_BAD_STATE 126 # define SSL_R_BAD_WRITE_RETRY 127 # define SSL_R_BIO_NOT_SET 128 # define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 129 # define SSL_R_BN_LIB 130 # define SSL_R_CA_DN_LENGTH_MISMATCH 131 # define SSL_R_CA_DN_TOO_LONG 132 # define SSL_R_CCS_RECEIVED_EARLY 133 # define SSL_R_CERTIFICATE_VERIFY_FAILED 134 # define SSL_R_CERT_LENGTH_MISMATCH 135 # define SSL_R_CHALLENGE_IS_DIFFERENT 136 # define SSL_R_CIPHER_CODE_WRONG_LENGTH 137 # define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 138 # define SSL_R_CIPHER_TABLE_SRC_ERROR 139 # define SSL_R_CLIENTHELLO_TLSEXT 157 # define SSL_R_COMPRESSED_LENGTH_TOO_LONG 140 # define SSL_R_COMPRESSION_FAILURE 141 # define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307 # define SSL_R_COMPRESSION_LIBRARY_ERROR 142 # define SSL_R_CONNECTION_ID_IS_DIFFERENT 143 # define SSL_R_CONNECTION_TYPE_NOT_SET 144 # define SSL_R_COOKIE_MISMATCH 308 # define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145 # define SSL_R_DATA_LENGTH_TOO_LONG 146 # define SSL_R_DECRYPTION_FAILED 147 # define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281 # define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148 # define SSL_R_DIGEST_CHECK_FAILED 149 # define SSL_R_DTLS_MESSAGE_TOO_BIG 318 # define SSL_R_DUPLICATE_COMPRESSION_ID 309 # define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310 # define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 # define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282 # define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151 # define SSL_R_EXCESSIVE_MESSAGE_SIZE 152 # define SSL_R_EXTRA_DATA_IN_MESSAGE 153 # define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154 # define SSL_R_HTTPS_PROXY_REQUEST 155 # define SSL_R_HTTP_REQUEST 156 # define SSL_R_ILLEGAL_PADDING 283 # define SSL_R_INAPPROPRIATE_FALLBACK 373 # define SSL_R_INVALID_CHALLENGE_LENGTH 158 # define SSL_R_INVALID_COMMAND 280 # define SSL_R_INVALID_PURPOSE 278 # define SSL_R_INVALID_STATUS_RESPONSE 316 # define SSL_R_INVALID_TICKET_KEYS_LENGTH 275 # define SSL_R_INVALID_TRUST 279 # define SSL_R_KEY_ARG_TOO_LONG 284 # define SSL_R_KRB5 285 # define SSL_R_KRB5_C_CC_PRINC 286 # define SSL_R_KRB5_C_GET_CRED 287 # define SSL_R_KRB5_C_INIT 288 # define SSL_R_KRB5_C_MK_REQ 289 # define SSL_R_KRB5_S_BAD_TICKET 290 # define SSL_R_KRB5_S_INIT 291 # define SSL_R_KRB5_S_RD_REQ 292 # define SSL_R_KRB5_S_TKT_EXPIRED 293 # define SSL_R_KRB5_S_TKT_NYV 294 # define SSL_R_KRB5_S_TKT_SKEW 295 # define SSL_R_LENGTH_MISMATCH 159 # define SSL_R_LENGTH_TOO_SHORT 160 # define SSL_R_LIBRARY_BUG 274 # define SSL_R_LIBRARY_HAS_NO_CIPHERS 161 # define SSL_R_MESSAGE_TOO_LONG 296 # define SSL_R_MISSING_DH_DSA_CERT 162 # define SSL_R_MISSING_DH_KEY 163 # define SSL_R_MISSING_DH_RSA_CERT 164 # define SSL_R_MISSING_DSA_SIGNING_CERT 165 # define SSL_R_MISSING_EXPORT_TMP_DH_KEY 166 # define SSL_R_MISSING_EXPORT_TMP_RSA_KEY 167 # define SSL_R_MISSING_RSA_CERTIFICATE 168 # define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169 # define SSL_R_MISSING_RSA_SIGNING_CERT 170 # define SSL_R_MISSING_TMP_DH_KEY 171 # define SSL_R_MISSING_TMP_ECDH_KEY 311 # define SSL_R_MISSING_TMP_RSA_KEY 172 # define SSL_R_MISSING_TMP_RSA_PKEY 173 # define SSL_R_MISSING_VERIFY_MESSAGE 174 # define SSL_R_MULTIPLE_SGC_RESTARTS 325 # define SSL_R_NON_SSLV2_INITIAL_PACKET 175 # define SSL_R_NO_CERTIFICATES_RETURNED 176 # define SSL_R_NO_CERTIFICATE_ASSIGNED 177 # define SSL_R_NO_CERTIFICATE_RETURNED 178 # define SSL_R_NO_CERTIFICATE_SET 179 # define SSL_R_NO_CERTIFICATE_SPECIFIED 180 # define SSL_R_NO_CIPHERS_AVAILABLE 181 # define SSL_R_NO_CIPHERS_PASSED 182 # define SSL_R_NO_CIPHERS_SPECIFIED 183 # define SSL_R_NO_CIPHER_LIST 184 # define SSL_R_NO_CIPHER_MATCH 185 # define SSL_R_NO_CLIENT_CERT_METHOD 317 # define SSL_R_NO_CLIENT_CERT_RECEIVED 186 # define SSL_R_NO_COMPRESSION_SPECIFIED 187 # define SSL_R_NO_METHOD_SPECIFIED 188 # define SSL_R_NO_PRIVATEKEY 189 # define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190 # define SSL_R_NO_PROTOCOLS_AVAILABLE 191 # define SSL_R_NO_PUBLICKEY 192 # define SSL_R_NO_RENEGOTIATION 319 # define SSL_R_NO_SHARED_CIPHER 193 # define SSL_R_NO_VERIFY_CALLBACK 194 # define SSL_R_NULL_SSL_CTX 195 # define SSL_R_NULL_SSL_METHOD_PASSED 196 # define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197 # define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297 # define SSL_R_PACKET_LENGTH_TOO_LONG 198 # define SSL_R_PARSE_TLSEXT 223 # define SSL_R_PATH_TOO_LONG 270 # define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199 # define SSL_R_PEER_ERROR 200 # define SSL_R_PEER_ERROR_CERTIFICATE 201 # define SSL_R_PEER_ERROR_NO_CERTIFICATE 202 # define SSL_R_PEER_ERROR_NO_CIPHER 203 # define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 204 # define SSL_R_PRE_MAC_LENGTH_TOO_LONG 205 # define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS 206 # define SSL_R_PROTOCOL_IS_SHUTDOWN 207 # define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR 208 # define SSL_R_PUBLIC_KEY_IS_NOT_RSA 209 # define SSL_R_PUBLIC_KEY_NOT_RSA 210 # define SSL_R_READ_BIO_NOT_SET 211 # define SSL_R_READ_TIMEOUT_EXPIRED 312 # define SSL_R_READ_WRONG_PACKET_TYPE 212 # define SSL_R_RECORD_LENGTH_MISMATCH 213 # define SSL_R_RECORD_TOO_LARGE 214 # define SSL_R_RECORD_TOO_SMALL 298 # define SSL_R_RENEGOTIATE_EXT_TOO_LONG 320 # define SSL_R_RENEGOTIATION_ENCODING_ERR 321 # define SSL_R_RENEGOTIATION_MISMATCH 322 # define SSL_R_REQUIRED_CIPHER_MISSING 215 # define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216 # define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217 # define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218 # define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 324 # define SSL_R_SERVERHELLO_TLSEXT 224 # define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277 # define SSL_R_SHORT_READ 219 # define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220 # define SSL_R_SSL23_DOING_SESSION_ID_REUSE 221 # define SSL_R_SSL2_CONNECTION_ID_TOO_LONG 299 # define SSL_R_SSL3_EXT_INVALID_SERVERNAME 225 # define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 226 # define SSL_R_SSL3_SESSION_ID_TOO_LONG 300 # define SSL_R_SSL3_SESSION_ID_TOO_SHORT 222 # define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042 # define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 # define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045 # define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044 # define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046 # define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030 # define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040 # define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047 # define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041 # define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 # define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043 # define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 228 # define SSL_R_SSL_HANDSHAKE_FAILURE 229 # define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 230 # define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301 # define SSL_R_SSL_SESSION_ID_CONFLICT 302 # define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273 # define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303 # define SSL_R_SSL_SESSION_ID_IS_DIFFERENT 231 # define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 # define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 # define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 # define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051 # define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060 # define SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK 1086 # define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 # define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 # define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 # define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 # define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 # define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 # define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 # define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 # define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 # define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 # define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 # define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 # define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232 # define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 227 +# define SSL_R_TOO_MANY_WARN_ALERTS 409 # define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233 # define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234 # define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235 # define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236 # define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 313 # define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 237 # define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 238 # define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314 # define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 # define SSL_R_UNABLE_TO_FIND_SSL_METHOD 240 # define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 241 # define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242 # define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243 # define SSL_R_UNEXPECTED_MESSAGE 244 # define SSL_R_UNEXPECTED_RECORD 245 # define SSL_R_UNINITIALIZED 276 # define SSL_R_UNKNOWN_ALERT_TYPE 246 # define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247 # define SSL_R_UNKNOWN_CIPHER_RETURNED 248 # define SSL_R_UNKNOWN_CIPHER_TYPE 249 # define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250 # define SSL_R_UNKNOWN_PKEY_TYPE 251 # define SSL_R_UNKNOWN_PROTOCOL 252 # define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253 # define SSL_R_UNKNOWN_SSL_VERSION 254 # define SSL_R_UNKNOWN_STATE 255 # define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 323 # define SSL_R_UNSUPPORTED_CIPHER 256 # define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 # define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315 # define SSL_R_UNSUPPORTED_PROTOCOL 258 # define SSL_R_UNSUPPORTED_SSL_VERSION 259 # define SSL_R_UNSUPPORTED_STATUS_TYPE 329 # define SSL_R_WRITE_BIO_NOT_SET 260 # define SSL_R_WRONG_CIPHER_RETURNED 261 # define SSL_R_WRONG_MESSAGE_TYPE 262 # define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263 # define SSL_R_WRONG_SIGNATURE_LENGTH 264 # define SSL_R_WRONG_SIGNATURE_SIZE 265 # define SSL_R_WRONG_SSL_VERSION 266 # define SSL_R_WRONG_VERSION_NUMBER 267 # define SSL_R_X509_LIB 268 # define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269 #ifdef __cplusplus } #endif #endif Index: releng/9.3/crypto/openssl/ssl/ssl3.h =================================================================== --- releng/9.3/crypto/openssl/ssl/ssl3.h (revision 308204) +++ releng/9.3/crypto/openssl/ssl/ssl3.h (revision 308205) @@ -1,615 +1,617 @@ /* ssl/ssl3.h */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ /* ==================================================================== * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * ECC cipher suite support in OpenSSL originally developed by * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ #ifndef HEADER_SSL3_H # define HEADER_SSL3_H # ifndef OPENSSL_NO_COMP # include # endif # include # include # include # include #ifdef __cplusplus extern "C" { #endif /* * Signalling cipher suite value from RFC 5746 * (TLS_EMPTY_RENEGOTIATION_INFO_SCSV) */ # define SSL3_CK_SCSV 0x030000FF /* * Signalling cipher suite value from draft-ietf-tls-downgrade-scsv-00 * (TLS_FALLBACK_SCSV) */ # define SSL3_CK_FALLBACK_SCSV 0x03005600 # define SSL3_CK_RSA_NULL_MD5 0x03000001 # define SSL3_CK_RSA_NULL_SHA 0x03000002 # define SSL3_CK_RSA_RC4_40_MD5 0x03000003 # define SSL3_CK_RSA_RC4_128_MD5 0x03000004 # define SSL3_CK_RSA_RC4_128_SHA 0x03000005 # define SSL3_CK_RSA_RC2_40_MD5 0x03000006 # define SSL3_CK_RSA_IDEA_128_SHA 0x03000007 # define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008 # define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009 # define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A # define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B # define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C # define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D # define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E # define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F # define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010 # define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011 # define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012 # define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013 # define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014 # define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015 # define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016 # define SSL3_CK_ADH_RC4_40_MD5 0x03000017 # define SSL3_CK_ADH_RC4_128_MD5 0x03000018 # define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019 # define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A # define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B # define SSL3_CK_FZA_DMS_NULL_SHA 0x0300001C # define SSL3_CK_FZA_DMS_FZA_SHA 0x0300001D # if 0 /* Because it clashes with KRB5, is never * used any more, and is safe to remove * according to David Hopwood * of the * ietf-tls list */ # define SSL3_CK_FZA_DMS_RC4_SHA 0x0300001E # endif /* * VRS Additional Kerberos5 entries */ # define SSL3_CK_KRB5_DES_64_CBC_SHA 0x0300001E # define SSL3_CK_KRB5_DES_192_CBC3_SHA 0x0300001F # define SSL3_CK_KRB5_RC4_128_SHA 0x03000020 # define SSL3_CK_KRB5_IDEA_128_CBC_SHA 0x03000021 # define SSL3_CK_KRB5_DES_64_CBC_MD5 0x03000022 # define SSL3_CK_KRB5_DES_192_CBC3_MD5 0x03000023 # define SSL3_CK_KRB5_RC4_128_MD5 0x03000024 # define SSL3_CK_KRB5_IDEA_128_CBC_MD5 0x03000025 # define SSL3_CK_KRB5_DES_40_CBC_SHA 0x03000026 # define SSL3_CK_KRB5_RC2_40_CBC_SHA 0x03000027 # define SSL3_CK_KRB5_RC4_40_SHA 0x03000028 # define SSL3_CK_KRB5_DES_40_CBC_MD5 0x03000029 # define SSL3_CK_KRB5_RC2_40_CBC_MD5 0x0300002A # define SSL3_CK_KRB5_RC4_40_MD5 0x0300002B # define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5" # define SSL3_TXT_RSA_NULL_SHA "NULL-SHA" # define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5" # define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5" # define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA" # define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5" # define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA" # define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA" # define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA" # define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA" # define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA" # define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA" # define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA" # define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA" # define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA" # define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA" # define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA" # define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA" # define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA" # define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA" # define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA" # define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA" # define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5" # define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5" # define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA" # define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA" # define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA" # define SSL3_TXT_FZA_DMS_NULL_SHA "FZA-NULL-SHA" # define SSL3_TXT_FZA_DMS_FZA_SHA "FZA-FZA-CBC-SHA" # define SSL3_TXT_FZA_DMS_RC4_SHA "FZA-RC4-SHA" # define SSL3_TXT_KRB5_DES_64_CBC_SHA "KRB5-DES-CBC-SHA" # define SSL3_TXT_KRB5_DES_192_CBC3_SHA "KRB5-DES-CBC3-SHA" # define SSL3_TXT_KRB5_RC4_128_SHA "KRB5-RC4-SHA" # define SSL3_TXT_KRB5_IDEA_128_CBC_SHA "KRB5-IDEA-CBC-SHA" # define SSL3_TXT_KRB5_DES_64_CBC_MD5 "KRB5-DES-CBC-MD5" # define SSL3_TXT_KRB5_DES_192_CBC3_MD5 "KRB5-DES-CBC3-MD5" # define SSL3_TXT_KRB5_RC4_128_MD5 "KRB5-RC4-MD5" # define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 "KRB5-IDEA-CBC-MD5" # define SSL3_TXT_KRB5_DES_40_CBC_SHA "EXP-KRB5-DES-CBC-SHA" # define SSL3_TXT_KRB5_RC2_40_CBC_SHA "EXP-KRB5-RC2-CBC-SHA" # define SSL3_TXT_KRB5_RC4_40_SHA "EXP-KRB5-RC4-SHA" # define SSL3_TXT_KRB5_DES_40_CBC_MD5 "EXP-KRB5-DES-CBC-MD5" # define SSL3_TXT_KRB5_RC2_40_CBC_MD5 "EXP-KRB5-RC2-CBC-MD5" # define SSL3_TXT_KRB5_RC4_40_MD5 "EXP-KRB5-RC4-MD5" # define SSL3_SSL_SESSION_ID_LENGTH 32 # define SSL3_MAX_SSL_SESSION_ID_LENGTH 32 # define SSL3_MASTER_SECRET_SIZE 48 # define SSL3_RANDOM_SIZE 32 # define SSL3_SESSION_ID_SIZE 32 # define SSL3_RT_HEADER_LENGTH 5 /* Due to MS stuffing up, this can change.... */ # if defined(OPENSSL_SYS_WIN16) || \ (defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)) # define SSL3_RT_MAX_EXTRA (14000) # else # define SSL3_RT_MAX_EXTRA (16384) # endif # define SSL3_RT_MAX_PLAIN_LENGTH 16384 # ifdef OPENSSL_NO_COMP # define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH # else # define SSL3_RT_MAX_COMPRESSED_LENGTH (1024+SSL3_RT_MAX_PLAIN_LENGTH) # endif # define SSL3_RT_MAX_ENCRYPTED_LENGTH (1024+SSL3_RT_MAX_COMPRESSED_LENGTH) # define SSL3_RT_MAX_PACKET_SIZE (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH) # define SSL3_RT_MAX_DATA_SIZE (1024*1024) # define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" # define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" # define SSL3_VERSION 0x0300 # define SSL3_VERSION_MAJOR 0x03 # define SSL3_VERSION_MINOR 0x00 # define SSL3_RT_CHANGE_CIPHER_SPEC 20 # define SSL3_RT_ALERT 21 # define SSL3_RT_HANDSHAKE 22 # define SSL3_RT_APPLICATION_DATA 23 # define SSL3_AL_WARNING 1 # define SSL3_AL_FATAL 2 # define SSL3_AD_CLOSE_NOTIFY 0 # define SSL3_AD_UNEXPECTED_MESSAGE 10/* fatal */ # define SSL3_AD_BAD_RECORD_MAC 20/* fatal */ # define SSL3_AD_DECOMPRESSION_FAILURE 30/* fatal */ # define SSL3_AD_HANDSHAKE_FAILURE 40/* fatal */ # define SSL3_AD_NO_CERTIFICATE 41 # define SSL3_AD_BAD_CERTIFICATE 42 # define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 # define SSL3_AD_CERTIFICATE_REVOKED 44 # define SSL3_AD_CERTIFICATE_EXPIRED 45 # define SSL3_AD_CERTIFICATE_UNKNOWN 46 # define SSL3_AD_ILLEGAL_PARAMETER 47/* fatal */ typedef struct ssl3_record_st { /* type of record */ /* * r */ int type; /* How many bytes available */ /* * rw */ unsigned int length; /* read/write offset into 'buf' */ /* * r */ unsigned int off; /* pointer to the record data */ /* * rw */ unsigned char *data; /* where the decode bytes are */ /* * rw */ unsigned char *input; /* only used with decompression - malloc()ed */ /* * r */ unsigned char *comp; /* epoch number, needed by DTLS1 */ /* * r */ unsigned long epoch; /* sequence number, needed by DTLS1 */ /* * r */ PQ_64BIT seq_num; } SSL3_RECORD; typedef struct ssl3_buffer_st { /* at least SSL3_RT_MAX_PACKET_SIZE bytes, see ssl3_setup_buffers() */ unsigned char *buf; /* buffer size */ size_t len; /* where to 'copy from' */ int offset; /* how many bytes left */ int left; } SSL3_BUFFER; # define SSL3_CT_RSA_SIGN 1 # define SSL3_CT_DSS_SIGN 2 # define SSL3_CT_RSA_FIXED_DH 3 # define SSL3_CT_DSS_FIXED_DH 4 # define SSL3_CT_RSA_EPHEMERAL_DH 5 # define SSL3_CT_DSS_EPHEMERAL_DH 6 # define SSL3_CT_FORTEZZA_DMS 20 /* * SSL3_CT_NUMBER is used to size arrays and it must be large enough to * contain all of the cert types defined either for SSLv3 and TLSv1. */ # define SSL3_CT_NUMBER 7 # define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001 # define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002 # define SSL3_FLAGS_POP_BUFFER 0x0004 # define TLS1_FLAGS_TLS_PADDING_BUG 0x0008 # define SSL3_FLAGS_CCS_OK 0x0080 /* * SSL3_FLAGS_SGC_RESTART_DONE is set when we restart a handshake because of * MS SGC and so prevents us from restarting the handshake in a loop. It's * reset on a renegotiation, so effectively limits the client to one restart * per negotiation. This limits the possibility of a DDoS attack where the * client handshakes in a loop using SGC to restart. Servers which permit * renegotiation can still be effected, but we can't prevent that. */ # define SSL3_FLAGS_SGC_RESTART_DONE 0x0040 typedef struct ssl3_state_st { long flags; int delay_buf_pop_ret; unsigned char read_sequence[8]; unsigned char read_mac_secret[EVP_MAX_MD_SIZE]; unsigned char write_sequence[8]; unsigned char write_mac_secret[EVP_MAX_MD_SIZE]; unsigned char server_random[SSL3_RANDOM_SIZE]; unsigned char client_random[SSL3_RANDOM_SIZE]; /* flags for countermeasure against known-IV weakness */ int need_empty_fragments; int empty_fragment_done; SSL3_BUFFER rbuf; /* read IO goes into here */ SSL3_BUFFER wbuf; /* write IO goes into here */ SSL3_RECORD rrec; /* each decoded record goes in here */ SSL3_RECORD wrec; /* goes out from here */ /* * storage for Alert/Handshake protocol data received but not yet * processed by ssl3_read_bytes: */ unsigned char alert_fragment[2]; unsigned int alert_fragment_len; unsigned char handshake_fragment[4]; unsigned int handshake_fragment_len; /* partial write - check the numbers match */ unsigned int wnum; /* number of bytes sent so far */ int wpend_tot; /* number bytes written */ int wpend_type; int wpend_ret; /* number of bytes submitted */ const unsigned char *wpend_buf; /* used during startup, digest all incoming/outgoing packets */ EVP_MD_CTX finish_dgst1; EVP_MD_CTX finish_dgst2; /* * this is set whenerver we see a change_cipher_spec message come in when * we are not looking for one */ int change_cipher_spec; int warn_alert; int fatal_alert; /* * we allow one fatal and one warning alert to be outstanding, send close * alert via the warning alert */ int alert_dispatch; unsigned char send_alert[2]; /* * This flag is set when we should renegotiate ASAP, basically when there * is no more data in the read or write buffers */ int renegotiate; int total_renegotiations; int num_renegotiations; int in_read_app_data; struct { /* actually only needs to be 16+20 */ unsigned char cert_verify_md[EVP_MAX_MD_SIZE * 2]; /* actually only need to be 16+20 for SSLv3 and 12 for TLS */ unsigned char finish_md[EVP_MAX_MD_SIZE * 2]; int finish_md_len; unsigned char peer_finish_md[EVP_MAX_MD_SIZE * 2]; int peer_finish_md_len; unsigned long message_size; int message_type; /* used to hold the new cipher we are going to use */ SSL_CIPHER *new_cipher; # ifndef OPENSSL_NO_DH DH *dh; # endif # ifndef OPENSSL_NO_ECDH EC_KEY *ecdh; /* holds short lived ECDH key */ # endif /* used when SSL_ST_FLUSH_DATA is entered */ int next_state; int reuse_message; /* used for certificate requests */ int cert_req; int ctype_num; char ctype[SSL3_CT_NUMBER]; STACK_OF(X509_NAME) *ca_names; int use_rsa_tmp; int key_block_length; unsigned char *key_block; const EVP_CIPHER *new_sym_enc; const EVP_MD *new_hash; # ifndef OPENSSL_NO_COMP const SSL_COMP *new_compression; # else char *new_compression; # endif int cert_request; } tmp; /* Connection binding to prevent renegotiation attacks */ unsigned char previous_client_finished[EVP_MAX_MD_SIZE]; unsigned char previous_client_finished_len; unsigned char previous_server_finished[EVP_MAX_MD_SIZE]; unsigned char previous_server_finished_len; int send_connection_binding; /* TODOEKR */ # ifndef OPENSSL_NO_TLSEXT # ifndef OPENSSL_NO_EC /* * This is set to true if we believe that this is a version of Safari * running on OS X 10.6 or newer. We wish to know this because Safari on * 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */ char is_probably_safari; # endif /* !OPENSSL_NO_EC */ # endif /* !OPENSSL_NO_TLSEXT */ + /* Count of the number of consecutive warning alerts received */ + unsigned int alert_count; } SSL3_STATE; /* SSLv3 */ /* * client */ /* extra state */ # define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT) /* write to server */ # define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT) # define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT) /* read from server */ # define SSL3_ST_CR_SRVR_HELLO_A (0x120|SSL_ST_CONNECT) # define SSL3_ST_CR_SRVR_HELLO_B (0x121|SSL_ST_CONNECT) # define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT) # define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT) # define SSL3_ST_CR_CERT_A (0x130|SSL_ST_CONNECT) # define SSL3_ST_CR_CERT_B (0x131|SSL_ST_CONNECT) # define SSL3_ST_CR_KEY_EXCH_A (0x140|SSL_ST_CONNECT) # define SSL3_ST_CR_KEY_EXCH_B (0x141|SSL_ST_CONNECT) # define SSL3_ST_CR_CERT_REQ_A (0x150|SSL_ST_CONNECT) # define SSL3_ST_CR_CERT_REQ_B (0x151|SSL_ST_CONNECT) # define SSL3_ST_CR_SRVR_DONE_A (0x160|SSL_ST_CONNECT) # define SSL3_ST_CR_SRVR_DONE_B (0x161|SSL_ST_CONNECT) /* write to server */ # define SSL3_ST_CW_CERT_A (0x170|SSL_ST_CONNECT) # define SSL3_ST_CW_CERT_B (0x171|SSL_ST_CONNECT) # define SSL3_ST_CW_CERT_C (0x172|SSL_ST_CONNECT) # define SSL3_ST_CW_CERT_D (0x173|SSL_ST_CONNECT) # define SSL3_ST_CW_KEY_EXCH_A (0x180|SSL_ST_CONNECT) # define SSL3_ST_CW_KEY_EXCH_B (0x181|SSL_ST_CONNECT) # define SSL3_ST_CW_CERT_VRFY_A (0x190|SSL_ST_CONNECT) # define SSL3_ST_CW_CERT_VRFY_B (0x191|SSL_ST_CONNECT) # define SSL3_ST_CW_CHANGE_A (0x1A0|SSL_ST_CONNECT) # define SSL3_ST_CW_CHANGE_B (0x1A1|SSL_ST_CONNECT) # define SSL3_ST_CW_FINISHED_A (0x1B0|SSL_ST_CONNECT) # define SSL3_ST_CW_FINISHED_B (0x1B1|SSL_ST_CONNECT) /* read from server */ # define SSL3_ST_CR_CHANGE_A (0x1C0|SSL_ST_CONNECT) # define SSL3_ST_CR_CHANGE_B (0x1C1|SSL_ST_CONNECT) # define SSL3_ST_CR_FINISHED_A (0x1D0|SSL_ST_CONNECT) # define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT) # define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT) # define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT) # define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT) # define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT) /* server */ /* extra state */ # define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT) /* read from client */ /* Do not change the number values, they do matter */ # define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT) # define SSL3_ST_SR_CLNT_HELLO_B (0x111|SSL_ST_ACCEPT) # define SSL3_ST_SR_CLNT_HELLO_C (0x112|SSL_ST_ACCEPT) /* write to client */ # define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT) # define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT) # define SSL3_ST_SW_HELLO_REQ_A (0x120|SSL_ST_ACCEPT) # define SSL3_ST_SW_HELLO_REQ_B (0x121|SSL_ST_ACCEPT) # define SSL3_ST_SW_HELLO_REQ_C (0x122|SSL_ST_ACCEPT) # define SSL3_ST_SW_SRVR_HELLO_A (0x130|SSL_ST_ACCEPT) # define SSL3_ST_SW_SRVR_HELLO_B (0x131|SSL_ST_ACCEPT) # define SSL3_ST_SW_CERT_A (0x140|SSL_ST_ACCEPT) # define SSL3_ST_SW_CERT_B (0x141|SSL_ST_ACCEPT) # define SSL3_ST_SW_KEY_EXCH_A (0x150|SSL_ST_ACCEPT) # define SSL3_ST_SW_KEY_EXCH_B (0x151|SSL_ST_ACCEPT) # define SSL3_ST_SW_CERT_REQ_A (0x160|SSL_ST_ACCEPT) # define SSL3_ST_SW_CERT_REQ_B (0x161|SSL_ST_ACCEPT) # define SSL3_ST_SW_SRVR_DONE_A (0x170|SSL_ST_ACCEPT) # define SSL3_ST_SW_SRVR_DONE_B (0x171|SSL_ST_ACCEPT) /* read from client */ # define SSL3_ST_SR_CERT_A (0x180|SSL_ST_ACCEPT) # define SSL3_ST_SR_CERT_B (0x181|SSL_ST_ACCEPT) # define SSL3_ST_SR_KEY_EXCH_A (0x190|SSL_ST_ACCEPT) # define SSL3_ST_SR_KEY_EXCH_B (0x191|SSL_ST_ACCEPT) # define SSL3_ST_SR_CERT_VRFY_A (0x1A0|SSL_ST_ACCEPT) # define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT) # define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT) # define SSL3_ST_SR_CHANGE_B (0x1B1|SSL_ST_ACCEPT) # define SSL3_ST_SR_FINISHED_A (0x1C0|SSL_ST_ACCEPT) # define SSL3_ST_SR_FINISHED_B (0x1C1|SSL_ST_ACCEPT) /* write to client */ # define SSL3_ST_SW_CHANGE_A (0x1D0|SSL_ST_ACCEPT) # define SSL3_ST_SW_CHANGE_B (0x1D1|SSL_ST_ACCEPT) # define SSL3_ST_SW_FINISHED_A (0x1E0|SSL_ST_ACCEPT) # define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT) # define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT) # define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT) # define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT) # define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT) # define SSL3_MT_HELLO_REQUEST 0 # define SSL3_MT_CLIENT_HELLO 1 # define SSL3_MT_SERVER_HELLO 2 # define SSL3_MT_NEWSESSION_TICKET 4 # define SSL3_MT_CERTIFICATE 11 # define SSL3_MT_SERVER_KEY_EXCHANGE 12 # define SSL3_MT_CERTIFICATE_REQUEST 13 # define SSL3_MT_SERVER_DONE 14 # define SSL3_MT_CERTIFICATE_VERIFY 15 # define SSL3_MT_CLIENT_KEY_EXCHANGE 16 # define SSL3_MT_FINISHED 20 # define SSL3_MT_CERTIFICATE_STATUS 22 # define DTLS1_MT_HELLO_VERIFY_REQUEST 3 # define SSL3_MT_CCS 1 /* These are used when changing over to a new cipher */ # define SSL3_CC_READ 0x01 # define SSL3_CC_WRITE 0x02 # define SSL3_CC_CLIENT 0x10 # define SSL3_CC_SERVER 0x20 # define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE) # define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ) # define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ) # define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER|SSL3_CC_WRITE) #ifdef __cplusplus } #endif #endif Index: releng/9.3/crypto/openssl/ssl/ssl_locl.h =================================================================== --- releng/9.3/crypto/openssl/ssl/ssl_locl.h (revision 308204) +++ releng/9.3/crypto/openssl/ssl/ssl_locl.h (revision 308205) @@ -1,1080 +1,1082 @@ /* ssl/ssl_locl.h */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ /* ==================================================================== * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ /* ==================================================================== * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. * ECC cipher suite support in OpenSSL originally developed by * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. */ #ifndef HEADER_SSL_LOCL_H # define HEADER_SSL_LOCL_H # include # include # include # include # include "e_os.h" # include # ifndef OPENSSL_NO_COMP # include # endif # include # include # ifndef OPENSSL_NO_RSA # include # endif # ifndef OPENSSL_NO_DSA # include # endif # include # include # include # ifdef OPENSSL_BUILD_SHLIBSSL # undef OPENSSL_EXTERN # define OPENSSL_EXTERN OPENSSL_EXPORT # endif # define PKCS1_CHECK # define c2l(c,l) (l = ((unsigned long)(*((c)++))) , \ l|=(((unsigned long)(*((c)++)))<< 8), \ l|=(((unsigned long)(*((c)++)))<<16), \ l|=(((unsigned long)(*((c)++)))<<24)) /* NOTE - c is not incremented as per c2l */ # define c2ln(c,l1,l2,n) { \ c+=n; \ l1=l2=0; \ switch (n) { \ case 8: l2 =((unsigned long)(*(--(c))))<<24; \ case 7: l2|=((unsigned long)(*(--(c))))<<16; \ case 6: l2|=((unsigned long)(*(--(c))))<< 8; \ case 5: l2|=((unsigned long)(*(--(c)))); \ case 4: l1 =((unsigned long)(*(--(c))))<<24; \ case 3: l1|=((unsigned long)(*(--(c))))<<16; \ case 2: l1|=((unsigned long)(*(--(c))))<< 8; \ case 1: l1|=((unsigned long)(*(--(c)))); \ } \ } # define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>>24)&0xff)) # define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24, \ l|=((unsigned long)(*((c)++)))<<16, \ l|=((unsigned long)(*((c)++)))<< 8, \ l|=((unsigned long)(*((c)++)))) # define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff)) # define l2n6(l,c) (*((c)++)=(unsigned char)(((l)>>40)&0xff), \ *((c)++)=(unsigned char)(((l)>>32)&0xff), \ *((c)++)=(unsigned char)(((l)>>24)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff)) # define l2n8(l,c) (*((c)++)=(unsigned char)(((l)>>56)&0xff), \ *((c)++)=(unsigned char)(((l)>>48)&0xff), \ *((c)++)=(unsigned char)(((l)>>40)&0xff), \ *((c)++)=(unsigned char)(((l)>>32)&0xff), \ *((c)++)=(unsigned char)(((l)>>24)&0xff), \ *((c)++)=(unsigned char)(((l)>>16)&0xff), \ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff)) # define n2l6(c,l) (l =((BN_ULLONG)(*((c)++)))<<40, \ l|=((BN_ULLONG)(*((c)++)))<<32, \ l|=((BN_ULLONG)(*((c)++)))<<24, \ l|=((BN_ULLONG)(*((c)++)))<<16, \ l|=((BN_ULLONG)(*((c)++)))<< 8, \ l|=((BN_ULLONG)(*((c)++)))) /* NOTE - c is not incremented as per l2c */ # define l2cn(l1,l2,c,n) { \ c+=n; \ switch (n) { \ case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ } \ } # define n2s(c,s) ((s=(((unsigned int)(c[0]))<< 8)| \ (((unsigned int)(c[1])) )),c+=2) # define s2n(s,c) ((c[0]=(unsigned char)(((s)>> 8)&0xff), \ c[1]=(unsigned char)(((s) )&0xff)),c+=2) # define n2l3(c,l) ((l =(((unsigned long)(c[0]))<<16)| \ (((unsigned long)(c[1]))<< 8)| \ (((unsigned long)(c[2])) )),c+=3) # define l2n3(l,c) ((c[0]=(unsigned char)(((l)>>16)&0xff), \ c[1]=(unsigned char)(((l)>> 8)&0xff), \ c[2]=(unsigned char)(((l) )&0xff)),c+=3) /* LOCAL STUFF */ # define SSL_DECRYPT 0 # define SSL_ENCRYPT 1 # define TWO_BYTE_BIT 0x80 # define SEC_ESC_BIT 0x40 # define TWO_BYTE_MASK 0x7fff # define THREE_BYTE_MASK 0x3fff # define INC32(a) ((a)=((a)+1)&0xffffffffL) # define DEC32(a) ((a)=((a)-1)&0xffffffffL) # define MAX_MAC_SIZE 20 /* up from 16 for SSLv3 */ +# define MAX_WARN_ALERT_COUNT 5 + /* * Define the Bitmasks for SSL_CIPHER.algorithms. * This bits are used packed as dense as possible. If new methods/ciphers * etc will be added, the bits a likely to change, so this information * is for internal library use only, even though SSL_CIPHER.algorithms * can be publicly accessed. * Use the according functions for cipher management instead. * * The bit mask handling in the selection and sorting scheme in * ssl_create_cipher_list() has only limited capabilities, reflecting * that the different entities within are mutually exclusive: * ONLY ONE BIT PER MASK CAN BE SET AT A TIME. */ # define SSL_MKEY_MASK 0x000000FFL /* RSA key exchange */ # define SSL_kRSA 0x00000001L /* DH cert RSA CA cert */ # define SSL_kDHr 0x00000002L /* DH cert DSA CA cert */ # define SSL_kDHd 0x00000004L # define SSL_kFZA 0x00000008L /* tmp DH key no DH cert */ # define SSL_kEDH 0x00000010L /* Kerberos5 key exchange */ # define SSL_kKRB5 0x00000020L /* ECDH w/ long-term keys */ # define SSL_kECDH 0x00000040L /* ephemeral ECDH */ # define SSL_kECDHE 0x00000080L # define SSL_EDH (SSL_kEDH|(SSL_AUTH_MASK^SSL_aNULL)) # define SSL_AUTH_MASK 0x00007F00L /* Authenticate with RSA */ # define SSL_aRSA 0x00000100L /* Authenticate with DSS */ # define SSL_aDSS 0x00000200L # define SSL_DSS SSL_aDSS # define SSL_aFZA 0x00000400L /* no Authenticate, ADH */ # define SSL_aNULL 0x00000800L /* no Authenticate, ADH */ # define SSL_aDH 0x00001000L /* Authenticate with KRB5 */ # define SSL_aKRB5 0x00002000L /* Authenticate with ECDSA */ # define SSL_aECDSA 0x00004000L # define SSL_NULL (SSL_eNULL) # define SSL_ADH (SSL_kEDH|SSL_aNULL) # define SSL_RSA (SSL_kRSA|SSL_aRSA) # define SSL_DH (SSL_kDHr|SSL_kDHd|SSL_kEDH) # define SSL_ECDH (SSL_kECDH|SSL_kECDHE) # define SSL_FZA (SSL_aFZA|SSL_kFZA|SSL_eFZA) # define SSL_KRB5 (SSL_kKRB5|SSL_aKRB5) # define SSL_ENC_MASK 0x1C3F8000L # define SSL_DES 0x00008000L # define SSL_3DES 0x00010000L # define SSL_RC4 0x00020000L # define SSL_RC2 0x00040000L # define SSL_IDEA 0x00080000L # define SSL_eFZA 0x00100000L # define SSL_eNULL 0x00200000L # define SSL_AES 0x04000000L # define SSL_CAMELLIA 0x08000000L # define SSL_SEED 0x10000000L # define SSL_MAC_MASK 0x00c00000L # define SSL_MD5 0x00400000L # define SSL_SHA1 0x00800000L # define SSL_SHA (SSL_SHA1) # define SSL_SSL_MASK 0x03000000L # define SSL_SSLV2 0x01000000L # define SSL_SSLV3 0x02000000L # define SSL_TLSV1 SSL_SSLV3/* for now */ /* we have used 1fffffff - 3 bits left to go. */ /* * Export and cipher strength information. For each cipher we have to decide * whether it is exportable or not. This information is likely to change * over time, since the export control rules are no static technical issue. * * Independent of the export flag the cipher strength is sorted into classes. * SSL_EXP40 was denoting the 40bit US export limit of past times, which now * is at 56bit (SSL_EXP56). If the exportable cipher class is going to change * again (eg. to 64bit) the use of "SSL_EXP*" becomes blurred even more, * since SSL_EXP64 could be similar to SSL_LOW. * For this reason SSL_MICRO and SSL_MINI macros are included to widen the * namespace of SSL_LOW-SSL_HIGH to lower values. As development of speed * and ciphers goes, another extension to SSL_SUPER and/or SSL_ULTRA would * be possible. */ # define SSL_EXP_MASK 0x00000003L # define SSL_NOT_EXP 0x00000001L # define SSL_EXPORT 0x00000002L # define SSL_STRONG_MASK 0x000000fcL # define SSL_STRONG_NONE 0x00000004L # define SSL_EXP40 0x00000008L # define SSL_MICRO (SSL_EXP40) # define SSL_EXP56 0x00000010L # define SSL_MINI (SSL_EXP56) # define SSL_LOW 0x00000020L # define SSL_MEDIUM 0x00000040L # define SSL_HIGH 0x00000080L # define SSL_FIPS 0x00000100L /* we have used 000001ff - 23 bits left to go */ /*- * Macros to check the export status and cipher strength for export ciphers. * Even though the macros for EXPORT and EXPORT40/56 have similar names, * their meaning is different: * *_EXPORT macros check the 'exportable' status. * *_EXPORT40/56 macros are used to check whether a certain cipher strength * is given. * Since the SSL_IS_EXPORT* and SSL_EXPORT* macros depend on the correct * algorithm structure element to be passed (algorithms, algo_strength) and no * typechecking can be done as they are all of type unsigned long, their * direct usage is discouraged. * Use the SSL_C_* macros instead. */ # define SSL_IS_EXPORT(a) ((a)&SSL_EXPORT) # define SSL_IS_EXPORT56(a) ((a)&SSL_EXP56) # define SSL_IS_EXPORT40(a) ((a)&SSL_EXP40) # define SSL_C_IS_EXPORT(c) SSL_IS_EXPORT((c)->algo_strength) # define SSL_C_IS_EXPORT56(c) SSL_IS_EXPORT56((c)->algo_strength) # define SSL_C_IS_EXPORT40(c) SSL_IS_EXPORT40((c)->algo_strength) # define SSL_EXPORT_KEYLENGTH(a,s) (SSL_IS_EXPORT40(s) ? 5 : \ ((a)&SSL_ENC_MASK) == SSL_DES ? 8 : 7) # define SSL_EXPORT_PKEYLENGTH(a) (SSL_IS_EXPORT40(a) ? 512 : 1024) # define SSL_C_EXPORT_KEYLENGTH(c) SSL_EXPORT_KEYLENGTH((c)->algorithms, \ (c)->algo_strength) # define SSL_C_EXPORT_PKEYLENGTH(c) SSL_EXPORT_PKEYLENGTH((c)->algo_strength) # define SSL_ALL 0xffffffffL # define SSL_ALL_CIPHERS (SSL_MKEY_MASK|SSL_AUTH_MASK|SSL_ENC_MASK|\ SSL_MAC_MASK) # define SSL_ALL_STRENGTHS (SSL_EXP_MASK|SSL_STRONG_MASK) /* Mostly for SSLv3 */ # define SSL_PKEY_RSA_ENC 0 # define SSL_PKEY_RSA_SIGN 1 # define SSL_PKEY_DSA_SIGN 2 # define SSL_PKEY_DH_RSA 3 # define SSL_PKEY_DH_DSA 4 # define SSL_PKEY_ECC 5 # define SSL_PKEY_NUM 6 /*- * SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) | * <- (EXPORT & (RSA_ENC | RSA_TMP) & RSA_SIGN) * SSL_kDH <- DH_ENC & (RSA_ENC | RSA_SIGN | DSA_SIGN) * SSL_kEDH <- RSA_ENC | RSA_SIGN | DSA_SIGN * SSL_aRSA <- RSA_ENC | RSA_SIGN * SSL_aDSS <- DSA_SIGN */ /*- #define CERT_INVALID 0 #define CERT_PUBLIC_KEY 1 #define CERT_PRIVATE_KEY 2 */ # ifndef OPENSSL_NO_EC /* * From ECC-TLS draft, used in encoding the curve type in ECParameters */ # define EXPLICIT_PRIME_CURVE_TYPE 1 # define EXPLICIT_CHAR2_CURVE_TYPE 2 # define NAMED_CURVE_TYPE 3 # endif /* OPENSSL_NO_EC */ typedef struct cert_pkey_st { X509 *x509; EVP_PKEY *privatekey; } CERT_PKEY; typedef struct cert_st { /* Current active set */ /* * ALWAYS points to an element of the pkeys array * Probably it would make more sense to store * an index, not a pointer. */ CERT_PKEY *key; /* * The following masks are for the key and auth algorithms that are * supported by the certs below */ int valid; unsigned long mask; unsigned long export_mask; # ifndef OPENSSL_NO_RSA RSA *rsa_tmp; RSA *(*rsa_tmp_cb) (SSL *ssl, int is_export, int keysize); # endif # ifndef OPENSSL_NO_DH DH *dh_tmp; DH *(*dh_tmp_cb) (SSL *ssl, int is_export, int keysize); # endif # ifndef OPENSSL_NO_ECDH EC_KEY *ecdh_tmp; /* Callback for generating ephemeral ECDH keys */ EC_KEY *(*ecdh_tmp_cb) (SSL *ssl, int is_export, int keysize); # endif CERT_PKEY pkeys[SSL_PKEY_NUM]; int references; /* >1 only if SSL_copy_session_id is used */ } CERT; typedef struct sess_cert_st { STACK_OF(X509) *cert_chain; /* as received from peer (not for SSL2) */ /* The 'peer_...' members are used only by clients. */ int peer_cert_type; CERT_PKEY *peer_key; /* points to an element of peer_pkeys (never * NULL!) */ CERT_PKEY peer_pkeys[SSL_PKEY_NUM]; /* * Obviously we don't have the private keys of these, so maybe we * shouldn't even use the CERT_PKEY type here. */ # ifndef OPENSSL_NO_RSA RSA *peer_rsa_tmp; /* not used for SSL 2 */ # endif # ifndef OPENSSL_NO_DH DH *peer_dh_tmp; /* not used for SSL 2 */ # endif # ifndef OPENSSL_NO_ECDH EC_KEY *peer_ecdh_tmp; # endif int references; /* actually always 1 at the moment */ } SESS_CERT; /* * #define MAC_DEBUG */ /* * #define ERR_DEBUG */ /* * #define ABORT_DEBUG */ /* * #define PKT_DEBUG 1 */ /* * #define DES_DEBUG */ /* * #define DES_OFB_DEBUG */ /* * #define SSL_DEBUG */ /* * #define RSA_DEBUG */ /* * #define IDEA_DEBUG */ # define FP_ICC (int (*)(const void *,const void *)) # define ssl_put_cipher_by_char(ssl,ciph,ptr) \ ((ssl)->method->put_cipher_by_char((ciph),(ptr))) # define ssl_get_cipher_by_char(ssl,ptr) \ ((ssl)->method->get_cipher_by_char(ptr)) /* * This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit * of a mess of functions, but hell, think of it as an opaque structure :-) */ typedef struct ssl3_enc_method { int (*enc) (SSL *, int); int (*mac) (SSL *, unsigned char *, int); int (*setup_key_block) (SSL *); int (*generate_master_secret) (SSL *, unsigned char *, unsigned char *, int); int (*change_cipher_state) (SSL *, int); int (*final_finish_mac) (SSL *, EVP_MD_CTX *, EVP_MD_CTX *, const char *, int, unsigned char *); int finish_mac_length; int (*cert_verify_mac) (SSL *, EVP_MD_CTX *, unsigned char *); const char *client_finished_label; int client_finished_label_len; const char *server_finished_label; int server_finished_label_len; int (*alert_value) (int); } SSL3_ENC_METHOD; # ifndef OPENSSL_NO_COMP /* Used for holding the relevant compression methods loaded into SSL_CTX */ typedef struct ssl3_comp_st { int comp_id; /* The identifier byte for this compression * type */ char *name; /* Text name used for the compression type */ COMP_METHOD *method; /* The method :-) */ } SSL3_COMP; # endif extern SSL3_ENC_METHOD ssl3_undef_enc_method; OPENSSL_EXTERN SSL_CIPHER ssl2_ciphers[]; OPENSSL_EXTERN SSL_CIPHER ssl3_ciphers[]; SSL_METHOD *ssl_bad_method(int ver); SSL_METHOD *sslv2_base_method(void); SSL_METHOD *sslv23_base_method(void); SSL_METHOD *sslv3_base_method(void); extern SSL3_ENC_METHOD TLSv1_enc_data; extern SSL3_ENC_METHOD SSLv3_enc_data; extern SSL3_ENC_METHOD DTLSv1_enc_data; # define IMPLEMENT_tls1_meth_func(func_name, s_accept, s_connect, s_get_meth) \ SSL_METHOD *func_name(void) \ { \ static SSL_METHOD func_name##_data= { \ TLS1_VERSION, \ tls1_new, \ tls1_clear, \ tls1_free, \ s_accept, \ s_connect, \ ssl3_read, \ ssl3_peek, \ ssl3_write, \ ssl3_shutdown, \ ssl3_renegotiate, \ ssl3_renegotiate_check, \ ssl3_get_message, \ ssl3_read_bytes, \ ssl3_write_bytes, \ ssl3_dispatch_alert, \ ssl3_ctrl, \ ssl3_ctx_ctrl, \ ssl3_get_cipher_by_char, \ ssl3_put_cipher_by_char, \ ssl3_pending, \ ssl3_num_ciphers, \ ssl3_get_cipher, \ s_get_meth, \ tls1_default_timeout, \ &TLSv1_enc_data, \ ssl_undefined_void_function, \ ssl3_callback_ctrl, \ ssl3_ctx_callback_ctrl, \ }; \ return &func_name##_data; \ } # define IMPLEMENT_ssl3_meth_func(func_name, s_accept, s_connect, s_get_meth) \ SSL_METHOD *func_name(void) \ { \ static SSL_METHOD func_name##_data= { \ SSL3_VERSION, \ ssl3_new, \ ssl3_clear, \ ssl3_free, \ s_accept, \ s_connect, \ ssl3_read, \ ssl3_peek, \ ssl3_write, \ ssl3_shutdown, \ ssl3_renegotiate, \ ssl3_renegotiate_check, \ ssl3_get_message, \ ssl3_read_bytes, \ ssl3_write_bytes, \ ssl3_dispatch_alert, \ ssl3_ctrl, \ ssl3_ctx_ctrl, \ ssl3_get_cipher_by_char, \ ssl3_put_cipher_by_char, \ ssl3_pending, \ ssl3_num_ciphers, \ ssl3_get_cipher, \ s_get_meth, \ ssl3_default_timeout, \ &SSLv3_enc_data, \ ssl_undefined_void_function, \ ssl3_callback_ctrl, \ ssl3_ctx_callback_ctrl, \ }; \ return &func_name##_data; \ } # define IMPLEMENT_ssl23_meth_func(func_name, s_accept, s_connect, s_get_meth) \ SSL_METHOD *func_name(void) \ { \ static SSL_METHOD func_name##_data= { \ TLS1_VERSION, \ tls1_new, \ tls1_clear, \ tls1_free, \ s_accept, \ s_connect, \ ssl23_read, \ ssl23_peek, \ ssl23_write, \ ssl_undefined_function, \ ssl_undefined_function, \ ssl_ok, \ ssl3_get_message, \ ssl3_read_bytes, \ ssl3_write_bytes, \ ssl3_dispatch_alert, \ ssl3_ctrl, \ ssl3_ctx_ctrl, \ ssl23_get_cipher_by_char, \ ssl23_put_cipher_by_char, \ ssl_undefined_const_function, \ ssl23_num_ciphers, \ ssl23_get_cipher, \ s_get_meth, \ ssl23_default_timeout, \ &ssl3_undef_enc_method, \ ssl_undefined_void_function, \ ssl3_callback_ctrl, \ ssl3_ctx_callback_ctrl, \ }; \ return &func_name##_data; \ } # define IMPLEMENT_ssl2_meth_func(func_name, s_accept, s_connect, s_get_meth) \ SSL_METHOD *func_name(void) \ { \ static SSL_METHOD func_name##_data= { \ SSL2_VERSION, \ ssl2_new, /* local */ \ ssl2_clear, /* local */ \ ssl2_free, /* local */ \ s_accept, \ s_connect, \ ssl2_read, \ ssl2_peek, \ ssl2_write, \ ssl2_shutdown, \ ssl_ok, /* NULL - renegotiate */ \ ssl_ok, /* NULL - check renegotiate */ \ NULL, /* NULL - ssl_get_message */ \ NULL, /* NULL - ssl_get_record */ \ NULL, /* NULL - ssl_write_bytes */ \ NULL, /* NULL - dispatch_alert */ \ ssl2_ctrl, /* local */ \ ssl2_ctx_ctrl, /* local */ \ ssl2_get_cipher_by_char, \ ssl2_put_cipher_by_char, \ ssl2_pending, \ ssl2_num_ciphers, \ ssl2_get_cipher, \ s_get_meth, \ ssl2_default_timeout, \ &ssl3_undef_enc_method, \ ssl_undefined_void_function, \ ssl2_callback_ctrl, /* local */ \ ssl2_ctx_callback_ctrl, /* local */ \ }; \ return &func_name##_data; \ } # define IMPLEMENT_dtls1_meth_func(func_name, s_accept, s_connect, s_get_meth) \ SSL_METHOD *func_name(void) \ { \ static SSL_METHOD func_name##_data= { \ DTLS1_VERSION, \ dtls1_new, \ dtls1_clear, \ dtls1_free, \ s_accept, \ s_connect, \ ssl3_read, \ ssl3_peek, \ ssl3_write, \ ssl3_shutdown, \ ssl3_renegotiate, \ ssl3_renegotiate_check, \ dtls1_get_message, \ dtls1_read_bytes, \ dtls1_write_app_data_bytes, \ dtls1_dispatch_alert, \ dtls1_ctrl, \ ssl3_ctx_ctrl, \ ssl3_get_cipher_by_char, \ ssl3_put_cipher_by_char, \ ssl3_pending, \ ssl3_num_ciphers, \ dtls1_get_cipher, \ s_get_meth, \ dtls1_default_timeout, \ &DTLSv1_enc_data, \ ssl_undefined_void_function, \ ssl3_callback_ctrl, \ ssl3_ctx_callback_ctrl, \ }; \ return &func_name##_data; \ } void ssl_clear_cipher_ctx(SSL *s); int ssl_clear_bad_session(SSL *s); CERT *ssl_cert_new(void); CERT *ssl_cert_dup(CERT *cert); int ssl_cert_inst(CERT **o); void ssl_cert_free(CERT *c); SESS_CERT *ssl_sess_cert_new(void); void ssl_sess_cert_free(SESS_CERT *sc); int ssl_set_peer_cert_type(SESS_CERT *c, int type); int ssl_get_new_session(SSL *s, int session); int ssl_get_prev_session(SSL *s, unsigned char *session, int len, const unsigned char *limit); SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket); int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b); int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap, const SSL_CIPHER *const *bp); STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, unsigned char *p, int num, STACK_OF(SSL_CIPHER) **skp); int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, unsigned char *p, int (*put_cb) (const SSL_CIPHER *, unsigned char *)); STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth, STACK_OF(SSL_CIPHER) **pref, STACK_OF(SSL_CIPHER) **sorted, const char *rule_str); void ssl_update_cache(SSL *s, int mode); int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, const EVP_MD **md, SSL_COMP **comp); int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk); int ssl_undefined_function(SSL *s); int ssl_undefined_void_function(void); int ssl_undefined_const_function(const SSL *s); CERT_PKEY *ssl_get_server_send_pkey(const SSL *s); X509 *ssl_get_server_send_cert(const SSL *); EVP_PKEY *ssl_get_sign_pkey(SSL *, SSL_CIPHER *); int ssl_cert_type(X509 *x, EVP_PKEY *pkey); void ssl_set_cert_masks(CERT *c, SSL_CIPHER *cipher); STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s); int ssl_verify_alarm_type(long type); void ssl_load_ciphers(void); int ssl2_enc_init(SSL *s, int client); int ssl2_generate_key_material(SSL *s); void ssl2_enc(SSL *s, int send_data); void ssl2_mac(SSL *s, unsigned char *mac, int send_data); SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p); int ssl2_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); int ssl2_part_read(SSL *s, unsigned long f, int i); int ssl2_do_write(SSL *s); int ssl2_set_certificate(SSL *s, int type, int len, const unsigned char *data); void ssl2_return_error(SSL *s, int reason); void ssl2_write_error(SSL *s); int ssl2_num_ciphers(void); SSL_CIPHER *ssl2_get_cipher(unsigned int u); int ssl2_new(SSL *s); void ssl2_free(SSL *s); int ssl2_accept(SSL *s); int ssl2_connect(SSL *s); int ssl2_read(SSL *s, void *buf, int len); int ssl2_peek(SSL *s, void *buf, int len); int ssl2_write(SSL *s, const void *buf, int len); int ssl2_shutdown(SSL *s); void ssl2_clear(SSL *s); long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg); long ssl2_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg); long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp) (void)); long ssl2_ctx_callback_ctrl(SSL_CTX *s, int cmd, void (*fp) (void)); int ssl2_pending(const SSL *s); long ssl2_default_timeout(void); SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p); int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); void ssl3_init_finished_mac(SSL *s); int ssl3_send_server_certificate(SSL *s); int ssl3_send_newsession_ticket(SSL *s); int ssl3_send_cert_status(SSL *s); int ssl3_get_finished(SSL *s, int state_a, int state_b); int ssl3_setup_key_block(SSL *s); int ssl3_send_change_cipher_spec(SSL *s, int state_a, int state_b); int ssl3_change_cipher_state(SSL *s, int which); void ssl3_cleanup_key_block(SSL *s); int ssl3_do_write(SSL *s, int type); int ssl3_send_alert(SSL *s, int level, int desc); int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, int len); int ssl3_get_req_cert_type(SSL *s, unsigned char *p); long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok); int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen); int ssl3_num_ciphers(void); SSL_CIPHER *ssl3_get_cipher(unsigned int u); int ssl3_renegotiate(SSL *ssl); int ssl3_renegotiate_check(SSL *ssl); int ssl3_dispatch_alert(SSL *s); int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek); int ssl3_write_bytes(SSL *s, int type, const void *buf, int len); int ssl3_final_finish_mac(SSL *s, EVP_MD_CTX *ctx1, EVP_MD_CTX *ctx2, const char *sender, int slen, unsigned char *p); int ssl3_cert_verify_mac(SSL *s, EVP_MD_CTX *in, unsigned char *p); void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len); int ssl3_enc(SSL *s, int send_data); int ssl3_mac(SSL *ssl, unsigned char *md, int send_data); unsigned long ssl3_output_cert_chain(SSL *s, X509 *x); SSL_CIPHER *ssl3_choose_cipher(SSL *ssl, STACK_OF(SSL_CIPHER) *clnt, STACK_OF(SSL_CIPHER) *srvr); int ssl3_setup_buffers(SSL *s); int ssl3_new(SSL *s); void ssl3_free(SSL *s); int ssl3_accept(SSL *s); int ssl3_connect(SSL *s); int ssl3_read(SSL *s, void *buf, int len); int ssl3_peek(SSL *s, void *buf, int len); int ssl3_write(SSL *s, const void *buf, int len); int ssl3_shutdown(SSL *s); void ssl3_clear(SSL *s); long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg); long ssl3_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg); long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp) (void)); long ssl3_ctx_callback_ctrl(SSL_CTX *s, int cmd, void (*fp) (void)); int ssl3_pending(const SSL *s); void ssl3_record_sequence_update(unsigned char *seq); int ssl3_do_change_cipher_spec(SSL *ssl); long ssl3_default_timeout(void); int ssl23_num_ciphers(void); SSL_CIPHER *ssl23_get_cipher(unsigned int u); int ssl23_read(SSL *s, void *buf, int len); int ssl23_peek(SSL *s, void *buf, int len); int ssl23_write(SSL *s, const void *buf, int len); int ssl23_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); SSL_CIPHER *ssl23_get_cipher_by_char(const unsigned char *p); long ssl23_default_timeout(void); long tls1_default_timeout(void); int dtls1_do_write(SSL *s, int type); int ssl3_read_n(SSL *s, int n, int max, int extend); int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek); int ssl3_do_compress(SSL *ssl); int ssl3_do_uncompress(SSL *ssl); int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, unsigned int len); unsigned char *dtls1_set_message_header(SSL *s, unsigned char *p, unsigned char mt, unsigned long len, unsigned long frag_off, unsigned long frag_len); int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len); int dtls1_write_bytes(SSL *s, int type, const void *buf, int len); int dtls1_send_change_cipher_spec(SSL *s, int a, int b); int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen); unsigned long dtls1_output_cert_chain(SSL *s, X509 *x); int dtls1_read_failed(SSL *s, int code); int dtls1_buffer_message(SSL *s, int ccs); int dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, int *found); int dtls1_get_queue_priority(unsigned short seq, int is_ccs); int dtls1_retransmit_buffered_messages(SSL *s); void dtls1_clear_received_buffer(SSL *s); void dtls1_clear_sent_buffer(SSL *s); void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr); void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr); void dtls1_reset_seq_numbers(SSL *s, int rw); long dtls1_default_timeout(void); struct timeval *dtls1_get_timeout(SSL *s, struct timeval *timeleft); int dtls1_check_timeout_num(SSL *s); int dtls1_handle_timeout(SSL *s); SSL_CIPHER *dtls1_get_cipher(unsigned int u); void dtls1_start_timer(SSL *s); void dtls1_stop_timer(SSL *s); int dtls1_is_timer_expired(SSL *s); void dtls1_double_timeout(SSL *s); int dtls1_send_newsession_ticket(SSL *s); unsigned int dtls1_min_mtu(void); /* some client-only functions */ int ssl3_client_hello(SSL *s); int ssl3_get_server_hello(SSL *s); int ssl3_get_certificate_request(SSL *s); int ssl3_get_new_session_ticket(SSL *s); int ssl3_get_cert_status(SSL *s); int ssl3_get_server_done(SSL *s); int ssl3_send_client_verify(SSL *s); int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey); int ssl3_send_client_certificate(SSL *s); int ssl3_send_client_key_exchange(SSL *s); int ssl3_get_key_exchange(SSL *s); int ssl3_get_server_certificate(SSL *s); int ssl3_check_cert_and_algorithm(SSL *s); # ifndef OPENSSL_NO_TLSEXT int ssl3_check_finished(SSL *s); # endif int dtls1_client_hello(SSL *s); int dtls1_send_client_certificate(SSL *s); int dtls1_send_client_key_exchange(SSL *s); int dtls1_send_client_verify(SSL *s); /* some server-only functions */ int ssl3_get_client_hello(SSL *s); int ssl3_send_server_hello(SSL *s); int ssl3_send_hello_request(SSL *s); int ssl3_send_server_key_exchange(SSL *s); int ssl3_send_certificate_request(SSL *s); int ssl3_send_server_done(SSL *s); int ssl3_check_client_hello(SSL *s); int ssl3_get_client_certificate(SSL *s); int ssl3_get_client_key_exchange(SSL *s); int ssl3_get_cert_verify(SSL *s); int dtls1_send_hello_request(SSL *s); int dtls1_send_server_hello(SSL *s); int dtls1_send_server_certificate(SSL *s); int dtls1_send_server_key_exchange(SSL *s); int dtls1_send_certificate_request(SSL *s); int dtls1_send_server_done(SSL *s); int ssl23_accept(SSL *s); int ssl23_connect(SSL *s); int ssl23_read_bytes(SSL *s, int n); int ssl23_write_bytes(SSL *s); int tls1_new(SSL *s); void tls1_free(SSL *s); void tls1_clear(SSL *s); long tls1_ctrl(SSL *s, int cmd, long larg, void *parg); long tls1_callback_ctrl(SSL *s, int cmd, void (*fp) (void)); SSL_METHOD *tlsv1_base_method(void); int dtls1_new(SSL *s); int dtls1_accept(SSL *s); int dtls1_connect(SSL *s); void dtls1_free(SSL *s); void dtls1_clear(SSL *s); long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg); SSL_METHOD *dtlsv1_base_method(void); long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok); int dtls1_get_record(SSL *s); int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragement); int dtls1_dispatch_alert(SSL *s); int dtls1_enc(SSL *s, int snd); int ssl_init_wbio_buffer(SSL *s, int push); void ssl_free_wbio_buffer(SSL *s); int tls1_change_cipher_state(SSL *s, int which); int tls1_setup_key_block(SSL *s); int tls1_enc(SSL *s, int snd); int tls1_final_finish_mac(SSL *s, EVP_MD_CTX *in1_ctx, EVP_MD_CTX *in2_ctx, const char *str, int slen, unsigned char *p); int tls1_cert_verify_mac(SSL *s, EVP_MD_CTX *in, unsigned char *p); int tls1_mac(SSL *ssl, unsigned char *md, int snd); int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, int len); int tls1_alert_code(int code); int ssl3_alert_code(int code); int ssl_ok(SSL *s); int check_srvr_ecc_cert_and_alg(X509 *x, SSL_CIPHER *cs); SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n); # ifndef OPENSSL_NO_TLSEXT unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *limit, int *al); int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al); int ssl_prepare_clienthello_tlsext(SSL *s); int ssl_prepare_serverhello_tlsext(SSL *s); int ssl_check_clienthello_tlsext_early(SSL *s); int ssl_check_clienthello_tlsext_late(SSL *s); int ssl_check_serverhello_tlsext(SSL *s); # ifdef OPENSSL_NO_SHA256 # define tlsext_tick_md EVP_sha1 # else # define tlsext_tick_md EVP_sha256 # endif int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, const unsigned char *limit, SSL_SESSION **ret); EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md); void ssl_clear_hash_ctx(EVP_MD_CTX **hash); int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, int maxlen); int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len, int *al); int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, int maxlen); int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, int *al); # endif /* s3_cbc.c */ void ssl3_cbc_copy_mac(unsigned char *out, const SSL3_RECORD *rec, unsigned md_size, unsigned orig_len); int ssl3_cbc_remove_padding(const SSL *s, SSL3_RECORD *rec, unsigned block_size, unsigned mac_size); int tls1_cbc_remove_padding(const SSL *s, SSL3_RECORD *rec, unsigned block_size, unsigned mac_size); char ssl3_cbc_record_digest_supported(const EVP_MD *hash); void ssl3_cbc_digest_record(const EVP_MD *hash, unsigned char *md_out, size_t *md_out_size, const unsigned char header[13], const unsigned char *data, size_t data_plus_mac_size, size_t data_plus_mac_plus_padding_size, const unsigned char *mac_secret, unsigned mac_secret_length, char is_sslv3); void tls_fips_digest_extra(const EVP_CIPHER_CTX *cipher_ctx, const EVP_MD *hash, HMAC_CTX *hctx, const unsigned char *data, size_t data_len, size_t orig_len); #endif Index: releng/9.3/sys/conf/newvers.sh =================================================================== --- releng/9.3/sys/conf/newvers.sh (revision 308204) +++ releng/9.3/sys/conf/newvers.sh (revision 308205) @@ -1,160 +1,160 @@ #!/bin/sh - # # Copyright (c) 1984, 1986, 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. # 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. # # @(#)newvers.sh 8.1 (Berkeley) 4/20/94 # $FreeBSD$ TYPE="FreeBSD" REVISION="9.3" -BRANCH="RELEASE-p49" +BRANCH="RELEASE-p50" if [ "X${BRANCH_OVERRIDE}" != "X" ]; then BRANCH=${BRANCH_OVERRIDE} fi RELEASE="${REVISION}-${BRANCH}" VERSION="${TYPE} ${RELEASE}" if [ "X${SYSDIR}" = "X" ]; then SYSDIR=$(dirname $0)/.. fi if [ "X${PARAMFILE}" != "X" ]; then RELDATE=$(awk '/__FreeBSD_version.*propagated to newvers/ {print $3}' \ ${PARAMFILE}) else RELDATE=$(awk '/__FreeBSD_version.*propagated to newvers/ {print $3}' \ ${SYSDIR}/sys/param.h) fi b=share/examples/etc/bsd-style-copyright year=`date '+%Y'` # look for copyright template for bsd_copyright in ../$b ../../$b ../../../$b /usr/src/$b /usr/$b do if [ -r "$bsd_copyright" ]; then COPYRIGHT=`sed \ -e "s/\[year\]/1992-$year/" \ -e 's/\[your name here\]\.* /The FreeBSD Project./' \ -e 's/\[your name\]\.*/The FreeBSD Project./' \ -e '/\[id for your version control system, if any\]/d' \ $bsd_copyright` break fi done # no copyright found, use a dummy if [ X"$COPYRIGHT" = X ]; then COPYRIGHT="/*- * Copyright (c) 1992-$year The FreeBSD Project. * All rights reserved. * */" fi # add newline COPYRIGHT="$COPYRIGHT " LC_ALL=C; export LC_ALL if [ ! -r version ] then echo 0 > version fi touch version v=`cat version` u=${USER:-root} d=`pwd` h=${HOSTNAME:-`hostname`} t=`date` i=`${MAKE:-make} -V KERN_IDENT` compiler_v=$($(${MAKE:-make} -V CC) -v 2>&1 | grep 'version') for dir in /bin /usr/bin /usr/local/bin; do if [ -x "${dir}/svnversion" ] ; then svnversion=${dir}/svnversion break fi done if [ -d "${SYSDIR}/../.git" ] ; then for dir in /bin /usr/bin /usr/local/bin; do if [ -x "${dir}/git" ] ; then git_cmd="${dir}/git --git-dir=${SYSDIR}/../.git" break fi done fi if [ -n "$svnversion" ] ; then echo "$svnversion" svn=`cd ${SYSDIR} && $svnversion` case "$svn" in [0-9]*) svn=" r${svn}" ;; *) unset svn ;; esac fi if [ -n "$git_cmd" ] ; then git=`$git_cmd rev-parse --verify --short HEAD 2>/dev/null` svn=`$git_cmd svn find-rev $git 2>/dev/null` if [ -n "$svn" ] ; then svn=" r${svn}" git="=${git}" else svn=`$git_cmd log | fgrep 'git-svn-id:' | head -1 | \ sed -n 's/^.*@\([0-9][0-9]*\).*$/\1/p'` if [ -z "$svn" ] ; then svn=`$git_cmd log --format='format:%N' | \ grep '^svn ' | head -1 | \ sed -n 's/^.*revision=\([0-9][0-9]*\).*$/\1/p'` fi if [ -n "$svn" ] ; then svn=" r${svn}" git="+${git}" else git=" ${git}" fi fi if $git_cmd --work-tree=${SYSDIR}/.. diff-index \ --name-only HEAD | read dummy; then git="${git}-dirty" fi fi cat << EOF > vers.c $COPYRIGHT #define SCCSSTR "@(#)${VERSION} #${v}${svn}${git}: ${t}" #define VERSTR "${VERSION} #${v}${svn}${git}: ${t}\\n ${u}@${h}:${d}\\n" #define RELSTR "${RELEASE}" char sccs[sizeof(SCCSSTR) > 128 ? sizeof(SCCSSTR) : 128] = SCCSSTR; char version[sizeof(VERSTR) > 256 ? sizeof(VERSTR) : 256] = VERSTR; char compiler_version[] = "${compiler_v}"; char ostype[] = "${TYPE}"; char osrelease[sizeof(RELSTR) > 32 ? sizeof(RELSTR) : 32] = RELSTR; int osreldate = ${RELDATE}; char kern_ident[] = "${i}"; EOF echo $((v + 1)) > version