-TABOUNCE
+-TADDR_PATTERN
-TALIAS_TOKEN
-TANVIL_CLNT
-TANVIL_LOCAL
-TBOUNCE_LOG
-TBOUNCE_STAT
-TCFG_PARSER
+-TCIDR_MATCH
-TCLEANUP_STATE
-TCLIENT_LIST
-TCLNT_STREAM
-THTABLE
-THTABLE_INFO
-TINET_ADDR_LIST
+-TINET_PROTO_INFO
-TINTV
-TINT_TABLE
-TJMP_BUF_WRAPPER
-TMAIL_PRINT
-TMAIL_SCAN
-TMAIL_STREAM
+-TMAI_HOSTADDR_STR
+-TMAI_HOSTNAME_STR
+-TMAI_SERVNAME_STR
+-TMAI_SERVPORT_STR
-TMAPS
-TMASTER_PROC
-TMASTER_SERV
/usr/spool/mail yes (compile time option)
/var/mail yes (compile time option)
/var/spool/mail yes (compile time option)
-8bit->7bit MIME yes
:include: yes (mail to /file and |command is off by default)
address probing yes (optional persistent database)
aliases yes (can enable/disable mail to /file or |command)
greylist yes (delegated policy script)
home mailbox yes
ident lookup no
-ipv6 no (to be done, patches exist)
+ipv6 yes (compatibility for ipv4-only kernels/libraries)
ldap tables yes (contributed)
lmtp support yes (client)
luser relay yes
mailq yes
majordomo yes (edit approve script to delete /^delivered-to:/i)
mime yes (including 8bit to quoted-printable conversion)
-mime conversion not yet; postfix uses just-send-eight
mysql tables yes (contributed)
netinfo tables yes (contributed)
newaliases yes (main alias database only)
nis tables yes
-nis+ tables yes
+nis+ tables yes (contributed)
no <> in smtp yes (most common address forms)
pgsql tables yes (contributed)
pipeline option yes (server and client)
size option yes, server and client
smarthost yes (specify relayhost in main.cf)
spf yes (delegated policy script)
-starttls yes (third party patch)
+starttls yes
tcp wrapper no (use built-in blacklist facility)
user+extension yes (also: .forward+extension)
user-extension yes (also: .forward-extension)
Bugfix: further postcat corner cases.
+20041221-9
+
+ Infrastructure: unified IPv4/IPv6 name/address API so that
+ Postfix can support IPv6 without #ifdef INET6 everywhere.
+ In particular, we allow #ifdef in libraries but avoid it
+ in applications. Files: util/myaddrinfo.[hc],
+ util/sock_addr.[hc], dns/dns_rr_to_pa.c, dns/dns_sa_to_rr.c,
+ dns/dns_rr_eq_sa.c, dns/dns_rr_to_sa.c, inet_proto.[hc].
+
+ Postfix no longer attempts to deliver mail via IPv6 when
+ the system has no IPv6 connectivity. Network protocol
+ support is now selected with the "inet_protocols" configuration
+ parameter, instead of "inet_interfaces". The "inet_protocols"
+ parameter also controls what DNS lookups Postfix will do.
+
+ Infrastructure: eliminated two host/port parsing routines.
+ Only one survives: host_port(), in an extended form that
+ allows for missing host or missing service information but
+ not both. File: util/host_port.c.
+
+20041229
+
+ Milestone: Postfix with the unified IPv4/IPv6 socket/name
+ API builds without compiler error on IPv4-only system and
+ actually works.
+
20041228
Bugfix: SMTPD_PROXY_README incorrectly claimed that ":port"
without exposing the service to the network. Instead,
":port" causes a client to connect to "localhost".
+20041231
+
+ Linux workaround: when mynetworks isn't set, a chrooted
+ process could not read the IPv6 address information from
+ /proc. We now invoke own_inet_addr() before chrooting,
+ while processing main.cf. File: global/mail_params.c.
+
+20050101
+
+ Workaround for (Linux) systems without IPV6_V6ONLY support
+ (RFC 3493). When Postfix listened on an IPv4 wild-card
+ smtp socket, the IPv6 wild-card smtp listener would fail
+ with EADDRINUSE (and vice versa). File: util/myaddrinfo.c.
+
+20050103
+
+ Safety: when the IPV6 netmask can't be determined, assume
+ /128 (host only). File: util/inet_addr_local.c.
+
+20050104
+
+ Re-implemented IPv6 support for net/mask pattern matching.
+ Files: util/cidr_match.[hc], util/dict_cidr.c,
+ util/match_ops.[hc], proto/cidr_table.
+
+20050105
+
+ Moved mask_addr() to its own module so that it could also
+ be called by mynetworks() and inet_addr_local() to remove
+ non-zero host bits from IPv6 network/mask patterns. File:
+ util/mask_addr.c.
+
+20050108
+
+ Re-implemented IPv6 support for network interface lookup
+ via the Linux /proc file system. File: util/inet_addr_local.c.
+
+20050111
+
+ Feature: specify "inet_interfaces = loopback-only" for
+ servers that must listen on local interfaces only, without
+ having to specify IPv4 and/or IPv6 addresses in main.cf or
+ master.cf. File: global/own_inet_addr.c.
+
+ Workaround: AIX 5.1 getaddrinfo() can't handle a null host
+ argument with AI_PASSIVE. Instead we specify an explicit
+ protocol family, a host of "::" or "0.0.0.0", and turn off
+ IPV6_V6ONLY. Files: util_myaddrinfo.c, util/inet_listen.c.
+
+ Workaround: AIX 5.1 getaddrinfo() can't handle a "0" service
+ argument. Instead we specify "1". Files: util/inet_addr_host.c.
+
+20040513
+
+ Cleanup: now that the over-all structure is proving itself,
+ clean up some internal APIs to increase robustness and get
+ rid of some clumsiness. Mainly, the getaddrinfo(3) interface.
+
+ Start-up performance: the hash_queue_names default setting
+ is reduced from eight directories to just defer and deferred.
+ This reduces time for checking the Postfix queue. Files:
+ conf/post-install, global/mail_params.h.
+
+20040514
+
+ Further cleanup: eliminate duplicate IPv6 results when the
+ mynetworks value is generated by Postfix. More documentation
+ of the new internal APIs.
+
+ Performance: reduced start-up delay by moving warning-only
+ startup checks into the background; they now start after
+ one minute to allow the system to finish booting. File:
+ conf/postfix-script.
+
+20050115
+
+ Further hardening of the IPv6 support: don't trust system
+ libraries to protect Postfix against malformed IPv6 address
+ literals. Their syntax is complex enough that errors are
+ likely. Files: global/resolve_local.c, util/valid_hostname.c.
+
+ Further cleanup: RFC 2821 requires the IPv6: prefix with
+ IPv6 address strings. The smtp and qmqp servers maintain
+ separate address instances, the bare address and the RFC
+ 2821 compatible form, and use each where appropriate. This
+ strict separation simplifies address syntax checks as well
+ as the implementation of XCLIENT and XFORWARD.
+
+20050116
+
+ Infrastructure: new valid_mailhost_addr() routine to verify
+ that an address literal satisfies RFC 2821. An IPv4 address
+ is in dotted-quad decimal form, and an IPv6 address is in
+ hexadecimal form, with the "IPv6:" prefix. Files:
+ global/valid_mailhost_addr.[hc].
+
+ Further cleanup: valid_hostname() no longer allows network
+ addresses or numerical domain names. While it made some
+ sense with IPv4 dotted quad decimal forms, with IPv6 it
+ just made no sense anymore. Again, being stricter actually
+ simplifies code. Files: util/valid_hostname.c and a
+ surprisingly small number of valid_hostname() callers that
+ did not reject numerical forms.
+
+ Bugfix: in the Postfix 2.2 SMTP client, the debug_peer_init()
+ call was moved to the after-chroot initialization.
+
+20050117
+
+ Milestone: first non-non-production snapshot with IPv6.
+
Open problems:
+ Med: transform IPv4-in-IPv6 address literals to IPv4 form
+ when comparing against local IP addresses?
+
+ Med: transform IPv4-in-IPv6 address literals to IPv4 form
+ when eliminating MX mailer loops?
+
+ Med: Postfix requires [] around IPv6 address information
+ in match lists such as mynetworks, debug_peer_list etc.,
+ but the [] must not be specified in access(5) maps. Other
+ places don't care. For now, this gotcha is documented in
+ IPV6_README and in postconf(5) with each feature that may
+ use IPv6 address information. The general recommendation
+ is not to use [] unless absolutely necessary.
+
+ Med: the partial address matching of IPv6 addresses in
+ access(5) maps is a bit lame: it repeatedly truncates the
+ last ":octetpair" from the printable address representation
+ until a match is found or until truncation is no longer
+ possible. Since one or more ":" are usually omitted from
+ the printable IPv6 address representation, this does not
+ really try all the possibilities that one might expect to
+ be tried. For now, this gotcha is documented in access(5).
+
+ Low: cap bounce queue life time with regular queue life
+ time.
+
Med: implement ${name[?:]value} in main.cf or update the
postconf(5) manual.
--- /dev/null
+ChangeLog for Dean Strik's IPv6 patch for Postfix. The patch is based on
+PLD's patch, which in turn seems to be based on KAME's. For more information:
+
+ http://www.ipnet6.org/postfix/
+
+---------------------------------------------------------------------
+
+Version 1.25 Postfix release 2.1.3
+ Postfix release 2.0.20
+ Postfix snapshot 2.2-20040616
+
+ Bugfix: Misplaced myfree() caused a small memory leak. Reported
+ by Christian von Roques.
+ File: util/match_ops.c
+
+ Removed the colon (:) from the characters XFORWARD replaces by
+ a question mark (IPv6 addresses looked like 2001?610?1108?5010??1
+ in logging). Reported by Philipp Morger.
+ File: smtpd/smtpd.c
+
+Version 1.24 Postfix release 2.1.1
+ Postfix release 2.0.20
+ Postfix snapshot 2.0.19-20040312
+ Postfix snapshot 2.2-20040504
+
+ Bugfix: Prefixlen non-null host portion validation (in CIDR maps
+ for example) yielded incorrect results sometimes because signed
+ arithmetic was used instead of unsigned.
+ File: util/match_ops.c
+
+ Patch correction: The TLS+IPv6 patch for Postfix 2.1.0 missed
+ the master.cf update (used for new installations). Added it
+ back.
+
+Version 1.23 Postfix release 2.1.0
+ Postfix release 2.0.20
+ Postfix snapshot 2.0.19-20040312
+
+ Patch fixes: Several code fixes to make the patch compile
+ and work correctly when compiled without IPv6 support.
+
+ Bugfix (Solaris only?): address family length was not updated
+ which could cause client hostname validation errors.
+ File: smtpd/smtpd_peer.c
+
+ Portability: added support for Darwin 7.3+. This may need
+ some further testing.
+
+ Cleanup: Restructure and redocument interface address
+ retrieval functions. (This reduced the number of preprocessor
+ statements from 99 to 93 ;)
+ File: util/inet_addr_local.c
+
+ Cleanup: make several explicit casts to have compilers shut
+ their pie holes about uninteresting things.
+
+Version 1.22 Postfix release 2.0.19
+ Postfix snapshot 2.0.19-20040312
+
+ Feature: Support "inet_interfaces = IPv4:all" and
+ "inet_interfaces = IPv6:all", to restrict postfix to use
+ either IPv4-only or IPv6-only. A more complete implementation
+ will be part of a future patch. (Slightly modified) patch by
+ Michal Ludvig, SuSE.
+ Files: util/interfaces_to_af.[ch], util/inet_addr_local.c,
+ global/own_inet_addr.c, global/wildcard_inet_addr.[ch],
+ master/master_ent.ch
+
+ Bugfix: In Postfix snapshots, a #define was misplaced with
+ the effect that IPv6 subnets were not included in auto-
+ generated $mynetworks (i.e., mynetworks not defined in main.cf,
+ when also mynetworks_style=subnet) on Linux 2.x systems.
+ File: utils/sys_defs.h
+
+Version 1.21a Postfix snapshots 2.0.18-2004{0122,0205,0209}
+ 2.0.19-20040312
+
+ TLS/snapshot version: Update TLS patch to 0.8.18-20040122.
+ Performed as a total repatch. 0.8.18 is cleaner with tls_*
+ variables if TLS is not actually compiled in.
+
+Version 1.21 Postfix releases 2.0.18 - 2.0.19
+ Postfix snapshot 2.0.16-20031231
+
+ Bugfix: The SMTP client could fail to setup a connection,
+ erroring with a bogus "getaddrinfo(...): hostname nor servname
+ provided" warning, because the wrong address was selected.
+ File: smtp/smtp_connect.c
+
+ Safety: in dynamically growing data structures, update the
+ length info after (instead of before) updating the data size.
+ File: util/inet_addr_list.c
+
+Version 1.20 Postfix release 2.0.16
+ Postfix snapshot 2.0.16-20031207
+
+ Bugfix: The SMTP client would abort when binding to specific
+ IPv6 addresses.
+ File: smtp/smtp_connect.c
+
+ Synchronisation/bugfix: LMTP source address binding is identical
+ to the SMTP source binding setup, avoiding the need for
+ lmtp_bind_address(6) if inet_interfaces is set to a single
+ host for an address family.
+ File: lmtp/lmtp_connect.c
+
+Version 1.19 Postfix release 2.0.16
+ Postfix snapshot 2.0.16-20031207
+
+ Bugfix: Synchronisation of TLS patches in snapshots of 1.18[ab]
+ was not complete, causing a crash of smtpd if used with the new
+ proxy agent.
+ File: smtpd/smtpd.c
+
+ Bugfix: SMTP source address binding based on a single hostname
+ in inet_interfaces did not work since the code counted IPv4 and
+ IPv6 addresses instead of only the used address family. Fixed,
+ thereby no longer requiring exact specification of
+ smtp_bind_address(6) in this case.
+ File: smtp/smtp_connect.c
+
+ Bugfix: The QMQP sink server did not compile correctly. This
+ program, part of smtpstone tools, is not compiled or installed
+ by default.
+ File: smtpstone/qmqp-sink.c
+
+ Bugfix: NI_WITHSCOPEID was not correctly defined everywhere,
+ which could result in EAI_BADFLAGS. Changed location of
+ definition to correct it.
+ Files: util/sys_defs.h, util/inet_addr_list.h
+
+Version 1.18b Postfix snapshot 2.0.16-20030921
+
+ IPv6 support: Added IPv6-enabled code to the new snapshot
+ check_*_{ns,mx}_access restrictions.
+ File: smtpd/smtpd_check.c
+
+Version 1.18a Postfix release 2.0.16
+
+ Update (TLS patches): Updated Lutz Jaenicke's TLS patch to
+ version 0.8.16. See pfixtls/ChangeLog for details.
+ Diff contributed by Tuomo Soini.
+
+ The TLS+IPv6 patch now contains the original TLS patch
+ documentation from Lutz Jaenicke.
+
+Version 1.18 Postfix releases 2.0.14 - 2.0.15
+ Postfix snapshot 2.0.14-20030812
+
+ Bugfix: Perform actual hostname verification in the SMTP
+ and QMTP servers. This was never supported in the IPv6
+ patch. Reported by Wolfgang S. Rupprecht.
+ Files: smtpd/smtpd_peer.c, qmqpd/qmqpd_peer.c
+
+ IPv6 address ranges using address/prefixlength (e.g. in
+ mynetworks and access maps) should be written as
+ [ipv6:addr:ess]/plen (e.g. [fec0:10:20::]/48). The old
+ supported syntax, [ipv6:addr:ess/plen] is deprecated and
+ support will be removed in a later version.
+ Thanks to Dr. Peter Bieringer and Pekka Savola for discussion.
+ Files: util/match_ops.c, global/mynetworks.c
+
+ Explicitly prefer IPv6 over IPv4 addresses when delivering
+ to a host when MX lookups are disabled when SMTP address
+ randomization is on (default).
+ File: smtp/smtp_addr.c
+
+ Compliance: write IPv6 address literals in mail headers
+ as [IPv6:addr] instead of [addr] as per RFC 2821:4.1.3
+ tagging requirement, for example [IPv6:fec0:10:20::1].
+ Pointed out by Dr. Peter Bieringer.
+ Files: smtpd/smtpd{,_peer,_state}.c, smtpd/smtpd.h
+
+Version 1.17 Postfix release 2.0.13, 2.0.14
+ Postfix snapshot 2.0.13-20030706, 2.0.14-20030812
+
+ Bugfix: Two memory allocation/deallocation bugs were
+ introduced in patch 1.16. The impact of these bugs could
+ be 'arbitrary' memory corruption.
+ File: util/match_ops.c
+
+Version 1.16 Postfix release 2.0.13
+ Postfix snapshot 2.0.13-20030706
+
+ Cleanup: rewrote match_ops.c. This rewrite is partly based on
+ patch by Takahiro Igarashi. The rewrite enables some better
+ handling of scoped addresses, and drops all GPL code from the
+ patch, easying license considerations. Also, allowed for
+ use of this code by the CIDR maps.
+ Files: util/match_ops.[ch]
+
+ Bugfix: correctly relay for scoped unicast addresses when
+ applicable. Until now, while Postfix was able to recognize
+ scoped addresses, it was not able to see e.g. fe80::10%fxp0
+ as local in mynetworks validation. KAME-only code.
+ (I've never heard of people using scoped addresses (think
+ link-local addresses) for mail relaying though...)
+ Files: util/inet_addr_list.[ch]
+
+ Feature (snapshot only): rewrote CIDR maps code to support
+ IPv6 addresses, using new match_ops code. Allow the use
+ of [::/0] since it allows one to easily disable further
+ checks for IPv6 addresses.
+ File: util/dict_cidr.c
+
+ Consistency: require IPv6 addresses in inet_interfaces to
+ be enclosed in square brackets.
+ File: util/inet_addr_host.c
+
+ Bugfix: (Linux2-only) A #define was misspelled. This could
+ lead to Postfix being unable to read the system's local IPv6
+ addresses (e.g. when using inet_interfaces).
+ Spotted by Jochen Friedrich.
+ File: util/sys_defs.h
+
+ Cleanup: require non-null host portion in CIDR /
+ prefixlength notations for IPv6 (was IPv4-only).
+
+Version 1.15a Postfix release 2.0.13
+
+ Update (TLS patches): Updated Lutz Jaenicke's TLS patch
+ to version 0.8.15. This version introduces new options
+ for managing SASL mechanisms. More information at:
+ http://www.aet.tu-cottbus.de/personen/jaenicke/pfixtls/
+ Diff contributed by Tuomo Soini.
+
+Version 1.15 Postfix release 2.0.12, 2.0.13
+ Postfix snapshot 2.0.12-20030621
+
+ Bugfix (TLS-snapshots only): a change in Postfix snapshot
+ 2.0.11-20030609 broke initialisation of TLS in smtpd,
+ causing TLS to both be unadvertised and unaccepted.
+ This was fixed again by reordering initialisation.
+ File: smtpd/smtpd.c
+
+ Update (TLS patches): Updated Lutz Jaenicke's TLS patch
+ to version 0.8.14. This version introduces a few fixes and
+ uses USE_SSL instead of HAS_SSL. More information at:
+ http://www.aet.tu-cottbus.de/personen/jaenicke/pfixtls/
+ Diff contributed by Tuomo Soini.
+
+ Bugfix (Postfix releases only - this was already added to
+ the snapshots in patch 1.14). KAME derived systems only.
+ Correctly decode scoped addresses, including network
+ interface specifiers.
+ File: util/inet_addr_local.c
+
+Version 1.14 Postfix releases 2.0.9, 2.0.10, 2.0.11, 2.0.12
+ Postfix snapshots 2.0.9-20030424, 2.0.10-20030521,
+ 2.0.11-20030609, 2.0.12-20030611
+
+ Patch change: made the patch available as an IPv6-only
+ patch (i.e., without the TLS code). This on popular
+ request by users and packagers.
+ A TLS+IPv6 version is still available of course.
+
+ Bugfix: correctly decode scoped addresses from now on
+ (KAME derived systems only). I think the original code
+ was written by Itojun, so I'm rather puzzled that it
+ didn't work...
+ File: util/inet_addr_local.c
+
+ Bugfix/portability: Recent KAME snapshots return both
+ TCP and SCTP address information on getaddrinfo() if
+ no protocol was specified. This causes the socket counts
+ to be wrong, confusing child processes.
+ Merged patch by JINMEI Tatuya of KAME to fix this.
+ Files: master/master.h, master/master_{ent,conf}.[ch],
+ util/inet_listen.c
+
+ Documentation: added an IPV6_README file to the patch.
+ This file contains the primary documentation. Also,
+ added a sample-ipv6.cf to describe the (currently few)
+ IPv6 related main.cf parameters.
+
+ Bugfix: the netmask structures for the *unsupported*
+ platforms (boldly assume /64) were added to the wrong
+ list (addresses instead of masks). This bug did not affect
+ any supported platform though.
+ File: util/inet_addr_local.c
+
+ Portability: added support for HP/Compaq Tru64Unix V5.1
+ and later. (compiled with CompaqCC only).
+ Thanks to Sten Spans for providing root access to an
+ IPv6-connected Tru64 testing machine.
+
+Version 1.13 Postfix releases 2.0.4 - 2.0.9
+ Postfix snapshots 2.0.3-20030126 - 2.0.7-20030319
+
+ Bugfix: Due to a missing storage pointer, DNS lookup
+ results in the permit_mx_backups code were not processed,
+ and smtpd would likely crash.
+ Thanks to Wouter de Jong for reporting the crashes.
+ File: smtpd/smtpd_check.c
+
+ Incompatible change: The addresses given to the parameters
+ smtp_bind_address6 and lmtp_bind_address6 now need to be
+ enclosed in square brackets for consistency.
+ Files: [ls]mtp/[ls]mtp_connect.c
+
+Version 1.12 Postfix releases 2.0.2, 2.0.3
+ Postfix snapshots 2.0.2-20030115, 2.0.3-20030126
+
+ Bugfix/workaround (Solaris): A simplified comparison
+ function for Solaris' qsort() function, would result
+ in corruption of network addresses in the SMTP client.
+ Fixed. Reported with possible fix by Edvard Tuinder.
+ File: smtp/smtp_addr.c
+
+Version 1.11 Postfix releases 2.0.0.x, 2.0.1, 2.0.2
+ Postfix snapshots 2.0.0-20030105, 2.0.1-20030112
+ 2.0.2-20030115
+
+ Bugfix (Solaris): Properly initialize lifconf structure
+ when requesting host interface addresses. If you get
+ warnings about SIOCGLIFCONF with earlier versions,
+ please upgrade.
+ File: util/inet_addr_local.c
+
+ Patch fix: fixed compilation errors in case the patch is
+ applied but built without IPv6 support (i.e., on unsupported
+ platforms).
+
+Version 1.10 Postfix snapshots 1.1.12-200212{19,21}
+ Postfix releases 2.0.0, 2.0.0.{1,2}
+ Postfix snapshots 2.0.0-20021223 - 2.0.0-20030101
+
+ 'Bugfix': don't show spurious warnings on Linux systems
+ about missing /proc/net/if_inet6 unless verbose mode
+ is enabled.
+ File: util/inet_addr_local.c
+
+ Bugfix: If unable to create a socket for a specific adress
+ in the SMTP client (e.g., when trying to create an IPv6
+ connection while the local host has no configured IPv6
+ addresses), then stop the attempt.
+ File: smtp/smtp_connect.c
+
+ Small bugfix: never query DNS for <localpart@[domain.tld]>.
+ This syntax now correctly generates an error immediately.
+ File: global/resolve_local.c
+
+ Updated TLS patch to 0.8.12-1.1.12-20021219-0.9.6h, fixing
+ a bug with "sendmail -bs".
+
+Version 1.9 Postfix version 1.1.11-20021115
+ Postfix version 1.1.12-2002{1124,1209-1213}
+
+ Bugfix: with getifaddrs() code (*BSD, linux-USAGI), IPv4
+ netmasks were set to /32 effectively. Work around broken
+ netmask data structures (*BSD only perhaps).
+
+ Bugfix: same data corruption in another place created
+ entirely wrong IPv4 netmasks. Work around broken
+ SIOCGIFNETMASK structure.
+
+ New code was added for correct IPv6 netmasks. The original
+ code did not contain IPv6 netmask support at all!
+ For Solaris, use SIOCGLIF*; Linux: /proc/net/if_inet6.
+ Getifaddrs() support is used otherwise. This should cover
+ all supported systems. Other systems also work, prefix
+ length is always set to /64 then.
+
+ Since there are no classes (context: Class A, class B etc
+ networks) with IPv6, default to IPv6 subnet style if the
+ mynetworks style is 'class'. I recommend against this style
+ anyway.
+
+ Added support to display IPv6 nets mynetworks output.
+
+Version 1.8 Postfix version 1.1.11-200211{01,15}
+
+ An earlier author of the patch made a typo in the GAI_STRERROR()
+ macro, resulting in bogus error messages when checking for
+ PTR records. Fixed.
+
+ IPv4-mapped addresses in the smtpd are converted to true IPv4
+ addresses just after the connection has been made. This means
+ that all IPv4-mapped addresses are now logged as true IPv4
+ addresses. Hence beside RBL checks, also access maps now treat
+ IPv4-mapped addresses as native IPv4. Note that ::ffff:...
+ entries in your access tables will no longer work.
+
+ You can now specify IPv6 'parent' networks in your access maps,
+ e.g. to reject all mail from 3ffe:200:... nodes, add the line
+ 3ffe:200 REJECT
+ Use of trailing colons is discouraged because postmap will
+ warn about it possibly being an alias...
+ NOTE: I'll soon obsolete this again in favor of the more
+ common address/len notation. This was just so trivial to add
+ that it didn't hurt and I needed it :)
+
+ For easy reference, the version of the TLS/IPv6 patch can be
+ dynamically queried using the tls_ipv6_version variable.
+ This gives the short version (like, "1.8").
+
+ The service bind address for 'inet' sockets in master.cf (e.g.,
+ smtpd), must be enclosed in square brackets '[..]' for IPv6
+ addresses. The old style (without brackets) still works but is
+ unsupported and may be removed in the future. Example
+ [::1]:smtp inet n - n - - smtpd
+
+Version 1.7 Postfix version 1.1.11-20021029 - 1.1.11-20021101
+
+ Postfix' SMTP client performs randomization of MX addresses
+ when sending mail. This however could result in A records
+ being used before AAAA records. This has been corrected.
+
+ Note that from Postfix version 1.1.11-20021029 on, there is
+ a proxy_interfaces parameter. This has of course not been
+ ported to IPv6 addresses...
+
+Version 1.6 Postfix version 1.1.11-20020928
+
+ Added IPv6 support for backup_mx_networks feature; also the
+ behaviour when DNS lookups fail when checking whether the
+ local host is an MX for a domain conforms to the IPv4 case:
+ defer rather than allow.
+
+Version 1.5 Postfix version 1.1.11-20020917
+
+ I introduced two bugs when I rewrote my older LMTP IPv6 patch.
+ These bugs effectively rendered LMTP useless. Now fixed.
+ Bugs spotted by Kaj Niemi.
+
+ Now supports Solaris 8 and 9. Due to lack of testing equipment,
+ this has been only tested in production on Solaris 9, both
+ with gcc and the Sun Workshop Compiler.
+
+Version 1.4 Postfix version 1.1.11-20020822 - 1.1.11-20020917
+
+ OpenBSD (>=200003) and FreeBSD release 4 and up now use
+ getifaddrs(). This makes for cleaner code. The old code
+ seems to be bug-ridden anyway.
+
+ Got rid of some compiler warnings. Should be cleaner on
+ Alpha as well now. Thanks to Sten Spans for providing me
+ access to an Alpha running FreeBSD4.
+
+ Fixed an old bug in smtpd memory alloation if you compiled
+ without IPv6 support (the wrong buffer size was used. This
+ was harmless for IPv6-enabled compiles since the sizes were
+ equal then).
+
+ Added ChangeLog to the patch (as IPv6-ChangeLog) (this
+ was absent in 1.3 contrary to docs).
+
+Version 1.3 Postfix version 1.1.11-20020613 - 1.1.11-20020718
+
+ FYI: In postfix version 1.1.11-20020718, DNS lookups for
+ AAAA can be done natively. The code matches the code in
+ the patch (though the #ifdef changed from INET6 to T_AAAA).
+ This change causes the patch for 1.1.11-20020718 to be a
+ bit smaller.
+
+Version 1.2 Postfix version 1.1.11-20020613
+
+ Added IPv6 support for the LMTP client.
+
+ Added lmtp_bind_address and lmtp_bind_address6 parameters,
+ similar to those for smtp.
+
+ Added IPv6 support for the QMQP server.
+
+Version 1.1 Postfix version 1.1.11-20020602 - 1.1.11-20020613
+
+ Added parameter smtp_bind_address6. By using this parameter,
+ it is possible to bind to an IPv6 address, independently of
+ IPv4 address binding.
+
+ Lutz fixed a bug in his TLS patch regarding SASL. Incorporated.
+
+Version 1.0.x Postfix version 1.1.8-20020505 - 1.1.11-20020602
+
+ Patch derived from PLD's IPv6 patch for Postfix, revision 1.10
+ which applied to early Postfix snapshots 1.1.x. Updated this
+ patch to apply to 1.1.8-20020505.
+
+ Added compile-time checks for SS_LEN. Some Linux installations,
+ and maybe other systems, do define SA_LEN, but not SS_LEN.
+
+ Several updates of postfix snapshots.
+
default: update
makefiles Makefiles:
+ (echo "# Do not edit -- this file documents how Postfix was built for your machine."; $(SHELL) makedefs) >makedefs.tmp
+ set +e; if cmp makedefs.tmp conf/makedefs.out; then rm makedefs.tmp; \
+ else mv makedefs.tmp conf/makedefs.out; fi >/dev/null 2>/dev/null
set -e; for i in $(DIRS); do \
(set -e; echo "[$$i]"; cd $$i; rm -f Makefile; \
$(MAKE) -f Makefile.in Makefile MAKELEVEL=) || exit 1; \
done;
- rm -f Makefile; (set -e; $(SHELL) makedefs && cat Makefile.in) >Makefile
- (echo "# Do not edit -- this file documents how Postfix was built for your machine."; $(SHELL) makedefs) >makedefs.tmp
- set +e; if cmp makedefs.tmp conf/makedefs.out; then rm makedefs.tmp; \
- else mv makedefs.tmp conf/makedefs.out; fi >/dev/null 2>/dev/null
+ rm -f Makefile; (tail +2 conf/makedefs.out; cat Makefile.in) >Makefile
update printfck tests:
set -e; for i in $(DIRS); do \
* ADDRESS_REWRITING_README: Address rewriting
* VIRTUAL_README: Virtual domain hosting
* SASL_README: SASL Authentication
+ * IPV6_README: IP Version 6 Support
* INSTALL: Installation from source code
P\bPr\bro\bob\bbl\ble\bem\bm s\bso\bol\blv\bvi\bin\bng\bg
# (yes) (yes) (yes) (never) (100)
# =================================================================
1.2.3.5:smtp inet n - n - - smtpd
- -o content_filter=foo:bar
+ -o content_filter=filter-service:filter-destination
-o receive_override_options=no_address_mappings
After this, you can follow the same procedure as outlined in the "advanced" or
# service type private unpriv chroot wakeup maxproc command
# (yes) (yes) (yes) (never) (100)
# =================================================================
- # SMTP service for domains that are content filtered with foo:bar
+ # SMTP service for domains that are filtered with service1:dest1
1.2.3.4:smtp inet n - n - - smtpd
- -o content_filter=foo:bar
+ -o content_filter=service1:dest1
-o receive_override_options=no_address_mappings
- # SMTP service for domains that are content filtered with xxx:yyy
+ # SMTP service for domains that are filtered with service2:dest2
1.2.3.5:smtp inet n - n - - smtpd
- -o content_filter=xxx:yyy
+ -o content_filter=service2:dest2
-o receive_override_options=no_address_mappings
After this, you can follow the same procedure as outlined in the "advanced" or
--- /dev/null
+P\bPo\bos\bst\btf\bfi\bix\bx I\bIP\bPv\bv6\b6 S\bSu\bup\bpp\bpo\bor\brt\bt
+
+-------------------------------------------------------------------------------
+
+I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
+
+Postfix 2.2 introduces support for the IPv6 (IP version 6) protocol, whose main
+feature of interest is that it uses 128-bit IP addresses instead of the 32-bit
+addresses used by IPv4.
+
+With this, Postfix can use the same SMTP protocol over IPv6 as it already uses
+over the older IPv4 network, and Postfix can do AAAA record lookups in the DNS
+in addition to the older A records. Information about IPv6 can be found at
+http://www.ipv6.org/.
+
+This document provides information on the following topics:
+
+ * Supported platforms
+ * Configuration
+ * Known limitations
+ * Compatibility with Postfix <2.2 IPv6 support
+ * IPv6 Support for unsupported platforms
+ * Credits
+
+S\bSu\bup\bpp\bpo\bor\brt\bte\bed\bd P\bPl\bla\bat\btf\bfo\bor\brm\bms\bs
+
+Postfix version 2.2 supports IPv4 and IPv6 on the following platforms:
+
+ * AIX 5.1+
+ * Darwin 7.3+
+ * FreeBSD 4+
+ * Linux 2.4+
+ * NetBSD 1.5+
+ * OpenBSD 2+
+ * Solaris 8+
+ * Tru64Unix V5.1+
+
+On other platforms Postfix will simply use IPv4 as it has always done.
+
+See below for tips how to port Postfix IPv6 support to other environments.
+
+C\bCo\bon\bnf\bfi\big\bgu\bur\bra\bat\bti\bio\bon\bn
+
+Postfix IPv6 support introduces two new main.cf configuration parameters, and
+introduces an important change in address syntax notation in match lists such
+as mynetworks or debug_peer_list.
+
+Postfix IPv6 address syntax is a little tricky, because there are a few places
+where you must enclose IPv6 address inside [] characters, and a few places
+where you must not. It is a good idea to use [] only in the few places where
+you have to. Check out the postconf(5) manual whenever you do IPv6 related
+configuration work with Postfix.
+
+ * The new inet_protocols parameter specifies what IP protocols Postfix will
+ use. This parameter also controls what DNS lookups Postfix will do.
+
+ /etc/postfix/main.cf:
+ # You must stop/start Postfix after changing this parameter.
+ inet_protocols = ipv4 (DEFAULT: enable IPv4 only)
+ inet_protocols = all (enable both IPv4 and IPv6)
+ inet_protocols = ipv4, ipv6 (enable both IPv4 and IPv6)
+ inet_protocols = ipv6 (enable IPv6 only)
+
+ By default, Postfix uses IPv4 only, because most systems aren't attached to
+ an IPv6 network.
+
+ o On systems with combined IPv4/IPv6 stacks, attempts to deliver mail via
+ IPv6 would always fail with "network unreachable", and those attempts
+ would only slow down Postfix.
+
+ o Linux kernels don't even load IPv6 protocol support by default. Any
+ attempt to use it would fail immediately.
+
+ Note 1: you must stop and start Postfix after changing the inet_protocols
+ configuration parameter.
+
+ Note 2: if you see error messages like the following, then you're running
+ Linux and need to turn on IPv6 in the kernel: see http://www.ipv6.org/ for
+ hints and tips. Unlike other systems, Linux does not have a combined stack
+ for IPv4 and IPv6, and IPv6 protocol support is not loaded by default.
+
+ postconf: warning: inet_protocols: IPv6 support is disabled: Address
+ family not supported by protocol
+ postconf: warning: inet_protocols: configuring for IPv4 support only
+
+ Note 3: on older Linux and Solaris systems, the setting "inet_protocols =
+ ipv6" will not prevent Postfix from accepting IPv4 connections. Postfix
+ will present the client IP addresses in IPv6 format, though. In all other
+ cases, Postfix always presents IPv4 client IP addresses in the traditional
+ dotted quad IPv4 format.
+
+ * The other new parameter is smtp_bind_address6. This sets the local
+ interface address for outgoing IPv6 SMTP connections, just like the
+ smtp_bind_address parameter does for IPv4:
+
+ /etc/postfix/main.cf:
+ smtp_bind_address6 = 2001:240:5c7:0:250:56ff:fe89:1
+
+ * If you left the value of the mynetworks parameter at its default (i.e. no
+ mynetworks setting in main.cf) Postfix will figure out by itself what its
+ network addresses are. This is what a typical setting looks like:
+
+ % postconf mynetworks
+ mynetworks = 127.0.0.0/8 168.100.189.0/28 [::1]/128 [fe80::]/10 [2001:
+ 240:5c7::]/64
+
+ If you did specify the mynetworks parameter value in main.cf, you need
+ update the mynetworks value to include the IPv6 networks the system is in.
+ Be sure to specify IPv6 address information inside [], like this:
+
+ /etc/postfix/main.cf:
+ mynetworks = ...IPv4 networks... [::1]/128 [2001:240:5c7::]/64 ...
+
+N\bNO\bOT\bTE\bE:\b: w\bwh\bhe\ben\bn c\bco\bon\bnf\bfi\big\bgu\bur\bri\bin\bng\bg P\bPo\bos\bst\btf\bfi\bix\bx m\bma\bat\btc\bch\bh l\bli\bis\bst\bts\bs s\bsu\buc\bch\bh a\bas\bs m\bmy\byn\bne\bet\btw\bwo\bor\brk\bks\bs o\bor\br
+d\bde\beb\bbu\bug\bg_\b_p\bpe\bee\ber\br_\b_l\bli\bis\bst\bt,\b, y\byo\bou\bu m\bmu\bus\bst\bt s\bsp\bpe\bec\bci\bif\bfy\by I\bIP\bPv\bv6\b6 a\bad\bdd\bdr\bre\bes\bss\bs i\bin\bnf\bfo\bor\brm\bma\bat\bti\bio\bon\bn i\bin\bns\bsi\bid\bde\be [\b[]\b] i\bin\bn t\bth\bhe\be
+m\bma\bai\bin\bn.\b.c\bcf\bf p\bpa\bar\bra\bam\bme\bet\bte\ber\br v\bva\bal\blu\bue\be a\ban\bnd\bd i\bin\bn f\bfi\bil\ble\bes\bs s\bsp\bpe\bec\bci\bif\bfi\bie\bed\bd w\bwi\bit\bth\bh a\ba "\b"/\b/f\bfi\bil\ble\be/\b/n\bna\bam\bme\be"\b" p\bpa\bat\btt\bte\ber\brn\bn.\b.
+I\bIP\bPv\bv6\b6 a\bad\bdd\bdr\bre\bes\bss\bse\bes\bs c\bco\bon\bnt\bta\bai\bin\bn t\bth\bhe\be "\b":\b:"\b" c\bch\bha\bar\bra\bac\bct\bte\ber\br,\b, a\ban\bnd\bd w\bwo\bou\bul\bld\bd o\bot\bth\bhe\ber\brw\bwi\bis\bse\be b\bbe\be c\bco\bon\bnf\bfu\bus\bse\bed\bd w\bwi\bit\bth\bh
+a\ba "\b"t\bty\byp\bpe\be:\b:t\bta\bab\bbl\ble\be"\b" p\bpa\bat\btt\bte\ber\brn\bn.\b.
+
+K\bKn\bno\bow\bwn\bn L\bLi\bim\bmi\bit\bta\bat\bti\bio\bon\bns\bs
+
+ * The order of IPv6/IPv4 outgoing connection attempts is not yet
+ configurable. Currently, IPv6 is tried before IPv4.
+
+ * Postfix currently does not support DNSBL (real-time blackhole list) lookups
+ for IPv6 client IP addresses; currently there are no blacklists that cover
+ the IPv6 address space.
+
+ * IPv6 does not have class A, B, C, etc. networks. With IPv6 networks, the
+ setting "mynetworks_style = class" has the same effect as the setting
+ "mynetworks_style = subnet".
+
+ * On Tru64Unix, Postfix can't figure out the local subnet mask and always
+ assumes a /128 network. This is a problem only with "mynetworks_style =
+ subnet" and no explicit mynetworks setting in main.cf.
+
+C\bCo\bom\bmp\bpa\bat\bti\bib\bbi\bil\bli\bit\bty\by w\bwi\bit\bth\bh P\bPo\bos\bst\btf\bfi\bix\bx <\b<2\b2.\b.2\b2 I\bIP\bPv\bv6\b6 s\bsu\bup\bpp\bpo\bor\brt\bt
+
+Postfix version 2.2 IPv6 support is based on the Postfix/IPv6 patch by Dean
+Strik and others, but differs in a few minor ways.
+
+ * main.cf: The inet_interfaces parameter does not support the notation "ipv6:
+ all" or "ipv4:all". Use the inet_protocols parameter instead.
+
+ * main.cf: Specify "inet_protocols = all" or "inet_protocols = ipv4, ipv6" in
+ order to enable both IPv4 and IPv6 support.
+
+ * main.cf: The inet_protocols parameter also controls what DNS lookups
+ Postfix will attempt to make when delivering or receiving mail.
+
+ * main.cf: Specify "inet_interfaces = loopback-only" to listen on loopback
+ network interfaces only.
+
+ * The lmtp_bind_address and lmtp_bind_address6 features were omitted. The
+ Postfix LMTP client will be absorbed into the SMTP client, so there is no
+ reason to keep adding features to the LMTP client.
+
+ * The SMTP server now requires that IPv6 addresses in SMTP commands are
+ specified as [ipv6:ipv6address], as described in RFC 2821.
+
+ * The IPv6 network address matching code was rewritten from the ground up,
+ and is expected to be closer to the specification. The result may be
+ incompatible with the Postfix/IPv6 patch.
+
+I\bIP\bPv\bv6\b6 S\bSu\bup\bpp\bpo\bor\brt\bt f\bfo\bor\br u\bun\bns\bsu\bup\bpp\bpo\bor\brt\bte\bed\bd p\bpl\bla\bat\btf\bfo\bor\brm\bms\bs
+
+Getting Postfix IPv6 working on other platforms involves the following steps:
+
+ * Specify how Postfix should find the local network interfaces. Postfix needs
+ this information to avoid mailer loops and to find out if mail for user@
+ [ipaddress] is a local or remote destination.
+
+ If your system has the getifaddrs() routine then add the following to your
+ platform-specific section in src/util/sys_defs.h:
+
+ #ifndef NO_IPV6
+ # define HAS_IPV6
+ # define HAVE_GETIFADDRS
+ #endif
+
+ Otherwise, if your system has the SIOCGLIF ioctl() command in /usr/include/
+ */*.h, add the following to your platform-specific section in src/util/
+ sys_defs.h:
+
+ #ifndef NO_IPV6
+ # define HAS_IPV6
+ # define HAS_SIOCGLIF
+ #endif
+
+ Otherwise, Postfix will have to use the old SIOCGIF commands and get along
+ with reduced IPv6 functionality (it won't be able to figure out your IPv6
+ netmasks, which are needed for "mynetworks_style = subnet". Add this to
+ your platform-specific section in src/util/sys_defs.h:
+
+ #ifndef NO_IPV6
+ # define HAS_IPV6
+ #endif
+
+ * Test if Postfix can figure out its interface information.
+
+ After compiling Postfix in the usual manner, step into the src/util
+ directory and type "make inet_addr_local". Running this file by hand should
+ produce all the interface addresses and network masks, for example:
+
+ % make
+ % cd src/util
+ % make inet_addr_local
+ [... some messages ...]
+ % ./inet_addr_local
+ [... some messages ...]
+ ./inet_addr_local: inet_addr_local: configured 2 IPv4 addresses
+ ./inet_addr_local: inet_addr_local: configured 4 IPv6 addresses
+ 168.100.189.2/255.255.255.224
+ 127.0.0.1/255.0.0.0
+ fe80:1::2d0:b7ff:fe88:2ca7/ffff:ffff:ffff:ffff::
+ 2001:240:5c7:0:2d0:b7ff:fe88:2ca7/ffff:ffff:ffff:ffff::
+ fe80:5::1/ffff:ffff:ffff:ffff::
+ ::1/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+
+ The above is for an old FreeBSD machine. Other systems produce slightly
+ different results, but you get the idea.
+
+If none of all this produces a usable result, send email to the postfix-
+users@postfix.org mailing list and we'll try to help you through this.
+
+C\bCr\bre\bed\bdi\bit\bts\bs
+
+The following information is in part based on information that was compiled by
+Dean Strik.
+
+ * Mark Huizer wrote the original Postfix IPv6 patch.
+
+ * Jun-ichiro 'itojun' Hagino of the KAME project made substantial
+ improvements. Since then, we speak of the KAME patch.
+
+ * The PLD Linux Distribution ported the code to other stacks (notably USAGI).
+ We speak of the PLD patch. A very important feature of the PLD patch was
+ that it can work with Lutz Jaenicke's TLS patch for Postfix.
+
+ * Dean Strik extended IPv6 support to platforms other than KAME and USAGI,
+ updated the patch to keep up with Postfix development, and provided a
+ combined IPv6 + TLS patch. Information about his effort can be found on
+ Dean Strik's Postfix website at http://www.ipnet6.org/postfix/.
+
+ * Wietse Venema took Dean Strik's IPv6 patch, merged it into Postfix 2.2, and
+ took the opportunity to eliminate all IPv4-specific code from Postfix that
+ could be removed. For systems without IPv6 support in the kernel and system
+ libraries, Postfix has a simple compatibility layer, so that it will use
+ IPv4 as before.
+
* When an attribute value is unavailable, the client either does not send the
attribute, or sends the attribute with an empty value ("name=").
+ * The client address is an IPv4 dotted quad in the form 1.2.3.4 or it is an
+ IPv6 address in the form 1:2:3::4:5:6.
+
* An attribute name must not contain "=", null or newline, and an attribute
value must not contain null or newline.
and change the patchlevel and the release date. Patches are never
issued for snapshot releases.
+Incompatible changes with snapshot Postfix-2.2-20050117
+=======================================================
+
+Only the deferred and defer queue directories are hashed by default,
+instead of eight queue directories. With modern file systems, this
+speeds up Postfix boot time without compromising performance under
+high load too much. Hashing is now turned on only for the defer and
+deferred queue directories, because those contain lots of mail when
+undeliverable mail is backing up.
+
+In order to speed up start-up, some Postfix file permission checks
+are run in the background after Postfix is started.
+
+The SMTP server now requires that IPv6 addresses in SMTP commands
+are specified as [ipv6:ipv6address], as described in RFC 2821.
+
+Incompatible changes with snapshot Postfix-2.2-20050111+IPV6
+============================================================
+
+Postfix version 2.2 IP version 6 support is based on the Postfix/IPv6
+patch by Dean Strik, but differs in a few minor ways.
+
+- Network protocol support including DNS lookup is selected with
+the inet_protocols parameter instead of the inet_interfaces parameter.
+This is needed so that Postfix will not attempt to deliver mail
+via IPv6 when the system has no IPv6 connectivity.
+
+- The lmtp_bind_address6 feature was omitted. The Postfix LMTP
+client will be absorbed into the SMTP client, so there is no reason
+to keep adding features to the LMTP client.
+
+- The cidr-based address matching code was rewritten. The new
+behavior is believed to be closer to expectation. The results may
+be incompatible with that of the Postfix/IPv6 patch.
+
+Major changes with snapshot Postfix-2.2-20050111+IPV6
+=====================================================
+
+Postfix version 2.2 IP version 6 support based on the Postfix/IPv6
+patch by Dean Strik and others. IP version 6 support is selected
+in main.cf; it is not selected at compile time as with TLS or SASL.
+
+IP version 6 support is always compiled into Postfix on systems
+that have Postfix compatible IP version 6 support. On other systems
+Postfix will simply use IP version 4 just like it did before. See
+the IPV6_README document for what systems are supported, and how
+to turn on IPv6 in main.cf.
+
Major changes with snapshot Postfix-2.2-20041218
================================================
# The optional access table directs the Postfix SMTP server
# to selectively reject or accept mail. Access can be
# allowed or denied for specific host names, domain names,
-# networks, host network addresses or mail addresses.
+# networks, host addresses or mail addresses.
#
# For an example, see the EXAMPLE section at the end of this
# manual page.
#
# net.work
#
-# net Matches any host address in the specified network.
-# A network address is a sequence of one or more
-# octets separated by ".".
+# net Matches the specified IPv4 host address or subnet-
+# work. An IPv4 host address is a sequence of four
+# decimal octets separated by ".".
#
-# NOTE: use the cidr lookup table type to specify
+# Subnetworks are matched by repeatedly truncating
+# the last ".octet" from the remote IPv4 host address
+# string until a match is found in the access table,
+# or until further truncation is not possible.
+#
+# NOTE 1: The information in the access map should be
+# in canonical form, with unnecessary null characters
+# eliminated. Address information must not be
+# enclosed with "[]" characters.
+#
+# NOTE 2: use the cidr lookup table type to specify
# network/netmask patterns. See cidr_table(5) for
# details.
#
+# net:work:addr:ess
+#
+# net:work:addr
+#
+# net:work
+#
+# net Matches the specified IPv6 host address or subnet-
+# work. An IPv6 host address is a sequence of three
+# to eight hexadecimal octet pairs separated by ":".
+#
+# Subnetworks are matched by repeatedly truncating
+# the last ":octetpair" from the remote IPv6 host
+# address string until a match is found in the access
+# table, or until further truncation is not possible.
+#
+# NOTE 1: the truncation and comparison are done with
+# the string representation of the IPv6 host address.
+# Thus, not all the ":" subnetworks will be tried.
+#
+# NOTE 2: The information in the access map should be
+# in canonical form, with unnecessary null characters
+# eliminated. Address information must not be
+# enclosed with "[]" characters.
+#
+# NOTE 3: use the cidr lookup table type to specify
+# network/netmask patterns. See cidr_table(5) for
+# details.
+#
+# IPv6 support is available in Postfix 2.2 and later.
+#
# ACCEPT ACTIONS
# OK Accept the address etc. that matches the pattern.
#
# all-numerical
# An all-numerical result is treated as OK. This for-
-# mat is generated by address-based relay authoriza-
+# mat is generated by address-based relay authoriza-
# tion schemes.
#
# REJECT ACTIONS
# 4NN text
#
# 5NN text
-# Reject the address etc. that matches the pattern,
+# Reject the address etc. that matches the pattern,
# and respond with the numerical three-digit code and
-# text. 4NN means "try again later", while 5NN means
+# text. 4NN means "try again later", while 5NN means
# "do not try again".
#
# REJECT optional text...
-# Reject the address etc. that matches the pattern.
-# Reply with $reject_code optional text... when the
-# optional text is specified, otherwise reply with a
+# Reject the address etc. that matches the pattern.
+# Reply with $reject_code optional text... when the
+# optional text is specified, otherwise reply with a
# generic error response message.
#
# DEFER_IF_REJECT optional text...
-# Defer the request if some later restriction would
+# Defer the request if some later restriction would
# result in a REJECT action. Reply with "450 optional
# text... when the optional text is specified, other-
# wise reply with a generic error response message.
# This feature is available in Postfix 2.1 and later.
#
# DEFER_IF_PERMIT optional text...
-# Defer the request if some later restriction would
-# result in a an explicit or implicit PERMIT action.
-# Reply with "450 optional text... when the optional
-# text is specified, otherwise reply with a generic
+# Defer the request if some later restriction would
+# result in a an explicit or implicit PERMIT action.
+# Reply with "450 optional text... when the optional
+# text is specified, otherwise reply with a generic
# error response message.
#
# This feature is available in Postfix 2.1 and later.
# reject_unauth_destination, and so on).
#
# DISCARD optional text...
-# Claim successful delivery and silently discard the
-# message. Log the optional text if specified, oth-
+# Claim successful delivery and silently discard the
+# message. Log the optional text if specified, oth-
# erwise log a generic message.
#
-# Note: this action currently affects all recipients
+# Note: this action currently affects all recipients
# of the message.
#
# This feature is available in Postfix 2.0 and later.
#
-# DUNNO Pretend that the lookup key was not found. This
-# prevents Postfix from trying substrings of the
-# lookup key (such as a subdomain name, or a network
+# DUNNO Pretend that the lookup key was not found. This
+# prevents Postfix from trying substrings of the
+# lookup key (such as a subdomain name, or a network
# address subnetwork).
#
# This feature is available in Postfix 2.0 and later.
#
# FILTER transport:destination
-# After the message is queued, send the entire mes-
+# After the message is queued, send the entire mes-
# sage through the specified external content filter.
-# The transport:destination syntax is described in
-# the transport(5) manual page. More information
-# about external content filters is in the Postfix
+# The transport:destination syntax is described in
+# the transport(5) manual page. More information
+# about external content filters is in the Postfix
# FILTER_README file.
#
-# Note: this action overrides the main.cf con-
+# Note: this action overrides the main.cf con-
# tent_filter setting, and currently affects all
# recipients of the message.
#
# This feature is available in Postfix 2.0 and later.
#
# HOLD optional text...
-# Place the message on the hold queue, where it will
-# sit until someone either deletes it or releases it
-# for delivery. Log the optional text if specified,
+# Place the message on the hold queue, where it will
+# sit until someone either deletes it or releases it
+# for delivery. Log the optional text if specified,
# otherwise log a generic message.
#
-# Mail that is placed on hold can be examined with
-# the postcat(1) command, and can be destroyed or
+# Mail that is placed on hold can be examined with
+# the postcat(1) command, and can be destroyed or
# released with the postsuper(1) command.
#
-# Note: use "postsuper -r" to release mail that was
-# kept on hold for a significant fraction of $maxi-
+# Note: use "postsuper -r" to release mail that was
+# kept on hold for a significant fraction of $maxi-
# mal_queue_lifetime or $bounce_queue_lifetime, or
# longer.
#
-# Note: this action currently affects all recipients
+# Note: this action currently affects all recipients
# of the message.
#
# This feature is available in Postfix 2.0 and later.
#
# PREPEND headername: headervalue
-# Prepend the specified message header to the mes-
+# Prepend the specified message header to the mes-
# sage. When this action is used multiple times, the
-# first prepended header appears before the second
+# first prepended header appears before the second
# etc. prepended header.
#
-# Note: this action does not support multi-line mes-
+# Note: this action does not support multi-line mes-
# sage headers.
#
# This feature is available in Postfix 2.1 and later.
#
# REDIRECT user@domain
-# After the message is queued, send the message to
+# After the message is queued, send the message to
# the specified address instead of the intended
# recipient(s).
#
-# Note: this action overrides the FILTER action, and
+# Note: this action overrides the FILTER action, and
# currently affects all recipients of the message.
#
# This feature is available in Postfix 2.1 and later.
#
# WARN optional text...
# Log a warning with the optional text, together with
-# client information and if available, with helo,
+# client information and if available, with helo,
# sender, recipient and protocol information.
#
# This feature is available in Postfix 2.1 and later.
#
# REGULAR EXPRESSION TABLES
-# This section describes how the table lookups change when
+# This section describes how the table lookups change when
# the table is given in the form of regular expressions. For
-# a description of regular expression lookup table syntax,
+# a description of regular expression lookup table syntax,
# see regexp_table(5) or pcre_table(5).
#
-# Each pattern is a regular expression that is applied to
+# Each pattern is a regular expression that is applied to
# the entire string being looked up. Depending on the appli-
-# cation, that string is an entire client hostname, an
+# cation, that string is an entire client hostname, an
# entire client IP address, or an entire mail address. Thus,
# no parent domain or parent network search is done,
-# user@domain mail addresses are not broken up into their
+# user@domain mail addresses are not broken up into their
# user@ and domain constituent parts, nor is user+foo broken
# up into user and foo.
#
-# Patterns are applied in the order as specified in the
-# table, until a pattern is found that matches the search
+# Patterns are applied in the order as specified in the
+# table, until a pattern is found that matches the search
# string.
#
-# Actions are the same as with indexed file lookups, with
-# the additional feature that parenthesized substrings from
+# Actions are the same as with indexed file lookups, with
+# the additional feature that parenthesized substrings from
# the pattern can be interpolated as $1, $2 and so on.
#
# TCP-BASED TABLES
-# This section describes how the table lookups change when
+# This section describes how the table lookups change when
# lookups are directed to a TCP-based server. For a descrip-
-# tion of the TCP client/server lookup protocol, see
-# tcp_table(5). This feature is not available in Postfix
+# tion of the TCP client/server lookup protocol, see
+# tcp_table(5). This feature is not available in Postfix
# version 2.1.
#
-# Each lookup operation uses the entire query string once.
-# Depending on the application, that string is an entire
+# Each lookup operation uses the entire query string once.
+# Depending on the application, that string is an entire
# client hostname, an entire client IP address, or an entire
-# mail address. Thus, no parent domain or parent network
-# search is done, user@domain mail addresses are not broken
-# up into their user@ and domain constituent parts, nor is
+# mail address. Thus, no parent domain or parent network
+# search is done, user@domain mail addresses are not broken
+# up into their user@ and domain constituent parts, nor is
# user+foo broken up into user and foo.
#
# Actions are the same as with indexed file lookups.
#
# EXAMPLE
-# The following example uses an indexed file, so that the
-# order of table entries does not matter. The example per-
-# mits access by the client at address 1.2.3.4 but rejects
-# all other clients in 1.2.3.0/24. Instead of hash lookup
-# tables, some systems use dbm. Use the command "postconf
-# -m" to find out what lookup tables Postfix supports on
+# The following example uses an indexed file, so that the
+# order of table entries does not matter. The example per-
+# mits access by the client at address 1.2.3.4 but rejects
+# all other clients in 1.2.3.0/24. Instead of hash lookup
+# tables, some systems use dbm. Use the command "postconf
+# -m" to find out what lookup tables Postfix supports on
# your system.
#
# /etc/postfix/main.cf:
# editing the file.
#
# BUGS
-# The table format does not understand quoting conventions.
+# The table format does not understand quoting conventions.
#
# SEE ALSO
# postmap(1), Postfix lookup table manager
# transport(5), transport:nexthop syntax
#
# README FILES
-# Use "postconf readme_directory" or "postconf html_direc-
+# Use "postconf readme_directory" or "postconf html_direc-
# tory" to locate this information.
# SMTPD_ACCESS_README, built-in SMTP server access control
# DATABASE_README, Postfix lookup table overview
#
# LICENSE
-# The Secure Mailer license must be distributed with this
+# The Secure Mailer license must be distributed with this
# software.
#
# AUTHOR(S)
}
done
- # With 20000 active queue files, the active queue directory should
- # be hashed, and so should the other directories, because they
- # can contain even more mail.
- #
- # Unfortunately, this sucks mailq performance on unloaded systems.
- #
- # If you don't want slow mailq, be sure to hash defer and deferred,
- # because those two directories can contain lots of files.
+ # File systems have improved since Postfix came out, and all we
+ # require now is that defer and deferred are hashed because those
+ # can contain lots of files.
found=`$POSTCONF -c $config_directory -h hash_queue_names`
missing=
- (echo "$found" | grep active >/dev/null) || missing="$missing active"
- (echo "$found" | grep bounce >/dev/null) || missing="$missing bounce"
(echo "$found" | grep defer >/dev/null) || missing="$missing defer"
- (echo "$found" | grep flush >/dev/null) || missing="$missing flush"
- (echo "$found" | grep incoming>/dev/null)|| missing="$missing incoming"
(echo "$found" | grep deferred>/dev/null)|| missing="$missing deferred"
test -n "$missing" && {
echo fixing main.cf hash_queue_names for missing $missing
$sample_directory/sample-debug.cf:f:root:-:644:o
$sample_directory/sample-filter.cf:f:root:-:644:o:o
$sample_directory/sample-flush.cf:f:root:-:644:o
+$sample_directory/sample-ipv6.cf:f:root:-:644:o
$sample_directory/sample-ldap.cf:f:root:-:644:o
$sample_directory/sample-lmtp.cf:f:root:-:644:o
$sample_directory/sample-local.cf:f:root:-:644:o
$readme_directory/FILTER_README:f:root:-:644
$readme_directory/HOSTING_README:f:root:-:644:o
$readme_directory/INSTALL:f:root:-:644
+$readme_directory/IPV6_README:f:root:-:644
$readme_directory/LDAP_README:f:root:-:644
$readme_directory/LINUX_README:f:root:-:644
$readme_directory/LMTP_README:f:root:-:644
$html_directory/ETRN_README.html:f:root:-:644
$html_directory/FILTER_README.html:f:root:-:644
$html_directory/INSTALL.html:f:root:-:644
+$html_directory/IPV6_README.html:f:root:-:644
$html_directory/LDAP_README.html:f:root:-:644
$html_directory/LINUX_README.html:f:root:-:644
$html_directory/LMTP_README.html:f:root:-:644
$FATAL the Postfix mail system is already running
exit 1
}
- $config_directory/postfix-script check || {
- $FATAL Postfix integrity check failed!
- exit 1
- }
+ if [ -f $queue_directory/quick-start ]
+ then
+ rm -f $queue_directory/quick-start
+ else
+ $config_directory/postfix-script check-fatal || {
+ $FATAL Postfix integrity check failed!
+ exit 1
+ }
+ # Warning checks proceed in the background.
+ $INFO starting background file permission checks in 60 seconds
+ (sleep 60; $config_directory/postfix-script check-warn) &
+ fi
$INFO starting the Postfix mail system
$daemon_directory/master &
;;
kill -9 `sed 1q pid/master.pid`
;;
+quick-stop)
+
+ $config_directory/postfix-script stop
+ touch $queue_directory/quick-start
+ ;;
+
stop)
$daemon_directory/master -t 2>/dev/null && {
check)
+ $config_directory/postfix-script check-fatal || exit 1
+ $config_directory/postfix-script check-warn
+ exit 0
+ ;;
+
+check-fatal)
+ # This command is NOT part of the public interface.
+
+ $SHELL $config_directory/post-install create-missing || {
+ $WARN unable to create missing queue directories
+ exit 1
+ }
+
+ # Look for incomplete installations.
+
+ test -f $config_directory/master.cf || {
+ $FATAL no $config_directory/master.cf file found
+ exit 1
+ }
+
+ # See if all queue files are in the right place. This is slow.
+ # We must scan all queues for mis-named queue files before the
+ # mail system can run.
+
+ $command_directory/postsuper || exit 1
+ exit 0
+ ;;
+
+check-warn)
+ # This command is NOT part of the public interface.
+
for dir in $daemon_directory $config_directory $queue_directory
do
ls -lLd $dir | (grep " root " >/dev/null ||
\( -perm -020 -o -perm -002 \) -type f \
-exec $WARN group or other writable: {} \;
- $SHELL $config_directory/post-install create-missing || {
- $WARN unable to create missing queue directories
- exit 1
- }
-
find `ls -d $queue_directory/* | \
egrep '/(incoming|active|defer|deferred|bounce|hold|trace|corrupt|public|private|flush)$'` \
! \( -type p -o -type s \) ! -user $mail_owner \
done
done
- # Look for incomplete installations.
-
- test -f $config_directory/master.cf || {
- $FATAL no $config_directory/master.cf file found
- exit 1
- }
-
- # See if all queue files are in the right place. This is slow.
- # We must scan all queues for mis-named queue files before the
- # mail system can run.
-
- $command_directory/postsuper || exit 1
-
find corrupt -type f -exec $WARN damaged message: {} \;
# XXX also: look for weird stuff, weird permissions, etc.
# (yes) (yes) (yes) (never) (100)
# =================================================================
1.2.3.5:smtp inet n - n - - smtpd
- -o <a href="postconf.5.html#content_filter">content_filter</a>=foo:bar
+ -o <a href="postconf.5.html#content_filter">content_filter</a>=filter-service:filter-destination
-o <a href="postconf.5.html#receive_override_options">receive_override_options</a>=<a href="postconf.5.html#no_address_mappings">no_address_mappings</a>
</pre>
# service type private unpriv chroot wakeup maxproc command
# (yes) (yes) (yes) (never) (100)
# =================================================================
- # SMTP service for domains that are content filtered with foo:bar
+ # SMTP service for domains that are filtered with service1:dest1
1.2.3.4:smtp inet n - n - - smtpd
- -o <a href="postconf.5.html#content_filter">content_filter</a>=foo:bar
+ -o <a href="postconf.5.html#content_filter">content_filter</a>=service1:dest1
-o <a href="postconf.5.html#receive_override_options">receive_override_options</a>=<a href="postconf.5.html#no_address_mappings">no_address_mappings</a>
- # SMTP service for domains that are content filtered with xxx:yyy
+ # SMTP service for domains that are filtered with service2:dest2
1.2.3.5:smtp inet n - n - - smtpd
- -o <a href="postconf.5.html#content_filter">content_filter</a>=xxx:yyy
+ -o <a href="postconf.5.html#content_filter">content_filter</a>=service2:dest2
-o <a href="postconf.5.html#receive_override_options">receive_override_options</a>=<a href="postconf.5.html#no_address_mappings">no_address_mappings</a>
</pre>
</blockquote>
--- /dev/null
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+<head>
+
+<title>Postfix IPv6 Support</title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix
+IPv6 Support</h1>
+
+<hr>
+
+<h2>Introduction</h2>
+
+<p> Postfix 2.2 introduces support for the IPv6 (IP version 6)
+protocol, whose main feature of interest is that it uses 128-bit
+IP addresses instead of the 32-bit addresses used by IPv4. </p>
+
+<p> With this, Postfix can use the same SMTP protocol over IPv6 as
+it already uses over the older IPv4 network, and Postfix can do
+AAAA record lookups in the DNS in addition to the older A records.
+Information about IPv6 can be found at <a href="http://www.ipv6.org/">http://www.ipv6.org/</a>. </p>
+
+<p> This document provides information on the following topics:
+</p>
+
+<ul>
+
+<li><a href="#platforms">Supported platforms</a>
+
+<li><a href="#configuration">Configuration</a>
+
+<li><a href="#limitations">Known limitations</a>
+
+<li><a href="#compat">Compatibility with Postfix <2.2 IPv6 support</a>
+
+<li><a href="#porting">IPv6 Support for unsupported platforms</a>
+
+<li><a href="#credits">Credits</a>
+
+</ul>
+
+<h2><a name="platforms">Supported Platforms</a></h2>
+
+<p> Postfix version 2.2 supports IPv4 and IPv6 on the following
+platforms: </p>
+
+<ul>
+
+<li> AIX 5.1+
+<li> Darwin 7.3+
+<li> FreeBSD 4+
+<li> Linux 2.4+
+<li> NetBSD 1.5+
+<li> OpenBSD 2+
+<li> Solaris 8+
+<li> Tru64Unix V5.1+
+
+</ul>
+
+<p> On other platforms Postfix will simply use IPv4 as it has always
+done. </p>
+
+<p> See <a href="#porting">below</a> for tips how to port Postfix
+IPv6 support to other environments. </p>
+
+<h2><a name="configuration">Configuration</a></h2>
+
+<p> Postfix IPv6 support introduces two new main.cf configuration
+parameters, and introduces an important change in address syntax
+notation in match lists such as <tt><a href="postconf.5.html#mynetworks">mynetworks</a></tt> or
+<tt><a href="postconf.5.html#debug_peer_list">debug_peer_list</a></tt>. </p>
+
+<p> Postfix IPv6 address syntax is a little tricky, because there
+are a few places where you must enclose IPv6 address inside
+<tt>[]</tt> characters, and a few places where you must not. It is
+a good idea to use <tt>[]</tt> only in the few places where you
+have to. Check out the <a href="postconf.5.html">postconf(5)</a> manual whenever you do IPv6
+related configuration work with Postfix. </p>
+
+<ul>
+
+<li> <p> The new <tt><a href="postconf.5.html#inet_protocols">inet_protocols</a></tt> parameter specifies what
+IP protocols Postfix will use. This parameter also controls what
+DNS lookups Postfix will do. </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ # You must stop/start Postfix after changing this parameter.
+ <a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv4 (DEFAULT: enable IPv4 only)
+ <a href="postconf.5.html#inet_protocols">inet_protocols</a> = all (enable both IPv4 and IPv6)
+ <a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv4, ipv6 (enable both IPv4 and IPv6)
+ <a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv6 (enable IPv6 only)
+</pre>
+</blockquote>
+
+<p> By default, Postfix uses IPv4 only, because most systems aren't
+attached to an IPv6 network. </p>
+
+<ul>
+
+<li> <p> On systems with combined IPv4/IPv6 stacks, attempts to
+deliver mail via IPv6 would always fail with "network unreachable",
+and those attempts would only slow down Postfix. </p>
+
+<li> <p> Linux kernels don't even load IPv6 protocol support by
+default. Any attempt to use it would fail immediately. </p>
+
+</ul>
+
+<p> Note 1: you must stop and start Postfix after changing the
+<tt><a href="postconf.5.html#inet_protocols">inet_protocols</a></tt> configuration parameter. </p>
+
+<p> Note 2: if you see error messages like the following, then
+you're running Linux and need to turn on IPv6 in the kernel: see
+<a href="http://www.ipv6.org/">http://www.ipv6.org/</a> for hints and tips. Unlike other systems,
+Linux does not have a combined stack for IPv4 and IPv6, and IPv6
+protocol support is not loaded by default. </p>
+
+<blockquote>
+<pre>
+postconf: warning: <a href="postconf.5.html#inet_protocols">inet_protocols</a>: IPv6 support is disabled: Address family not supported by protocol
+postconf: warning: <a href="postconf.5.html#inet_protocols">inet_protocols</a>: configuring for IPv4 support only
+</pre>
+</blockquote>
+
+<p> Note 3: on older Linux and Solaris systems, the setting
+"<tt><a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv6</tt>" will not prevent Postfix from
+accepting IPv4 connections. Postfix will present the client IP
+addresses in IPv6 format, though. In all other cases, Postfix always
+presents IPv4 client IP addresses in the traditional dotted quad
+IPv4 format. </p>
+
+<li> <p> The other new parameter is <tt><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a></tt>.
+This sets the local interface address for outgoing IPv6 SMTP
+connections, just like the <tt><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a></tt> parameter
+does for IPv4: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> = 2001:240:5c7:0:250:56ff:fe89:1
+</pre>
+</blockquote>
+
+<li> <p> If you left the value of the <tt><a href="postconf.5.html#mynetworks">mynetworks</a></tt> parameter at its
+default (i.e. no <tt><a href="postconf.5.html#mynetworks">mynetworks</a></tt> setting in main.cf) Postfix will figure
+out by itself what its network addresses are. This is what a typical
+setting looks like: </p>
+
+<blockquote>
+<pre>
+% postconf <a href="postconf.5.html#mynetworks">mynetworks</a>
+<a href="postconf.5.html#mynetworks">mynetworks</a> = 127.0.0.0/8 168.100.189.0/28 [::1]/128 [fe80::]/10 [2001:240:5c7::]/64
+</pre>
+</blockquote>
+
+<p> If you did specify the <tt><a href="postconf.5.html#mynetworks">mynetworks</a></tt> parameter value in
+main.cf, you need update the <tt><a href="postconf.5.html#mynetworks">mynetworks</a></tt> value to include
+the IPv6 networks the system is in. Be sure to specify IPv6 address
+information inside <tt>[]</tt>, like this: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ <a href="postconf.5.html#mynetworks">mynetworks</a> = ...<i>IPv4 networks</i>... [::1]/128 [2001:240:5c7::]/64 ...
+</pre>
+</blockquote>
+
+</ul>
+
+<p> <b> NOTE: when configuring Postfix match lists such as
+<tt><a href="postconf.5.html#mynetworks">mynetworks</a></tt> or <tt><a href="postconf.5.html#debug_peer_list">debug_peer_list</a></tt>, you must specify
+IPv6 address information inside <tt>[]</tt> in the main.cf parameter
+value and in files specified with a "<i>/file/name</i>" pattern.
+IPv6 addresses contain the ":" character, and would otherwise be
+confused with a "<i>type:table</i>" pattern. </b> </p>
+
+<h2><a name="limitations">Known Limitations</a></h2>
+
+<ul>
+
+<li> <p> The order of IPv6/IPv4 outgoing connection attempts is
+not yet configurable. Currently, IPv6 is tried before IPv4. </p>
+
+<li> <p> Postfix currently does not support DNSBL (real-time
+blackhole list) lookups for IPv6 client IP addresses; currently
+there are no blacklists that cover the IPv6 address space. </p>
+
+<li> <p> IPv6 does not have class A, B, C, etc. networks. With IPv6
+networks, the setting "<tt><a href="postconf.5.html#mynetworks_style">mynetworks_style</a> = class</tt>" has the
+same effect as the setting "<tt><a href="postconf.5.html#mynetworks_style">mynetworks_style</a> = subnet</tt>".
+</p>
+
+<li> <p> On Tru64Unix, Postfix can't figure out the local subnet mask
+and always assumes a /128 network. This is a problem only with
+"<tt><a href="postconf.5.html#mynetworks_style">mynetworks_style</a> = subnet</tt>" and no explicit <tt><a href="postconf.5.html#mynetworks">mynetworks</a></tt>
+setting in main.cf. </p>
+
+</ul>
+
+<h2> <a name="compat">Compatibility with Postfix <2.2 IPv6 support</a>
+</h2>
+
+<p> Postfix version 2.2 IPv6 support is based on the Postfix/IPv6 patch
+by Dean Strik and others, but differs in a few minor ways. </p>
+
+<ul>
+
+<li> <p> main.cf: The <tt><a href="postconf.5.html#inet_interfaces">inet_interfaces</a></tt> parameter does not support
+the notation "<tt>ipv6:all</tt>" or "<tt>ipv4:all</tt>". Use the
+<tt><a href="postconf.5.html#inet_protocols">inet_protocols</a></tt> parameter instead. </p>
+
+<li> <p> main.cf: Specify "<tt><a href="postconf.5.html#inet_protocols">inet_protocols</a> = all</tt>" or
+"<tt><a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv4, ipv6</tt>" in order to enable both IPv4
+and IPv6 support. </p>
+
+<li> <p> main.cf: The <tt><a href="postconf.5.html#inet_protocols">inet_protocols</a></tt> parameter also controls
+what DNS lookups Postfix will attempt to make when delivering or
+receiving mail. </p>
+
+<li> <p> main.cf: Specify "<tt><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = loopback-only</tt>"
+to listen on loopback network interfaces only. </p>
+
+<li> <p> The <tt>lmtp_bind_address</tt> and <tt>lmtp_bind_address6</tt>
+features were omitted. The Postfix LMTP client will be absorbed
+into the SMTP client, so there is no reason to keep adding features
+to the LMTP client. </p>
+
+<li> <p> The SMTP server now requires that IPv6 addresses in SMTP
+commands are specified as <tt>[ipv6:<i>ipv6address</i>]</tt>, as
+described in <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a>. </p>
+
+<li> <p> The IPv6 network address matching code was rewritten from
+the ground up, and is expected to be closer to the specification.
+The result may be incompatible with the Postfix/IPv6 patch.
+</p>
+
+</ul>
+
+<h2><a name="porting">IPv6 Support for unsupported platforms</a></h2>
+
+<p> Getting Postfix IPv6 working on other platforms involves the
+following steps: </p>
+
+<ul>
+
+<li> <p> Specify how Postfix should find the local network interfaces.
+Postfix needs this information to avoid mailer loops and to find out
+if mail for <i>user@[ipaddress]</i> is a local or remote destination. </p>
+
+<p> If your system has the <tt>getifaddrs()</tt> routine then add
+the following to your platform-specific section in
+<tt>src/util/sys_defs.h</tt>: </p>
+
+<blockquote>
+<pre>
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAVE_GETIFADDRS
+#endif
+</pre>
+</blockquote>
+
+<p> Otherwise, if your system has the SIOCGLIF <tt>ioctl()</tt>
+command in <tt>/usr/include/*/*.h</tt>, add the following to your
+platform-specific section in <tt>src/util/sys_defs.h</tt>: </p>
+
+<blockquote>
+<pre>
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAS_SIOCGLIF
+#endif
+</pre>
+</blockquote>
+
+<p> Otherwise, Postfix will have to use the old SIOCGIF commands
+and get along with reduced IPv6 functionality (it won't be able to
+figure out your IPv6 netmasks, which are needed for "<tt><a href="postconf.5.html#mynetworks_style">mynetworks_style</a>
+= subnet</tt>". Add this to your platform-specific section in
+<tt>src/util/sys_defs.h</tt>: </p>
+
+<blockquote>
+<pre>
+#ifndef NO_IPV6
+# define HAS_IPV6
+#endif
+</pre>
+</blockquote>
+
+<li> <p> Test if Postfix can figure out its interface information. </p>
+
+<p> After compiling Postfix in the usual manner, step into the
+<tt>src/util</tt> directory and type "<tt>make inet_addr_local</tt>".
+Running this file by hand should produce all the interface addresses
+and network masks, for example: </p>
+
+<blockquote>
+<pre>
+% make
+% cd src/util
+% make inet_addr_local
+[... some messages ...]
+% ./inet_addr_local
+[... some messages ...]
+./inet_addr_local: inet_addr_local: configured 2 IPv4 addresses
+./inet_addr_local: inet_addr_local: configured 4 IPv6 addresses
+168.100.189.2/255.255.255.224
+127.0.0.1/255.0.0.0
+fe80:1::2d0:b7ff:fe88:2ca7/ffff:ffff:ffff:ffff::
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7/ffff:ffff:ffff:ffff::
+fe80:5::1/ffff:ffff:ffff:ffff::
+::1/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+</pre>
+</blockquote>
+
+<p> The above is for an old FreeBSD machine. Other systems produce
+slightly different results, but you get the idea. </p>
+
+</ul>
+
+<p> If none of all this produces a usable result, send email to the
+postfix-users@postfix.org mailing list and we'll try to help you
+through this. </p>
+
+<h2><a name="credits">Credits</a></h2>
+
+<p> The following information is in part based on information that
+was compiled by Dean Strik. </p>
+
+<ul>
+
+<li> <p> Mark Huizer wrote the original Postfix IPv6 patch. </p>
+
+<li> <p> Jun-ichiro 'itojun' Hagino of the KAME project made
+substantial improvements. Since then, we speak of the KAME patch.
+</p>
+
+<li> <p> The PLD Linux Distribution ported the code to other stacks
+(notably USAGI). We speak of the PLD patch. A very important
+feature of the PLD patch was that it can work with Lutz Jaenicke's
+TLS patch for Postfix. </p>
+
+<li> <p> Dean Strik extended IPv6 support to platforms other than
+KAME and USAGI, updated the patch to keep up with Postfix development,
+and provided a combined IPv6 + TLS patch. Information about his
+effort can be found on Dean Strik's Postfix website at
+<a href="http://www.ipnet6.org/postfix/">http://www.ipnet6.org/postfix/</a>. </p>
+
+<li> <p> Wietse Venema took Dean Strik's IPv6 patch, merged it into
+Postfix 2.2, and took the opportunity to eliminate all IPv4-specific
+code from Postfix that could be removed. For systems without IPv6
+support in the kernel and system libraries, Postfix has a simple
+compatibility layer, so that it will use IPv4 as before. </p>
+
+</ul>
+
+</body>
+
+</html>
<p> When receiving mail, Postfix logs the client-provided username,
authentication method, and sender address to the maillog file, and
-optionally grants mail access via the permit_sasl_authenticated
+optionally grants mail access via the <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a>
UCE restriction. </p>
<p> Postfix does not record the client's SASL authentication
<pre>
/etc/postfix/main.cf:
<a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> =
- <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a> permit_sasl_authenticated ...
+ <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a> <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a> ...
</pre>
</blockquote>
either does not send the attribute, or sends the attribute with
an empty value ("name="). </p>
+ <li> <p> The client address is an IPv4 dotted quad in the form
+ 1.2.3.4 or it is an IPv6 address in the form 1:2:3::4:5:6.
+ </p>
+
<li> <p> An attribute name must not contain "=", null or newline,
and an attribute value must not contain null or newline. </p>
The optional <b>access</b> table directs the Postfix SMTP server
to selectively reject or accept mail. Access can be
allowed or denied for specific host names, domain names,
- networks, host network addresses or mail addresses.
+ networks, host addresses or mail addresses.
For an example, see the EXAMPLE section at the end of this
manual page.
<i>net.work</i>
- <i>net</i> Matches any host address in the specified network.
- A network address is a sequence of one or more
- octets separated by ".".
+ <i>net</i> Matches the specified IPv4 host address or subnet-
+ work. An IPv4 host address is a sequence of four
+ decimal octets separated by ".".
- NOTE: use the <b>cidr</b> lookup table type to specify
+ Subnetworks are matched by repeatedly truncating
+ the last ".octet" from the remote IPv4 host address
+ string until a match is found in the access table,
+ or until further truncation is not possible.
+
+ NOTE 1: The information in the access map should be
+ in canonical form, with unnecessary null characters
+ eliminated. Address information must not be
+ enclosed with "[]" characters.
+
+ NOTE 2: use the <b>cidr</b> lookup table type to specify
network/netmask patterns. See <a href="cidr_table.5.html">cidr_table(5)</a> for
details.
+ <i>net:work:addr:ess</i>
+
+ <i>net:work:addr</i>
+
+ <i>net:work</i>
+
+ <i>net</i> Matches the specified IPv6 host address or subnet-
+ work. An IPv6 host address is a sequence of three
+ to eight hexadecimal octet pairs separated by ":".
+
+ Subnetworks are matched by repeatedly truncating
+ the last ":octetpair" from the remote IPv6 host
+ address string until a match is found in the access
+ table, or until further truncation is not possible.
+
+ NOTE 1: the truncation and comparison are done with
+ the string representation of the IPv6 host address.
+ Thus, not all the ":" subnetworks will be tried.
+
+ NOTE 2: The information in the access map should be
+ in canonical form, with unnecessary null characters
+ eliminated. Address information must not be
+ enclosed with "[]" characters.
+
+ NOTE 3: use the <b>cidr</b> lookup table type to specify
+ network/netmask patterns. See <a href="cidr_table.5.html">cidr_table(5)</a> for
+ details.
+
+ IPv6 support is available in Postfix 2.2 and later.
+
<b>ACCEPT ACTIONS</b>
<b>OK</b> Accept the address etc. that matches the pattern.
<i>all-numerical</i>
An all-numerical result is treated as OK. This for-
- mat is generated by address-based relay authoriza-
+ mat is generated by address-based relay authoriza-
tion schemes.
<b>REJECT ACTIONS</b>
<b>4</b><i>NN text</i>
<b>5</b><i>NN text</i>
- Reject the address etc. that matches the pattern,
+ Reject the address etc. that matches the pattern,
and respond with the numerical three-digit code and
- text. <b>4</b><i>NN</i> means "try again later", while <b>5</b><i>NN</i> means
+ text. <b>4</b><i>NN</i> means "try again later", while <b>5</b><i>NN</i> means
"do not try again".
<b>REJECT</b> <i>optional text...</i>
- Reject the address etc. that matches the pattern.
- Reply with <i>$reject</i><b>_</b><i>code optional text...</i> when the
- optional text is specified, otherwise reply with a
+ Reject the address etc. that matches the pattern.
+ Reply with <i>$reject</i><b>_</b><i>code optional text...</i> when the
+ optional text is specified, otherwise reply with a
generic error response message.
<b>DEFER_IF_REJECT</b> <i>optional text...</i>
- Defer the request if some later restriction would
+ Defer the request if some later restriction would
result in a REJECT action. Reply with "<b>450</b> <i>optional</i>
<i>text...</i> when the optional text is specified, other-
wise reply with a generic error response message.
This feature is available in Postfix 2.1 and later.
<b>DEFER_IF_PERMIT</b> <i>optional text...</i>
- Defer the request if some later restriction would
- result in a an explicit or implicit PERMIT action.
- Reply with "<b>450</b> <i>optional text...</i> when the optional
- text is specified, otherwise reply with a generic
+ Defer the request if some later restriction would
+ result in a an explicit or implicit PERMIT action.
+ Reply with "<b>450</b> <i>optional text...</i> when the optional
+ text is specified, otherwise reply with a generic
error response message.
This feature is available in Postfix 2.1 and later.
<b><a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a></b>, and so on).
<b>DISCARD</b> <i>optional text...</i>
- Claim successful delivery and silently discard the
- message. Log the optional text if specified, oth-
+ Claim successful delivery and silently discard the
+ message. Log the optional text if specified, oth-
erwise log a generic message.
- Note: this action currently affects all recipients
+ Note: this action currently affects all recipients
of the message.
This feature is available in Postfix 2.0 and later.
- <b>DUNNO</b> Pretend that the lookup key was not found. This
- prevents Postfix from trying substrings of the
- lookup key (such as a subdomain name, or a network
+ <b>DUNNO</b> Pretend that the lookup key was not found. This
+ prevents Postfix from trying substrings of the
+ lookup key (such as a subdomain name, or a network
address subnetwork).
This feature is available in Postfix 2.0 and later.
<b>FILTER</b> <i>transport:destination</i>
- After the message is queued, send the entire mes-
+ After the message is queued, send the entire mes-
sage through the specified external content filter.
- The <i>transport:destination</i> syntax is described in
- the <a href="transport.5.html">transport(5)</a> manual page. More information
- about external content filters is in the Postfix
+ The <i>transport:destination</i> syntax is described in
+ the <a href="transport.5.html">transport(5)</a> manual page. More information
+ about external content filters is in the Postfix
<a href="FILTER_README.html">FILTER_README</a> file.
- Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b>
+ Note: this action overrides the <b>main.cf <a href="postconf.5.html#content_filter">con</a>-</b>
<b><a href="postconf.5.html#content_filter">tent_filter</a></b> setting, and currently affects all
recipients of the message.
This feature is available in Postfix 2.0 and later.
<b>HOLD</b> <i>optional text...</i>
- Place the message on the <b>hold</b> queue, where it will
- sit until someone either deletes it or releases it
- for delivery. Log the optional text if specified,
+ Place the message on the <b>hold</b> queue, where it will
+ sit until someone either deletes it or releases it
+ for delivery. Log the optional text if specified,
otherwise log a generic message.
- Mail that is placed on hold can be examined with
- the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and can be destroyed or
+ Mail that is placed on hold can be examined with
+ the <a href="postcat.1.html"><b>postcat</b>(1)</a> command, and can be destroyed or
released with the <a href="postsuper.1.html"><b>postsuper</b>(1)</a> command.
- Note: use "<b>postsuper -r</b>" to release mail that was
- kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
+ Note: use "<b>postsuper -r</b>" to release mail that was
+ kept on hold for a significant fraction of <b>$<a href="postconf.5.html#maximal_queue_lifetime">maxi</a>-</b>
<b><a href="postconf.5.html#maximal_queue_lifetime">mal_queue_lifetime</a></b> or <b>$<a href="postconf.5.html#bounce_queue_lifetime">bounce_queue_lifetime</a></b>, or
longer.
- Note: this action currently affects all recipients
+ Note: this action currently affects all recipients
of the message.
This feature is available in Postfix 2.0 and later.
<b>PREPEND</b> <i>headername: headervalue</i>
- Prepend the specified message header to the mes-
+ Prepend the specified message header to the mes-
sage. When this action is used multiple times, the
- first prepended header appears before the second
+ first prepended header appears before the second
etc. prepended header.
- Note: this action does not support multi-line mes-
+ Note: this action does not support multi-line mes-
sage headers.
This feature is available in Postfix 2.1 and later.
<b>REDIRECT</b> <i>user@domain</i>
- After the message is queued, send the message to
+ After the message is queued, send the message to
the specified address instead of the intended
recipient(s).
- Note: this action overrides the FILTER action, and
+ Note: this action overrides the FILTER action, and
currently affects all recipients of the message.
This feature is available in Postfix 2.1 and later.
<b>WARN</b> <i>optional text...</i>
Log a warning with the optional text, together with
- client information and if available, with helo,
+ client information and if available, with helo,
sender, recipient and protocol information.
This feature is available in Postfix 2.1 and later.
<b>REGULAR EXPRESSION TABLES</b>
- This section describes how the table lookups change when
+ This section describes how the table lookups change when
the table is given in the form of regular expressions. For
- a description of regular expression lookup table syntax,
+ a description of regular expression lookup table syntax,
see <a href="regexp_table.5.html"><b>regexp_table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
- Each pattern is a regular expression that is applied to
+ Each pattern is a regular expression that is applied to
the entire string being looked up. Depending on the appli-
- cation, that string is an entire client hostname, an
+ cation, that string is an entire client hostname, an
entire client IP address, or an entire mail address. Thus,
no parent domain or parent network search is done,
- <i>user@domain</i> mail addresses are not broken up into their
+ <i>user@domain</i> mail addresses are not broken up into their
<i>user@</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken
up into <i>user</i> and <i>foo</i>.
- Patterns are applied in the order as specified in the
- table, until a pattern is found that matches the search
+ Patterns are applied in the order as specified in the
+ table, until a pattern is found that matches the search
string.
- Actions are the same as with indexed file lookups, with
- the additional feature that parenthesized substrings from
+ Actions are the same as with indexed file lookups, with
+ the additional feature that parenthesized substrings from
the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
<b>TCP-BASED TABLES</b>
- This section describes how the table lookups change when
+ This section describes how the table lookups change when
lookups are directed to a TCP-based server. For a descrip-
- tion of the TCP client/server lookup protocol, see
- <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>. This feature is not available in Postfix
+ tion of the TCP client/server lookup protocol, see
+ <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>. This feature is not available in Postfix
version 2.1.
- Each lookup operation uses the entire query string once.
- Depending on the application, that string is an entire
+ Each lookup operation uses the entire query string once.
+ Depending on the application, that string is an entire
client hostname, an entire client IP address, or an entire
- mail address. Thus, no parent domain or parent network
- search is done, <i>user@domain</i> mail addresses are not broken
- up into their <i>user@</i> and <i>domain</i> constituent parts, nor is
+ mail address. Thus, no parent domain or parent network
+ search is done, <i>user@domain</i> mail addresses are not broken
+ up into their <i>user@</i> and <i>domain</i> constituent parts, nor is
<i>user+foo</i> broken up into <i>user</i> and <i>foo</i>.
Actions are the same as with indexed file lookups.
<b>EXAMPLE</b>
- The following example uses an indexed file, so that the
- order of table entries does not matter. The example per-
- mits access by the client at address 1.2.3.4 but rejects
- all other clients in 1.2.3.0/24. Instead of <b>hash</b> lookup
- tables, some systems use <b>dbm</b>. Use the command "<b>postconf</b>
- <b>-m</b>" to find out what lookup tables Postfix supports on
+ The following example uses an indexed file, so that the
+ order of table entries does not matter. The example per-
+ mits access by the client at address 1.2.3.4 but rejects
+ all other clients in 1.2.3.0/24. Instead of <b>hash</b> lookup
+ tables, some systems use <b>dbm</b>. Use the command "<b>postconf</b>
+ <b>-m</b>" to find out what lookup tables Postfix supports on
your system.
/etc/postfix/main.cf:
editing the file.
<b>BUGS</b>
- The table format does not understand quoting conventions.
+ The table format does not understand quoting conventions.
<b>SEE ALSO</b>
<a href="postmap.1.html">postmap(1)</a>, Postfix lookup table manager
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
<i>network</i><b>_</b><i>address</i><b>/</b><i>network</i><b>_</b><i>mask result</i>
When a search string matches the specified network
block, use the corresponding <i>result</i> value. Specify
- 0.0.0.0/0 to match every address.
+ 0.0.0.0/0 to match every IPv4 address, and ::/0 to
+ match every IPv6 address.
+
+ Note: address information may be enclosed inside
+ "[]" but this form is not recommended.
+
+ IPv6 support is available in Postfix 2.2 and later.
<i>network</i><b>_</b><i>address result</i>
- When a search string matches the specified network
+ When a search string matches the specified network
address, use the corresponding <i>result</i> value.
blank lines and comments
- Empty lines and whitespace-only lines are ignored,
- as are lines whose first non-whitespace character
+ Empty lines and whitespace-only lines are ignored,
+ as are lines whose first non-whitespace character
is a `#'.
multi-line text
- A logical line starts with non-whitespace text. A
- line that starts with whitespace continues a logi-
+ A logical line starts with non-whitespace text. A
+ line that starts with whitespace continues a logi-
cal line.
<b>SEARCH ORDER</b>
- Patterns are applied in the order as specified in the
- table, until a pattern is found that matches the search
+ Patterns are applied in the order as specified in the
+ table, until a pattern is found that matches the search
string.
<b>EXAMPLE SMTPD ACCESS MAP</b>
<li> <a href="SASL_README.html"> SASL Authentication </a>
+<li> <a href="IPV6_README.html"> IP Version 6 Support </a>
+
<li> <a href="INSTALL.html"> Installation from source code </a>
</ul>
<b>postfix reload</b> command after a configuration change.
<b>RESOURCE AND RATE CONTROLS</b>
- <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
- built-in watchdog timer.
-
<b><a href="postconf.5.html#default_process_limit">default_process_limit</a> (100)</b>
The default maximal number of Postfix child pro-
cesses that provide a given service.
The network interface addresses that this mail sys-
tem receives mail on.
+ <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
+ The Internet protocols Postfix will attempt to use
+ when making or accepting connections.
+
<b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
- The list of environment parameters that a Postfix
- process will import from a non-Postfix parent pro-
+ The list of environment parameters that a Postfix
+ process will import from a non-Postfix parent pro-
cess.
<b><a href="postconf.5.html#mail_owner">mail_owner</a> (postfix)</b>
and most Postfix daemon processes.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon pro-
+ The process ID of a Postfix command or daemon pro-
cess.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the pro-
+ The mail system name that is prepended to the pro-
cess name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
syslogd(8), system logging
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the <a href="postconf.5.html#authorized_verp_clients">authorized_verp_clients</a> value, and in files
+specified with "/file/name". IP version 6 addresses contain the
+":" character, and would otherwise be confused with a "<a href="DATABASE_README.html">type:table</a>"
+pattern. </p>
+
</DD>
</DD>
<DT><b><a name="hash_queue_names">hash_queue_names</a>
-(default: see "postconf -d" output)</b></DT><DD>
+(default: deferred, defer)</b></DT><DD>
<p>
The names of queue directories that are split across multiple
subdirectory levels.
</p>
+<p> Before Postfix version 2.2, the default list of hashed queues
+was significantly larger. Claims about improvements in file system
+technology suggest that hashing of the <a href="QSHAPE_README.html#incoming_queue">incoming</a> and <a href="QSHAPE_README.html#active_queue">active queues</a>
+is no longer needed. Fewer hashed directories speed up the time
+needed to restart Postfix. </p>
+
<p>
After changing the <a href="postconf.5.html#hash_queue_names">hash_queue_names</a> or <a href="postconf.5.html#hash_queue_depth">hash_queue_depth</a> parameter,
execute the command "<b>postfix reload</b>".
<DT><b><a name="inet_interfaces">inet_interfaces</a>
(default: all)</b></DT><DD>
+<p> The network interface addresses that this mail system receives
+mail on. By default, the software claims all active interfaces on
+the machine; with Postfix 2.2 and later, specify "<b>loopback-only</b>"
+to select only local interfaces. The parameter also controls
+delivery of mail to user@[ip.address]. </p>
+
<p>
-The network interface addresses that this mail system receives mail
-on. By default, the software claims all active interfaces on the
-machine. The parameter also controls delivery of mail to
-user@[ip.address].
+Note: you need to stop and start Postfix when this parameter changes.
</p>
-<p>
-When <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> consists of just one IP address that is not a
-loopback (net 127) address, the Postfix SMTP client will use this address
-as the IP source address for outbound mail. </p>
+<p> When <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> specifies just one IPv4 and/or IPv6 address
+that is not a loopback address, the Postfix SMTP client will use
+this address as the IP source address for outbound mail. </p>
<p>
On a multi-homed firewall with separate Postfix instances listening on the
"inside" and "outside" interfaces, this can prevent each instance from
being able to reach servers on the "other side" of the firewall. Setting
-<a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> to 0.0.0.0 avoids the potential problem. </p>
+<a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> to 0.0.0.0 avoids the potential problem for
+IPv4, and setting <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> to :: solves the problem
+for IPv6. </p>
<p>
-A better solution is to leave <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> at the default value
+A better solution for multi-homed firewalls is to leave <a href="postconf.5.html#inet_interfaces">inet_interfaces</a>
+at the default value
and instead use explicit IP addresses in master.cf. This preserves SMTP
loop detection, by ensuring that each side of the firewall knows that the
other IP address is still the same host. Setting $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> to a
-single IP address is primarily useful with virtual hosting of domains on
+single IPv4 and/or IPV6 address is primarily useful with virtual
+hosting of domains on
secondary IP addresses, when each IP address serves a different domain
(and has a different $<a href="postconf.5.html#myhostname">myhostname</a> setting). </p>
<p>
See also the <a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> parameter, for network addresses that
-are forwarded to us by way of a proxy or address translator.
+are forwarded to Postfix by way of a proxy or address translator.
</p>
<p>
-Note: you need to stop and start Postfix when this parameter changes.
+Examples:
+</p>
+
+<pre>
+<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = all (DEFAULT)
+<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = loopback-only
+<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = 127.0.0.1
+<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> = 192.168.1.2, 127.0.0.1
+</pre>
+
+
+</DD>
+
+<DT><b><a name="inet_protocols">inet_protocols</a>
+(default: ipv4)</b></DT><DD>
+
+<p> The Internet protocols Postfix will attempt to use when making
+or accepting connections. Specify one or more of "ipv4" or "ipv6",
+separated by whitespace or commas. The form "all" is equivalent to
+"ipv4, ipv6". </p>
+
+<p> Note: you MUST stop and start Postfix after changing this
+parameter. </p>
+
+<p> On systems that pre-date IPV6_V6ONLY support (<a href="http://www.faqs.org/rfcs/rfc3493.html">RFC 3493</a>), an
+IPv6 server will also accept IPv4 connections, even when IPv4 is
+turned off with the <a href="postconf.5.html#inet_protocols">inet_protocols</a> parameter. On systems with
+IPV6_V6ONLY support, Postfix will use separate server sockets for
+IPv6 and IPv4, and each will accept only connections for the
+corresponding protocol. </p>
+
+<p> When IPv4 support is enabled via the <a href="postconf.5.html#inet_protocols">inet_protocols</a> parameter,
+Postfix will to DNS type A record lookups, and will convert
+IPv4-in-IPv6 client IP addresses (::ffff:1.2.3.4) to their original
+IPv4 form (1.2.3.4). The latter is needed on hosts that pre-date
+IPV6_V6ONLY support (<a href="http://www.faqs.org/rfcs/rfc3493.html">RFC 3493</a>). </p>
+
+<p> When IPv6 support is enabled via the <a href="postconf.5.html#inet_protocols">inet_protocols</a> parameter,
+Postfix will do DNS type AAAA record lookups. </p>
+
+<p> When both IPv4 and IPv6 support are enabled, the Postfix SMTP
+client will attempt to connect via IPv6 before attempting to use
+IPv4. </p>
+
+<p> This feature is available in Postfix version 2.2 and later. </p>
+
+<p>
+Examples:
</p>
+<pre>
+<a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv4 (DEFAULT)
+<a href="postconf.5.html#inet_protocols">inet_protocols</a> = all
+<a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv6
+<a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv4, ipv6
+</pre>
+
</DD>
first match. Specify "!pattern" to exclude an address or network
block from the list. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the <a href="postconf.5.html#mynetworks">mynetworks</a> value, and in files specified with
+"/file/name". IP version 6 addresses contain the ":" character,
+and would otherwise be confused with a "<a href="DATABASE_README.html">type:table</a>" pattern. </p>
+
<p> Examples: </p>
<pre>
-<a href="postconf.5.html#mynetworks">mynetworks</a> = 168.100.189.0/28, 127.0.0.0/8
+<a href="postconf.5.html#mynetworks">mynetworks</a> = 127.0.0.0/8 168.100.189.0/28
<a href="postconf.5.html#mynetworks">mynetworks</a> = !192.168.0.1, 192.168.0.0/28
+<a href="postconf.5.html#mynetworks">mynetworks</a> = 127.0.0.0/8 168.100.189.0/28 [::1]/128 [2001:240:5c7::]/64
<a href="postconf.5.html#mynetworks">mynetworks</a> = $<a href="postconf.5.html#config_directory">config_directory</a>/mynetworks
<a href="postconf.5.html#mynetworks">mynetworks</a> = hash:/etc/postfix/network_table
</pre>
<p>
An optional numerical network address that the SMTP client should
-bind to when making a connection.
+bind to when making an IPv4 connection.
</p>
<p>
smtp ... smtp -o <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a>=11.22.33.44
</pre>
-<p> Note: when <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> specifies exactly one address that
-is a non-loopback address, it is automatically used as the
-<a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a>. This supports virtual IP hosting, but can be
-a problem on multi-homed firewalls. See the <a href="postconf.5.html#inet_interfaces">inet_interfaces</a>
-documentation for more detail. </p>
+<p> Note 1: when <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> specifies no more than one IPv4
+address, and that address is a non-loopback address, it is
+automatically used as the <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a>. This supports virtual
+IP hosting, but can be a problem on multi-homed firewalls. See the
+<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> documentation for more detail. </p>
+
+<p> Note 2: address information may be enclosed inside <tt>[]</tt>,
+but this form is not recommended. </p>
+
+
+</DD>
+
+<DT><b><a name="smtp_bind_address6">smtp_bind_address6</a>
+(default: empty)</b></DT><DD>
+
+<p>
+An optional numerical network address that the SMTP client should
+bind to when making an IPv6 connection.
+</p>
+
+<p>
+This can be specified in the main.cf file for all SMTP clients, or
+it can be specified in the master.cf file for a specific client,
+for example:
+</p>
+
+<pre>
+ /etc/postfix/master.cf:
+ smtp ... smtp -o <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a>=1:2:3:4:5:6:7:8
+</pre>
+
+<p> Note 1: when <a href="postconf.5.html#inet_interfaces">inet_interfaces</a> specifies no more than one IPv6
+address, and that address is a non-loopback address, it is
+automatically used as the <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a>. This supports virtual
+IP hosting, but can be a problem on multi-homed firewalls. See the
+<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> documentation for more detail. </p>
+
+<p> Note 2: address information may be enclosed inside <tt>[]</tt>,
+but this form is not recommended. </p>
+
+<p> This feature is available in Postfix version 2.2 and later. </p>
</DD>
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the <a href="postconf.5.html#smtpd_authorized_verp_clients">smtpd_authorized_verp_clients</a> value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "<a href="DATABASE_README.html">type:table</a>"
+pattern. </p>
+
</DD>
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the <a href="postconf.5.html#smtpd_authorized_xclient_hosts">smtpd_authorized_xclient_hosts</a> value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "<a href="DATABASE_README.html">type:table</a>"
+pattern. </p>
+
</DD>
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the <a href="postconf.5.html#smtpd_authorized_xforward_hosts">smtpd_authorized_xforward_hosts</a> value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "<a href="DATABASE_README.html">type:table</a>"
+pattern. </p>
+
</DD>
dot causes the domain to match any name below it).
</p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the <a href="postconf.5.html#smtpd_client_event_limit_exceptions">smtpd_client_event_limit_exceptions</a> value, and
+in files specified with "/file/name". IP version 6 addresses
+contain the ":" character, and would otherwise be confused with a
+"<a href="DATABASE_README.html">type:table</a>" pattern. </p>
+
<p>
This feature is available in Postfix 2.2 and later.
</p>
matches a lookup string (the lookup result is ignored). Continue
long lines by starting the next line with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the <a href="postconf.5.html#smtpd_sasl_exceptions_networks">smtpd_sasl_exceptions_networks</a> value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "<a href="DATABASE_README.html">type:table</a>"
+pattern. </p>
+
<p>
Example:
</p>
<p> Optional lookup tables with a) names of domains for which all
addresses are aliased to addresses in other local or remote domains,
and b) addresses that are aliased to addresses in other local or
-remote domains. Available before Postfix version 2.0. With Postfix 2.1
+remote domains. Available before Postfix version 2.0. With Postfix 2.0
and later, this is replaced by separate controls: <a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>
and <a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>. </p>
<b>-s</b> <i>site</i>
Schedule immediate delivery of all mail that is
- queued for the named <i>site</i>. The site must be eligi-
- ble for the "fast flush" service. See <a href="flush.8.html"><b>flush</b>(8)</a> for
- more information about the "fast flush" service.
-
- This option implements the traditional <b>sendmail</b>
+ queued for the named <i>site</i>. A numerical site must be
+ specified as a valid <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> address literal
+ enclosed in [], just like in email addresses. The
+ site must be eligible for the "fast flush" service.
+ See <a href="flush.8.html"><b>flush</b>(8)</a> for more information about the "fast
+ flush" service.
+
+ This option implements the traditional <b>sendmail</b>
<b>-qR</b><i>site</i> command, by contacting the Postfix <a href="flush.8.html"><b>flush</b>(8)</a>
daemon.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>SECURITY</b>
- This program is designed to run with set-group ID privi-
+ This program is designed to run with set-group ID privi-
leges, so that it can connect to Postfix daemon processes.
<b>DIAGNOSTICS</b>
- Problems are logged to <b>syslogd</b>(8) and to the standard
+ Problems are logged to <b>syslogd</b>(8) and to the standard
error stream.
<b>ENVIRONMENT</b>
MAIL_CONFIG
- Directory with the <b>main.cf</b> file. In order to avoid
- exploitation of set-group ID privileges, a non-
+ Directory with the <b>main.cf</b> file. In order to avoid
+ exploitation of set-group ID privileges, a non-
standard directory is allowed only if:
- <b>o</b> The name is listed in the standard <b>main.cf</b>
- file with the <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a></b>
+ <b>o</b> The name is listed in the standard <b>main.cf</b>
+ file with the <b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a></b>
configuration parameter.
<b>o</b> The command is invoked by the super-user.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <b>main.cf</b> parameters are especially relevant
to this program. The text below provides only a parameter
- summary. See <a href="postconf.5.html">postconf(5)</a> for more details including exam-
+ summary. See <a href="postconf.5.html">postconf(5)</a> for more details including exam-
ples.
<b><a href="postconf.5.html#alternate_config_directories">alternate_config_directories</a> (empty)</b>
- A list of non-default Postfix configuration direc-
+ A list of non-default Postfix configuration direc-
tories that may be specified with "-c <a href="postconf.5.html#config_directory">config_direc</a>-
- <a href="postconf.5.html#config_directory">tory</a>" on the command line, or via the MAIL_CONFIG
+ <a href="postconf.5.html#config_directory">tory</a>" on the command line, or via the MAIL_CONFIG
environment parameter.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#fast_flush_domains">fast_flush_domains</a> ($<a href="postconf.5.html#relay_domains">relay_domains</a>)</b>
Optional list of destinations that are eligible for
- per-destination logfiles with mail that is queued
+ per-destination logfiles with mail that is queued
to those destinations.
<b><a href="postconf.5.html#import_environment">import_environment</a> (see 'postconf -d' output)</b>
- The list of environment parameters that a Postfix
- process will import from a non-Postfix parent pro-
+ The list of environment parameters that a Postfix
+ process will import from a non-Postfix parent pro-
cess.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the pro-
+ The mail system name that is prepended to the pro-
cess name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<b><a href="postconf.5.html#trigger_timeout">trigger_timeout</a> (10s)</b>
- The time limit for sending a trigger to a Postfix
- daemon (for example, the <a href="pickup.8.html">pickup(8)</a> or <a href="qmgr.8.html">qmgr(8)</a> dae-
+ The time limit for sending a trigger to a Postfix
+ daemon (for example, the <a href="pickup.8.html">pickup(8)</a> or <a href="qmgr.8.html">qmgr(8)</a> dae-
mon).
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#authorized_flush_users">authorized_flush_users</a> (static:anyone)</b>
- List of users who are authorized to flush the
+ List of users who are authorized to flush the
queue.
<b><a href="postconf.5.html#authorized_mailq_users">authorized_mailq_users</a> (static:anyone)</b>
<a href="ETRN_README.html">ETRN_README</a>, Postfix ETRN howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>HISTORY</b>
- The postqueue command was introduced with Postfix version
+ The postqueue command was introduced with Postfix version
1.1.
<b>AUTHOR(S)</b>
qmqp-sink - multi-threaded QMQP test server
<b>SYNOPSIS</b>
- <b>qmqp-sink</b> [<b>-cv</b>] [<b>-x</b> <i>time</i>] [<b>inet:</b>][<i>host</i>]:<i>port backlog</i>
+ <b>qmqp-sink</b> [<b>-46cv</b>] [<b>-x</b> <i>time</i>] [<b>inet:</b>][<i>host</i>]:<i>port backlog</i>
- <b>qmqp-sink</b> [<b>-cv</b>] [<b>-x</b> <i>time</i>] <b>unix:</b><i>pathname backlog</i>
+ <b>qmqp-sink</b> [<b>-46cv</b>] [<b>-x</b> <i>time</i>] <b>unix:</b><i>pathname backlog</i>
<b>DESCRIPTION</b>
<b>qmqp-sink</b> listens on the named host (or address) and port.
It receives messages from the network and throws them
away. The purpose is to measure QMQP client performance,
not protocol compliance. Connections can be accepted on
- IPV4 endpoints or UNIX-domain sockets. IPV4 is the
- default. This program is the complement of the <a href="qmqp-source.1.html"><b>qmqp-</b></a>
- <a href="qmqp-source.1.html"><b>source</b>(1)</a> program.
+ IPv4 or IPv6 endpoints, or on UNIX-domain sockets. IPv4
+ and IPv6 are the default. This program is the complement
+ of the <a href="qmqp-source.1.html"><b>qmqp-source</b>(1)</a> program.
+
+ <b>-4</b> Support IPv4 only. This option has no effect when
+ Postfix is built without IPv6 support.
+
+ <b>-6</b> Support IPv6 only. This option is not available
+ when Postfix is built without IPv6 support.
<b>-c</b> Display a running counter that is updated whenever
a delivery is completed.
<b>qmqp-source</b> connects to the named host and TCP port
(default 628) and sends one or more messages to it, either
sequentially or in parallel. The program speaks the QMQP
- protocol. Connections can be made to UNIX-domain and IPV4
- servers. IPV4 is the default.
+ protocol. Connections can be made to UNIX-domain and IPv4
+ or IPv6 servers. IPv4 and IPv6 are the default.
Options:
+ <b>-4</b> Connect to the server with IPv4. This option has no
+ effect when Postfix is built without IPv6 support.
+
+ <b>-6</b> Connect to the server with IPv6. This option is not
+ available when Postfix is built without IPv6 sup-
+ port.
+
<b>-c</b> Display a running counter that is incremented each
time a delivery completes.
<b><a href="postconf.5.html#receive_override_options">receive_override_options</a> (empty)</b>
Enable or disable recipient validation, built-in
- content filtering, or address rewriting.
+ content filtering, or address mapping.
<b>RESOURCE AND RATE CONTROLS</b>
<b><a href="postconf.5.html#line_length_limit">line_length_limit</a> (2048)</b>
Non-default alias database. Specify <i>pathname</i> or
<i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details.
+ <b>-O</b> <i>option=value</i> (ignored)
+ Backwards compatibility.
+
<b>-o7</b> (ignored)
<b>-o8</b> (ignored)
away. The purpose is to measure client performance, not
protocol compliance.
- Connections can be accepted on IPV4 endpoints or UNIX-
- domain sockets. IPV4 is the default. This program is the
- complement of the <a href="smtp-source.1.html"><b>smtp-source</b>(1)</a> program.
+ Connections can be accepted on IPv4 or IPv6 endpoints, or
+ on UNIX-domain sockets. IPv4 and IPv6 are the default.
+ This program is the complement of the <a href="smtp-source.1.html"><b>smtp-source</b>(1)</a> pro-
+ gram.
Arguments:
+ <b>-4</b> Support IPv4 only. This option has no effect when
+ Postfix is built without IPv6 support.
+
+ <b>-6</b> Support IPv6 only. This option is not available
+ when Postfix is built without IPv6 support.
+
<b>-a</b> Do not announce SASL authentication support.
- <b>-c</b> Display a running counter that is updated whenever
+ <b>-c</b> Display a running counter that is updated whenever
an SMTP QUIT command is executed.
<b>-C</b> Disable XCLIENT support.
<b>-e</b> Do not announce ESMTP support.
<b>-f</b> <i>command,command,...</i>
- Reject the specified commands with a hard (5xx)
+ Reject the specified commands with a hard (5xx)
error code.
<b>-F</b> Disable XFORWARD support.
<b>-h</b> <i>hostname</i>
- Use <i>hostname</i> in the SMTP greeting, in the HELO
- response, and in the EHLO response. The default
+ Use <i>hostname</i> in the SMTP greeting, in the HELO
+ response, and in the EHLO response. The default
hostname is "smtp-sink".
<b>-L</b> Enable LMTP instead of SMTP.
Terminate after <i>count</i> sessions. This is for testing
purposes.
- <b>-p</b> Do not announce support for ESMTP command pipelin-
+ <b>-p</b> Do not announce support for ESMTP command pipelin-
ing.
- <b>-P</b> Change the server greeting so that it appears to
+ <b>-P</b> Change the server greeting so that it appears to
come through a CISCO PIX system. Implies <b>-e</b>.
<b>-q</b> <i>command,command,...</i>
- Disconnect (without replying) after receiving one
+ Disconnect (without replying) after receiving one
of the specified commands.
<b>-r</b> <i>command,command,...</i>
- Reject the specified commands with a soft (4xx)
+ Reject the specified commands with a soft (4xx)
error code.
<b>-s</b> <i>command,command,...</i>
- Log the named commands to syslogd. Examples of
- commands that can be logged are HELO, EHLO, LHLO,
- MAIL, RCPT, VRFY, RSET, NOOP, and QUIT. Separate
- command names by white space or commas, and use
- quotes to protect white space from the shell. Com-
+ Log the named commands to syslogd. Examples of
+ commands that can be logged are HELO, EHLO, LHLO,
+ MAIL, RCPT, VRFY, RSET, NOOP, and QUIT. Separate
+ command names by white space or commas, and use
+ quotes to protect white space from the shell. Com-
mand names are case-insensitive.
<b>-v</b> Show the SMTP conversations.
<b>-8</b> Do not announce 8BITMIME support.
[<b>inet:</b>][<i>host</i>]:<i>port</i>
- Listen on network interface <i>host</i> (default: any
+ Listen on network interface <i>host</i> (default: any
interface) TCP port <i>port</i>. Both <i>host</i> and <i>port</i> may be
specified in numeric or symbolic form.
Listen on the UNIX-domain socket at <i>pathname</i>.
<i>backlog</i>
- The maximum length the queue of pending connec-
+ The maximum length the queue of pending connec-
tions, as defined by the listen(2) call.
<b>SEE ALSO</b>
<a href="smtp-source.1.html">smtp-source(1)</a>, SMTP/LMTP message generator
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
<b>smtp-source</b> connects to the named <i>host</i> and TCP <i>port</i>
(default: port 25) and sends one or more messages to it,
either sequentially or in parallel. The program speaks
- either SMTP (default) or LMTP. Connections can be made to
- UNIX-domain and IPV4 servers. IPV4 is the default.
+ either SMTP (default) or LMTP. Connections can be made to
+ UNIX-domain and IPv4 or IPv6 servers. IPv4 and IPv6 are
+ the default.
Arguments:
- <b>-c</b> Display a running counter that is incremented each
+ <b>-4</b> Connect to the server with IPv4. This option has no
+ effect when Postfix is built without IPv6 support.
+
+ <b>-6</b> Connect to the server with IPv6. This option is not
+ available when Postfix is built without IPv6 sup-
+ port.
+
+ <b>-c</b> Display a running counter that is incremented each
time an SMTP DATA command completes.
<b>-C</b> <i>count</i>
- When a host sends RESET instead of SYN|ACK, try
- <i>count</i> times before giving up. The default count is
+ When a host sends RESET instead of SYN|ACK, try
+ <i>count</i> times before giving up. The default count is
1. Specify a larger count in order to work around a
problem with TCP/IP stacks that send RESET when the
listen queue is full.
- <b>-d</b> Don't disconnect after sending a message; send the
+ <b>-d</b> Don't disconnect after sending a message; send the
next message over the same connection.
<b>-f</b> <i>from</i>
- Use the specified sender address (default:
+ Use the specified sender address (default:
<foo@<a href="postconf.5.html#myhostname">myhostname</a>>).
- <b>-o</b> Old mode: don't send HELO, and don't send message
+ <b>-o</b> Old mode: don't send HELO, and don't send message
headers.
<b>-l</b> <i>length</i>
- Send <i>length</i> bytes as message payload. The length
+ Send <i>length</i> bytes as message payload. The length
does not include message headers.
<b>-L</b> Speak LMTP rather than SMTP.
<b>-m</b> <i>message</i><b>_</b><i>count</i>
Send the specified number of messages (default: 1).
- <b>-N</b> Prepend a non-repeating sequence number to each
- recipient address. This avoids the artificial 100%
- hit rate in the resolve and rewrite client caches
- and exercises the trivial-rewrite daemon, better
- approximating Postfix performance under real-life
+ <b>-N</b> Prepend a non-repeating sequence number to each
+ recipient address. This avoids the artificial 100%
+ hit rate in the resolve and rewrite client caches
+ and exercises the trivial-rewrite daemon, better
+ approximating Postfix performance under real-life
work-loads.
<b>-r</b> <i>recipient</i><b>_</b><i>count</i>
- Send the specified number of recipients per trans-
+ Send the specified number of recipients per trans-
action (default: 1). Recipient names are generated
by prepending a number to the recipient address.
lel (default: 1).
<b>-S</b> <i>subject</i>
- Send mail with the named subject line (default:
+ Send mail with the named subject line (default:
none).
- <b>-t</b> <i>to</i> Use the specified recipient address (default:
+ <b>-t</b> <i>to</i> Use the specified recipient address (default:
<foo@<a href="postconf.5.html#myhostname">myhostname</a>>).
<b>-R</b> <i>interval</i>
Wait for a random period of time 0 <= n <= interval
- between messages. Suspending one thread does not
+ between messages. Suspending one thread does not
affect other delivery threads.
<b>-w</b> <i>interval</i>
thread does not affect other delivery threads.
[<b>inet:</b>]<i>host</i>[:<i>port</i>]
- Connect via TCP to host <i>host</i>, port <i>port</i>. The
+ Connect via TCP to host <i>host</i>, port <i>port</i>. The
default port is <b>smtp</b>.
<b>unix:</b><i>pathname</i>
<a href="smtp-sink.1.html">smtp-sink(1)</a>, SMTP/LMTP message dump
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
The network interface addresses that this mail sys-
tem receives mail on.
+ <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
+ The Internet protocols Postfix will attempt to use
+ when making or accepting connections.
+
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
The time limit for sending or receiving information
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for the next service request
+ The maximum amount of time that an idle Postfix
+ daemon process waits for the next service request
before exiting.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon pro-
+ The process ID of a Postfix command or daemon pro-
cess.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
The network interface addresses that this mail sys-
- tem receives mail on by way of a proxy or network
+ tem receives mail on by way of a proxy or network
address translation unit.
<b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
An optional numerical network address that the SMTP
- client should bind to when making a connection.
+ client should bind to when making an IPv4 connec-
+ tion.
+
+ <b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
+ An optional numerical network address that the SMTP
+ client should bind to when making an IPv6 connec-
+ tion.
- <b><a href="postconf.5.html#<a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a>"><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a></a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
+ <b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
The hostname to send in the SMTP EHLO or HELO com-
mand.
tem receives mail on by way of a proxy or network
address translation unit.
+ <b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
+ The Internet protocols Postfix will attempt to use
+ when making or accepting connections.
+
<b><a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> (<a href="proxymap.8.html">proxy</a>:unix:passwd.byname</b>
<b>$<a href="postconf.5.html#alias_maps">alias_maps</a>)</b>
- Lookup tables with all names or addresses of local
- recipients: a recipient address is local when its
- domain matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> or
+ Lookup tables with all names or addresses of local
+ recipients: a recipient address is local when its
+ domain matches $<a href="postconf.5.html#mydestination">mydestination</a>, $<a href="postconf.5.html#inet_interfaces">inet_interfaces</a> or
$<a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a>.
<b><a href="postconf.5.html#unknown_local_recipient_reject_code">unknown_local_recipient_reject_code</a> (550)</b>
- The numerical Postfix SMTP server response code
- when a recipient address is local, and
- $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> specifies a list of lookup
+ The numerical Postfix SMTP server response code
+ when a recipient address is local, and
+ $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a> specifies a list of lookup
tables that does not match the recipient.
- Parameters concerning known/unknown recipients of relay
+ Parameters concerning known/unknown recipients of relay
destinations:
<b><a href="postconf.5.html#relay_domains">relay_domains</a> ($<a href="postconf.5.html#mydestination">mydestination</a>)</b>
- What destination domains (and subdomains thereof)
+ What destination domains (and subdomains thereof)
this system will relay mail to.
<b><a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> (empty)</b>
- Optional lookup tables with all valid addresses in
+ Optional lookup tables with all valid addresses in
the domains that match $<a href="postconf.5.html#relay_domains">relay_domains</a>.
<b><a href="postconf.5.html#unknown_relay_recipient_reject_code">unknown_relay_recipient_reject_code</a> (550)</b>
The numerical Postfix SMTP server reply code when a
- recipient address matches $<a href="postconf.5.html#relay_domains">relay_domains</a>, and
- <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> specifies a list of lookup
+ recipient address matches $<a href="postconf.5.html#relay_domains">relay_domains</a>, and
+ <a href="postconf.5.html#relay_recipient_maps">relay_recipient_maps</a> specifies a list of lookup
tables that does not match the recipient address.
- Parameters concerning known/unknown recipients in virtual
+ Parameters concerning known/unknown recipients in virtual
alias domains:
<b><a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a> ($<a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a>)</b>
Postfix is final destination for the specified list
- of virtual alias domains, that is, domains for
- which all addresses are aliased to addresses in
+ of virtual alias domains, that is, domains for
+ which all addresses are aliased to addresses in
other local or remote domains.
<b><a href="postconf.5.html#virtual_alias_maps">virtual_alias_maps</a> ($<a href="postconf.5.html#virtual_maps">virtual_maps</a>)</b>
- Optional lookup tables that alias specific mail
- addresses or domains to other local or remote
+ Optional lookup tables that alias specific mail
+ addresses or domains to other local or remote
address.
<b><a href="postconf.5.html#unknown_virtual_alias_reject_code">unknown_virtual_alias_reject_code</a> (550)</b>
The SMTP server reply code when a recipient address
- matches $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>, and $<a href="postconf.5.html#virtual_alias_maps">vir</a>-
- <a href="postconf.5.html#virtual_alias_maps">tual_alias_maps</a> specifies a list of lookup tables
+ matches $<a href="postconf.5.html#virtual_alias_domains">virtual_alias_domains</a>, and $<a href="postconf.5.html#virtual_alias_maps">vir</a>-
+ <a href="postconf.5.html#virtual_alias_maps">tual_alias_maps</a> specifies a list of lookup tables
that does not match the recipient address.
- Parameters concerning known/unknown recipients in virtual
+ Parameters concerning known/unknown recipients in virtual
mailbox domains:
<b><a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a> ($<a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a>)</b>
Postfix is final destination for the specified list
- of domains; mail is delivered via the $<a href="postconf.5.html#virtual_transport">vir</a>-
+ of domains; mail is delivered via the $<a href="postconf.5.html#virtual_transport">vir</a>-
<a href="postconf.5.html#virtual_transport">tual_transport</a> mail delivery transport.
<b><a href="postconf.5.html#virtual_mailbox_maps">virtual_mailbox_maps</a> (empty)</b>
- Optional lookup tables with all valid addresses in
+ Optional lookup tables with all valid addresses in
the domains that match $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>.
<b><a href="postconf.5.html#unknown_virtual_mailbox_reject_code">unknown_virtual_mailbox_reject_code</a> (550)</b>
The SMTP server reply code when a recipient address
- matches $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>, and $<a href="postconf.5.html#virtual_mailbox_maps">vir</a>-
+ matches $<a href="postconf.5.html#virtual_mailbox_domains">virtual_mailbox_domains</a>, and $<a href="postconf.5.html#virtual_mailbox_maps">vir</a>-
<a href="postconf.5.html#virtual_mailbox_maps">tual_mailbox_maps</a> specifies a list of lookup tables
that does not match the recipient address.
<b>RESOURCE AND RATE CONTROLS</b>
- The following parameters limit resource usage by the SMTP
+ The following parameters limit resource usage by the SMTP
server and/or control client request rates.
<b><a href="postconf.5.html#line_length_limit">line_length_limit</a> (2048)</b>
- Upon input, long lines are chopped up into pieces
- of at most this length; upon delivery, long lines
+ Upon input, long lines are chopped up into pieces
+ of at most this length; upon delivery, long lines
are reconstructed.
<b><a href="postconf.5.html#queue_minfree">queue_minfree</a> (0)</b>
- The minimal amount of free space in bytes in the
+ The minimal amount of free space in bytes in the
queue file system that is needed to receive mail.
<b><a href="postconf.5.html#message_size_limit">message_size_limit</a> (10240000)</b>
- The maximal size in bytes of a message, including
+ The maximal size in bytes of a message, including
envelope information.
<b><a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a> (1000)</b>
- The maximal number of recipients that the Postfix
+ The maximal number of recipients that the Postfix
SMTP server accepts per message delivery request.
<b><a href="postconf.5.html#smtpd_timeout">smtpd_timeout</a> (300s)</b>
- The time limit for sending a Postfix SMTP server
- response and for receiving a remote SMTP client
+ The time limit for sending a Postfix SMTP server
+ response and for receiving a remote SMTP client
request.
<b><a href="postconf.5.html#smtpd_history_flush_threshold">smtpd_history_flush_threshold</a> (100)</b>
- The maximal number of lines in the Postfix SMTP
- server command history before it is flushed upon
+ The maximal number of lines in the Postfix SMTP
+ server command history before it is flushed upon
receipt of EHLO, RSET, or end of DATA.
The per SMTP client connection count and request rate lim-
its are implemented in co-operation with the <a href="anvil.8.html">anvil(8)</a> ser-
- vice, and are available in Postfix version 2.2 and later.
+ vice, and are available in Postfix version 2.2 and later.
<b><a href="postconf.5.html#smtpd_client_connection_count_limit">smtpd_client_connection_count_limit</a> (50)</b>
- How many simultaneous connections any client is
+ How many simultaneous connections any client is
allowed to make to this service.
<b><a href="postconf.5.html#smtpd_client_connection_rate_limit">smtpd_client_connection_rate_limit</a> (0)</b>
The maximal number of connection attempts any
- client is allowed to make to this service per time
+ client is allowed to make to this service per time
unit.
<b><a href="postconf.5.html#smtpd_client_message_rate_limit">smtpd_client_message_rate_limit</a> (0)</b>
- The maximal number of message delivery requests
- that any client is allowed to make to this service
+ The maximal number of message delivery requests
+ that any client is allowed to make to this service
per time unit, regardless of whether or not Postfix
actually accepts those messages.
<b><a href="postconf.5.html#smtpd_client_recipient_rate_limit">smtpd_client_recipient_rate_limit</a> (0)</b>
- The maximal number of recipient addresses that any
- client is allowed to send to this service per time
+ The maximal number of recipient addresses that any
+ client is allowed to send to this service per time
unit, regardless of whether or not Postfix actually
accepts those recipients.
<b><a href="postconf.5.html#smtpd_client_event_limit_exceptions">smtpd_client_event_limit_exceptions</a> ($<a href="postconf.5.html#mynetworks">mynetworks</a>)</b>
- Clients that are excluded from connection count,
- connection rate, message rate or recipient rate
+ Clients that are excluded from connection count,
+ connection rate, message rate or recipient rate
restrictions.
<b>TARPIT CONTROLS</b>
- When a remote SMTP client makes errors, the Postfix SMTP
- server can insert delays before responding. This can help
- to slow down run-away software. The behavior is con-
- trolled by an error counter that counts the number of
- errors within an SMTP session that a client makes without
+ When a remote SMTP client makes errors, the Postfix SMTP
+ server can insert delays before responding. This can help
+ to slow down run-away software. The behavior is con-
+ trolled by an error counter that counts the number of
+ errors within an SMTP session that a client makes without
delivering mail.
<b><a href="postconf.5.html#smtpd_error_sleep_time">smtpd_error_sleep_time</a> (1s)</b>
- With Postfix 2.1 and later: the SMTP server
- response delay after a client has made more than
- $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a> errors, and fewer than
- $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> errors, without delivering
+ With Postfix 2.1 and later: the SMTP server
+ response delay after a client has made more than
+ $<a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a> errors, and fewer than
+ $<a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> errors, without delivering
mail.
<b><a href="postconf.5.html#smtpd_soft_error_limit">smtpd_soft_error_limit</a> (10)</b>
- The number of errors a remote SMTP client is
- allowed to make without delivering mail before the
+ The number of errors a remote SMTP client is
+ allowed to make without delivering mail before the
Postfix SMTP server slows down all its responses.
<b><a href="postconf.5.html#smtpd_hard_error_limit">smtpd_hard_error_limit</a> (20)</b>
- The maximal number of errors a remote SMTP client
+ The maximal number of errors a remote SMTP client
is allowed to make without delivering mail.
<b><a href="postconf.5.html#smtpd_junk_command_limit">smtpd_junk_command_limit</a> (100)</b>
- The number of junk commands (NOOP, VRFY, ETRN or
+ The number of junk commands (NOOP, VRFY, ETRN or
RSET) that a remote SMTP client can send before the
- Postfix SMTP server starts to increment the error
+ Postfix SMTP server starts to increment the error
counter with each junk command.
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#smtpd_recipient_overshoot_limit">smtpd_recipient_overshoot_limit</a> (1000)</b>
- The number of recipients that a remote SMTP client
- can send in excess of the limit specified with
+ The number of recipients that a remote SMTP client
+ can send in excess of the limit specified with
$<a href="postconf.5.html#smtpd_recipient_limit">smtpd_recipient_limit</a>, before the Postfix SMTP
- server increments the per-session error count for
+ server increments the per-session error count for
each excess recipient.
<b>ACCESS POLICY DELEGATION CONTROLS</b>
- As of version 2.1, Postfix can be configured to delegate
- access policy decisions to an external server that runs
- outside Postfix. See the file <a href="SMTPD_POLICY_README.html">SMTPD_POLICY_README</a> for
+ As of version 2.1, Postfix can be configured to delegate
+ access policy decisions to an external server that runs
+ outside Postfix. See the file <a href="SMTPD_POLICY_README.html">SMTPD_POLICY_README</a> for
more information.
<b><a href="postconf.5.html#smtpd_policy_service_max_idle">smtpd_policy_service_max_idle</a> (300s)</b>
- The time after which an idle SMTPD policy service
+ The time after which an idle SMTPD policy service
connection is closed.
<b><a href="postconf.5.html#smtpd_policy_service_max_ttl">smtpd_policy_service_max_ttl</a> (1000s)</b>
connection is closed.
<b><a href="postconf.5.html#smtpd_policy_service_timeout">smtpd_policy_service_timeout</a> (100s)</b>
- The time limit for connecting to, writing to or
+ The time limit for connecting to, writing to or
receiving from a delegated SMTPD policy server.
<b>ACCESS CONTROLS</b>
- The <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction to
+ The <a href="SMTPD_ACCESS_README.html">SMTPD_ACCESS_README</a> document gives an introduction to
all the SMTP server access control features.
<b><a href="postconf.5.html#smtpd_delay_reject">smtpd_delay_reject</a> (yes)</b>
- Wait until the RCPT TO command before evaluating
+ Wait until the RCPT TO command before evaluating
$<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a>, $smtpd_helo_restric-
tions and $<a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a>, or wait until
- the ETRN command before evaluating
+ the ETRN command before evaluating
$<a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> and $smtpd_helo_restric-
tions.
- <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a> (see 'postconf -d' out-</b>
+ <b><a href="postconf.5.html#parent_domain_matches_subdomains">parent_domain_matches_subdomains</a> (see 'postconf -d' out-</b>
<b>put)</b>
What Postfix features match subdomains of
"domain.tld" automatically, instead of requiring an
explicit ".domain.tld" pattern.
<b><a href="postconf.5.html#smtpd_client_restrictions">smtpd_client_restrictions</a> (empty)</b>
- Optional SMTP server access restrictions in the
+ Optional SMTP server access restrictions in the
context of a client SMTP connection request.
<b><a href="postconf.5.html#smtpd_helo_required">smtpd_helo_required</a> (no)</b>
Require that a remote SMTP client introduces itself
- at the beginning of an SMTP session with the HELO
+ at the beginning of an SMTP session with the HELO
or EHLO command.
<b><a href="postconf.5.html#smtpd_helo_restrictions">smtpd_helo_restrictions</a> (empty)</b>
- Optional restrictions that the Postfix SMTP server
+ Optional restrictions that the Postfix SMTP server
applies in the context of the SMTP HELO command.
<b><a href="postconf.5.html#smtpd_sender_restrictions">smtpd_sender_restrictions</a> (empty)</b>
- Optional restrictions that the Postfix SMTP server
+ Optional restrictions that the Postfix SMTP server
applies in the context of the MAIL FROM command.
<b><a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> (<a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a>,</b>
<b><a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a>)</b>
The access restrictions that the Postfix SMTP
- server applies in the context of the RCPT TO com-
+ server applies in the context of the RCPT TO com-
mand.
<b><a href="postconf.5.html#smtpd_etrn_restrictions">smtpd_etrn_restrictions</a> (empty)</b>
- Optional SMTP server access restrictions in the
+ Optional SMTP server access restrictions in the
context of a client ETRN request.
<b><a href="postconf.5.html#allow_untrusted_routing">allow_untrusted_routing</a> (no)</b>
- Forward mail with sender-specified routing
- (user[@%!]remote[@%!]site) from untrusted clients
+ Forward mail with sender-specified routing
+ (user[@%!]remote[@%!]site) from untrusted clients
to destinations matching $<a href="postconf.5.html#relay_domains">relay_domains</a>.
<b><a href="postconf.5.html#smtpd_restriction_classes">smtpd_restriction_classes</a> (empty)</b>
- User-defined aliases for groups of access restric-
+ User-defined aliases for groups of access restric-
tions.
<b><a href="postconf.5.html#smtpd_null_access_lookup_key">smtpd_null_access_lookup_key</a> (</b><><b>)</b>
- The lookup key to be used in SMTP <a href="access.5.html">access(5)</a> tables
+ The lookup key to be used in SMTP <a href="access.5.html">access(5)</a> tables
instead of the null sender address.
<b><a href="postconf.5.html#permit_mx_backup_networks">permit_mx_backup_networks</a> (empty)</b>
Restrict the use of the <a href="postconf.5.html#permit_mx_backup">permit_mx_backup</a> SMTP
- access feature to only domains whose primary MX
+ access feature to only domains whose primary MX
hosts match the listed networks.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#smtpd_data_restrictions">smtpd_data_restrictions</a> (empty)</b>
- Optional access restrictions that the Postfix SMTP
+ Optional access restrictions that the Postfix SMTP
server applies in the context of the SMTP DATA com-
mand.
<b><a href="postconf.5.html#smtpd_expansion_filter">smtpd_expansion_filter</a> (see 'postconf -d' output)</b>
- What characters are allowed in $name expansions of
+ What characters are allowed in $name expansions of
RBL reply templates.
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#smtpd_reject_unlisted_sender">smtpd_reject_unlisted_sender</a> (no)</b>
- Request that the Postfix SMTP server rejects mail
- from unknown sender addresses, even when no
- explicit <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access restriction
+ Request that the Postfix SMTP server rejects mail
+ from unknown sender addresses, even when no
+ explicit <a href="postconf.5.html#reject_unlisted_sender">reject_unlisted_sender</a> access restriction
is specified.
<b><a href="postconf.5.html#smtpd_reject_unlisted_recipient">smtpd_reject_unlisted_recipient</a> (yes)</b>
- Request that the Postfix SMTP server rejects mail
+ Request that the Postfix SMTP server rejects mail
for unknown recipient addresses, even when no
- explicit <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access restric-
+ explicit <a href="postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a> access restric-
tion is specified.
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtpd_end_of_data_restrictions">smtpd_end_of_data_restrictions</a> (empty)</b>
- Optional access restrictions that the Postfix SMTP
- server applies in the context of the SMTP END-OF-
+ Optional access restrictions that the Postfix SMTP
+ server applies in the context of the SMTP END-OF-
DATA command.
<b>SENDER AND RECIPIENT ADDRESS VERIFICATION CONTROLS</b>
- Postfix version 2.1 introduces sender and recipient
- address verification. This feature is implemented by
- sending probe email messages that are not actually deliv-
- ered. This feature is requested via the <a href="postconf.5.html#reject_unverified_sender">reject_unveri</a>-
- <a href="postconf.5.html#reject_unverified_sender">fied_sender</a> and <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a> access
- restrictions. The status of verification probes is main-
+ Postfix version 2.1 introduces sender and recipient
+ address verification. This feature is implemented by
+ sending probe email messages that are not actually deliv-
+ ered. This feature is requested via the <a href="postconf.5.html#reject_unverified_sender">reject_unveri</a>-
+ <a href="postconf.5.html#reject_unverified_sender">fied_sender</a> and <a href="postconf.5.html#reject_unverified_recipient">reject_unverified_recipient</a> access
+ restrictions. The status of verification probes is main-
tained by the <a href="verify.8.html">verify(8)</a> server. See the file ADDRESS_VER-
- <a href="IFICATION_README.html">IFICATION_README</a> for information about how to configure
+ <a href="IFICATION_README.html">IFICATION_README</a> for information about how to configure
and operate the Postfix sender/recipient address verifica-
tion service.
<b><a href="postconf.5.html#address_verify_poll_count">address_verify_poll_count</a> (3)</b>
- How many times to query the <a href="verify.8.html">verify(8)</a> service for
- the completion of an address verification request
+ How many times to query the <a href="verify.8.html">verify(8)</a> service for
+ the completion of an address verification request
in progress.
<b><a href="postconf.5.html#address_verify_poll_delay">address_verify_poll_delay</a> (3s)</b>
- The delay between queries for the completion of an
+ The delay between queries for the completion of an
address verification request in progress.
<b><a href="postconf.5.html#address_verify_sender">address_verify_sender</a> (postmaster)</b>
- The sender address to use in address verification
+ The sender address to use in address verification
probes.
<b><a href="postconf.5.html#unverified_sender_reject_code">unverified_sender_reject_code</a> (450)</b>
- The numerical Postfix SMTP server response code
- when a recipient address is rejected by the
+ The numerical Postfix SMTP server response code
+ when a recipient address is rejected by the
<a href="postconf.5.html#reject_unverified_sender">reject_unverified_sender</a> restriction.
<b><a href="postconf.5.html#unverified_recipient_reject_code">unverified_recipient_reject_code</a> (450)</b>
- The numerical Postfix SMTP server response when a
+ The numerical Postfix SMTP server response when a
recipient address is rejected by the <a href="postconf.5.html#reject_unverified_recipient">reject_unveri</a>-
<a href="postconf.5.html#reject_unverified_recipient">fied_recipient</a> restriction.
<b>ACCESS CONTROL RESPONSES</b>
- The following parameters control numerical SMTP reply
+ The following parameters control numerical SMTP reply
codes and/or text responses.
<b><a href="postconf.5.html#access_map_reject_code">access_map_reject_code</a> (554)</b>
- The numerical Postfix SMTP server response code
- when a client is rejected by an <a href="access.5.html">access(5)</a> map
+ The numerical Postfix SMTP server response code
+ when a client is rejected by an <a href="access.5.html">access(5)</a> map
restriction.
<b><a href="postconf.5.html#defer_code">defer_code</a> (450)</b>
- The numerical Postfix SMTP server response code
- when a remote SMTP client request is rejected by
+ The numerical Postfix SMTP server response code
+ when a remote SMTP client request is rejected by
the "defer" restriction.
<b><a href="postconf.5.html#invalid_hostname_reject_code">invalid_hostname_reject_code</a> (501)</b>
- The numerical Postfix SMTP server response code
- when the client HELO or EHLO command parameter is
- rejected by the <a href="postconf.5.html#reject_invalid_hostname">reject_invalid_hostname</a> restric-
+ The numerical Postfix SMTP server response code
+ when the client HELO or EHLO command parameter is
+ rejected by the <a href="postconf.5.html#reject_invalid_hostname">reject_invalid_hostname</a> restric-
tion.
<b><a href="postconf.5.html#maps_rbl_reject_code">maps_rbl_reject_code</a> (554)</b>
- The numerical Postfix SMTP server response code
+ The numerical Postfix SMTP server response code
when a remote SMTP client request is blocked by the
<a href="postconf.5.html#reject_rbl_client">reject_rbl_client</a>, <a href="postconf.5.html#reject_rhsbl_client">reject_rhsbl_client</a>,
<a href="postconf.5.html#reject_rhsbl_sender">reject_rhsbl_sender</a> or <a href="postconf.5.html#reject_rhsbl_recipient">reject_rhsbl_recipient</a>
<b><a href="postconf.5.html#non_fqdn_reject_code">non_fqdn_reject_code</a> (504)</b>
The numerical Postfix SMTP server reply code when a
- client request is rejected by the
+ client request is rejected by the
<a href="postconf.5.html#reject_non_fqdn_hostname">reject_non_fqdn_hostname</a>, <a href="postconf.5.html#reject_non_fqdn_sender">reject_non_fqdn_sender</a> or
<a href="postconf.5.html#reject_non_fqdn_recipient">reject_non_fqdn_recipient</a> restriction.
<b><a href="postconf.5.html#reject_code">reject_code</a> (554)</b>
- The numerical Postfix SMTP server response code
- when a remote SMTP client request is rejected by
+ The numerical Postfix SMTP server response code
+ when a remote SMTP client request is rejected by
the "<b>reject</b>" restriction.
<b><a href="postconf.5.html#relay_domains_reject_code">relay_domains_reject_code</a> (554)</b>
- The numerical Postfix SMTP server response code
- when a client request is rejected by the
+ The numerical Postfix SMTP server response code
+ when a client request is rejected by the
<a href="postconf.5.html#reject_unauth_destination">reject_unauth_destination</a> recipient restriction.
<b><a href="postconf.5.html#unknown_address_reject_code">unknown_address_reject_code</a> (450)</b>
- The numerical Postfix SMTP server response code
- when a sender or recipient address is rejected by
+ The numerical Postfix SMTP server response code
+ when a sender or recipient address is rejected by
the <a href="postconf.5.html#reject_unknown_sender_domain">reject_unknown_sender_domain</a> or
<a href="postconf.5.html#reject_unknown_recipient_domain">reject_unknown_recipient_domain</a> restriction.
<b><a href="postconf.5.html#unknown_client_reject_code">unknown_client_reject_code</a> (450)</b>
- The numerical Postfix SMTP server response code
- when a client without valid address <=> name map-
- ping is rejected by the <a href="postconf.5.html#reject_unknown_client">reject_unknown_client</a>
+ The numerical Postfix SMTP server response code
+ when a client without valid address <=> name map-
+ ping is rejected by the <a href="postconf.5.html#reject_unknown_client">reject_unknown_client</a>
restriction.
<b><a href="postconf.5.html#unknown_hostname_reject_code">unknown_hostname_reject_code</a> (450)</b>
- The numerical Postfix SMTP server response code
- when the hostname specified with the HELO or EHLO
- command is rejected by the <a href="postconf.5.html#reject_unknown_hostname">reject_unknown_hostname</a>
+ The numerical Postfix SMTP server response code
+ when the hostname specified with the HELO or EHLO
+ command is rejected by the <a href="postconf.5.html#reject_unknown_hostname">reject_unknown_hostname</a>
restriction.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#default_rbl_reply">default_rbl_reply</a> (see 'postconf -d' output)</b>
- The default SMTP server response template for a
- request that is rejected by an RBL-based restric-
+ The default SMTP server response template for a
+ request that is rejected by an RBL-based restric-
tion.
<b><a href="postconf.5.html#multi_recipient_bounce_reject_code">multi_recipient_bounce_reject_code</a> (550)</b>
- The numerical Postfix SMTP server response code
+ The numerical Postfix SMTP server response code
when a remote SMTP client request is blocked by the
<a href="postconf.5.html#reject_multi_recipient_bounce">reject_multi_recipient_bounce</a> restriction.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#command_directory">command_directory</a> (see 'postconf -d' output)</b>
- The location of all postfix administrative com-
+ The location of all postfix administrative com-
mands.
<b><a href="postconf.5.html#double_bounce_sender">double_bounce_sender</a> (double-bounce)</b>
and most Postfix daemon processes.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for the next service request
+ The maximum amount of time that an idle Postfix
+ daemon process waits for the next service request
before exiting.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
<b><a href="postconf.5.html#myhostname">myhostname</a> (see 'postconf -d' output)</b>
The internet hostname of this mail system.
<b><a href="postconf.5.html#mynetworks">mynetworks</a> (see 'postconf -d' output)</b>
- The list of "trusted" SMTP clients that have more
+ The list of "trusted" SMTP clients that have more
privileges than "strangers".
<b><a href="postconf.5.html#myorigin">myorigin</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
The domain name that locally-posted mail appears to
- come from, and that locally posted mail is deliv-
+ come from, and that locally posted mail is deliv-
ered to.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon pro-
+ The process ID of a Postfix command or daemon pro-
cess.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
- The location of the Postfix top-level queue direc-
+ The location of the Postfix top-level queue direc-
tory.
<b><a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> (empty)</b>
sions (user+foo).
<b><a href="postconf.5.html#smtpd_banner">smtpd_banner</a> ($<a href="postconf.5.html#myhostname">myhostname</a> ESMTP $<a href="postconf.5.html#mail_name">mail_name</a>)</b>
- The text that follows the 220 status code in the
+ The text that follows the 220 status code in the
SMTP greeting banner.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the pro-
+ The mail system name that is prepended to the pro-
cess name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtpd_forbidden_commands">smtpd_forbidden_commands</a> (CONNECT, GET, POST)</b>
- List of commands that causes the Postfix SMTP
- server to immediately terminate the session with a
+ List of commands that causes the Postfix SMTP
+ server to immediately terminate the session with a
221 code.
<b>SEE ALSO</b>
<a href="XFORWARD_README.html">XFORWARD_README</a>, Postfix XFORWARD extension
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
# Use the native compiler by default
: ${CC=cc}
: ${DEBUG="-g3"}
+ case $RELEASE in
+ V[0-4].*) CCARGS="$CCARGS -DNO_IPV6";;
+ esac
;;
SunOS.4*) SYSTYPE=SUNOS4
SYSLIBS=-lresolv
SunOS.5*) SYSTYPE=SUNOS5
RANLIB=echo
SYSLIBS="-lresolv -lsocket -lnsl"
+ # Solaris 8 added usleep() and POSIX regular expressions
case $RELEASE in
- 5.[0-4]) CCARGS="$CCARGS -DMISSING_USLEEP";;
- *) CCARGS="$CCARGS -DHAS_POSIX_REGEXP";;
+ 5.[0-4]) CCARGS="$CCARGS -DMISSING_USLEEP -DNO_POSIX_REGEXP";;
+ esac
+ # Solaris 8 added IPv6
+ case $RELEASE in
+ 5.[0-7]) CCARGS="$CCARGS -DNO_IPV6";;
esac
- CCARGS="$CCARGS -DCANT_WRITE_BEFORE_SENDING_FD"
# Solaris 9 added closefrom()
case $RELEASE in
- 5.9*|5.[1-9][0-9]*) CCARGS="$CCARGS -DHAS_CLOSEFROM";;
+ 5.[0-8]) CCARGS="$CCARGS -DNO_CLOSEFROM";;
esac
# Work around broken str*casecmp(). Do it all here instead
# of having half the solution in the sys_defs.h file.
}
done
done
+ case "$RELEASE" in
+ 2.[0-3].*) CCARGS="$CCARGS -DNO_IPV6";;
+ esac
;;
IRIX*.5.*) SYSTYPE=IRIX5
# Use the native compiler by default
: ${CC=cc}
case $RELEASE in
1.[0-3]) AWK=gawk
+ CCARGS="$CCARGS -DNO_IPV6"
;;
[2-6].*) AWK=awk
+ CCARGS="$CCARGS -DNO_IPV6"
SYSLIBS=-flat_namespace
;;
*) AWK=awk
.RE
.IP "\fB-s \fIsite\fR"
Schedule immediate delivery of all mail that is queued for the named
-\fIsite\fR. The site must be eligible for the "fast flush" service.
+\fIsite\fR. A numerical site must be specified as a valid RFC 2821
+address literal enclosed in [], just like in email addresses.
+The site must be eligible for the "fast flush" service.
See \fBflush\fR(8) for more information about the "fast flush"
service.
.na
.nf
.fi
-\fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
+\fBqmqp-sink\fR [\fB-46cv\fR] [\fB-x \fItime\fR]
[\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR
-\fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
+\fBqmqp-sink\fR [\fB-46cv\fR] [\fB-x \fItime\fR]
\fBunix:\fR\fIpathname\fR \fIbacklog\fR
.SH DESCRIPTION
.ad
It receives messages from the network and throws them away.
The purpose is to measure QMQP client performance, not protocol
compliance.
-Connections can be accepted on IPV4 endpoints or UNIX-domain sockets.
-IPV4 is the default.
+Connections can be accepted on IPv4 or IPv6 endpoints, or on
+UNIX-domain sockets.
+IPv4 and IPv6 are the default.
This program is the complement of the \fBqmqp-source\fR(1) program.
+.IP \fB-4\fR
+Support IPv4 only. This option has no effect when
+Postfix is built without IPv6 support.
+.IP \fB-6\fR
+Support IPv6 only. This option is not available when
+Postfix is built without IPv6 support.
.IP \fB-c\fR
Display a running counter that is updated whenever a delivery
is completed.
\fBqmqp-source\fR connects to the named host and TCP port (default 628)
and sends one or more messages to it, either sequentially
or in parallel. The program speaks the QMQP protocol.
-Connections can be made to UNIX-domain and IPV4 servers.
-IPV4 is the default.
+Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
+IPv4 and IPv6 are the default.
Options:
+.IP \fB-4\fR
+Connect to the server with IPv4. This option has no effect when
+Postfix is built without IPv6 support.
+.IP \fB-6\fR
+Connect to the server with IPv6. This option is not available when
+Postfix is built without IPv6 support.
.IP \fB-c\fR
Display a running counter that is incremented each time
a delivery completes.
Non-default alias database. Specify \fIpathname\fR or
\fItype\fR:\fIpathname\fR. See \fBpostalias\fR(1) for
details.
+.IP "\fB-O \fIoption=value\fR (ignored)"
+Backwards compatibility.
.IP "\fB-o7\fR (ignored)"
.IP "\fB-o8\fR (ignored)"
To send 8-bit or binary content, use an appropriate MIME encapsulation
The purpose is to measure client performance, not protocol
compliance.
-Connections can be accepted on IPV4 endpoints or UNIX-domain sockets.
-IPV4 is the default.
+Connections can be accepted on IPv4 or IPv6 endpoints, or on
+UNIX-domain sockets.
+IPv4 and IPv6 are the default.
This program is the complement of the \fBsmtp-source\fR(1) program.
Arguments:
+.IP \fB-4\fR
+Support IPv4 only. This option has no effect when
+Postfix is built without IPv6 support.
+.IP \fB-6\fR
+Support IPv6 only. This option is not available when
+Postfix is built without IPv6 support.
.IP \fB-a\fR
Do not announce SASL authentication support.
.IP \fB-c\fR
(default: port 25)
and sends one or more messages to it, either sequentially
or in parallel. The program speaks either SMTP (default) or
-LMTP. Connections can be made to UNIX-domain and IPV4 servers.
-IPV4 is the default.
+LMTP.
+Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
+IPv4 and IPv6 are the default.
Arguments:
+.IP \fB-4\fR
+Connect to the server with IPv4. This option has no effect when
+Postfix is built without IPv6 support.
+.IP \fB-6\fR
+Connect to the server with IPv6. This option is not available when
+Postfix is built without IPv6 support.
.IP \fB-c\fR
Display a running counter that is incremented each time
an SMTP DATA command completes.
The optional \fBaccess\fR table directs the Postfix SMTP server
to selectively reject or accept mail. Access can be allowed or
denied for specific host names, domain names, networks, host
-network addresses or mail addresses.
+addresses or mail addresses.
For an example, see the EXAMPLE section at the end of this
manual page.
.IP \fInet.work.addr\fR
.IP \fInet.work\fR
.IP \fInet\fR
-Matches any host address in the specified network. A network
-address is a sequence of one or more octets separated by ".".
+Matches the specified IPv4 host address or subnetwork. An
+IPv4 host address is a sequence of four decimal octets
+separated by ".".
-NOTE: use the \fBcidr\fR lookup table type to specify
+Subnetworks are matched by repeatedly truncating the last
+".octet" from the remote IPv4 host address string until a
+match is found in the access table, or until further
+truncation is not possible.
+
+NOTE 1: The information in the access map should be in
+canonical form, with unnecessary null characters eliminated.
+Address information must not be enclosed with "[]" characters.
+
+NOTE 2: use the \fBcidr\fR lookup table type to specify
network/netmask patterns. See cidr_table(5) for details.
+.IP \fInet:work:addr:ess\fR
+.IP \fInet:work:addr\fR
+.IP \fInet:work\fR
+.IP \fInet\fR
+Matches the specified IPv6 host address or subnetwork. An
+IPv6 host address is a sequence of three to eight hexadecimal
+octet pairs separated by ":".
+
+Subnetworks are matched by repeatedly truncating the last
+":octetpair" from the remote IPv6 host address string until
+a match is found in the access table, or until further
+truncation is not possible.
+
+NOTE 1: the truncation and comparison are done with the
+string representation of the IPv6 host address. Thus, not
+all the ":" subnetworks will be tried.
+
+NOTE 2: The information in the access map should be in
+canonical form, with unnecessary null characters eliminated.
+Address information must not be enclosed with "[]" characters.
+
+NOTE 3: use the \fBcidr\fR lookup table type to specify
+network/netmask patterns. See cidr_table(5) for details.
+
+IPv6 support is available in Postfix 2.2 and later.
.SH "ACCEPT ACTIONS"
.na
.nf
.IP "\fInetwork_address\fB/\fInetwork_mask result\fR"
When a search string matches the specified network block,
use the corresponding \fIresult\fR value. Specify
-0.0.0.0/0 to match every address.
+0.0.0.0/0 to match every IPv4 address, and ::/0 to match
+every IPv6 address.
+
+Note: address information may be enclosed inside "[]" but
+this form is not recommended.
+
+IPv6 support is available in Postfix 2.2 and later.
.IP "\fInetwork_address result\fR"
When a search string matches the specified network address,
use the corresponding \fIresult\fR value.
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
with whitespace.
+.PP
+Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the authorized_verp_clients value, and in files
+specified with "/file/name". IP version 6 addresses contain the
+":" character, and would otherwise be confused with a "type:table"
+pattern.
.SH backwards_bounce_logfile_compatibility (default: yes)
Produce additional bounce(8) logfile records that can be read by
older Postfix versions. The current and more extensible "name =
.PP
After changing the hash_queue_names or hash_queue_depth parameter,
execute the command "\fBpostfix reload\fR".
-.SH hash_queue_names (default: see "postconf -d" output)
+.SH hash_queue_names (default: deferred, defer)
The names of queue directories that are split across multiple
subdirectory levels.
.PP
+Before Postfix version 2.2, the default list of hashed queues
+was significantly larger. Claims about improvements in file system
+technology suggest that hashing of the incoming and active queues
+is no longer needed. Fewer hashed directories speed up the time
+needed to restart Postfix.
+.PP
After changing the hash_queue_names or hash_queue_depth parameter,
execute the command "\fBpostfix reload\fR".
.SH header_address_token_limit (default: 10240)
.PP
Specify 0 to disable the feature. Valid delays are 0..10.
.SH inet_interfaces (default: all)
-The network interface addresses that this mail system receives mail
-on. By default, the software claims all active interfaces on the
-machine. The parameter also controls delivery of mail to
-user@[ip.address].
+The network interface addresses that this mail system receives
+mail on. By default, the software claims all active interfaces on
+the machine; with Postfix 2.2 and later, specify "\fBloopback-only\fR"
+to select only local interfaces. The parameter also controls
+delivery of mail to user@[ip.address].
.PP
-When inet_interfaces consists of just one IP address that is not a
-loopback (net 127) address, the Postfix SMTP client will use this address
-as the IP source address for outbound mail.
+Note: you need to stop and start Postfix when this parameter changes.
+.PP
+When inet_interfaces specifies just one IPv4 and/or IPv6 address
+that is not a loopback address, the Postfix SMTP client will use
+this address as the IP source address for outbound mail.
.PP
On a multi-homed firewall with separate Postfix instances listening on the
"inside" and "outside" interfaces, this can prevent each instance from
being able to reach servers on the "other side" of the firewall. Setting
-smtp_bind_address to 0.0.0.0 avoids the potential problem.
+smtp_bind_address to 0.0.0.0 avoids the potential problem for
+IPv4, and setting smtp_bind_address6 to :: solves the problem
+for IPv6.
.PP
-A better solution is to leave inet_interfaces at the default value
+A better solution for multi-homed firewalls is to leave inet_interfaces
+at the default value
and instead use explicit IP addresses in master.cf. This preserves SMTP
loop detection, by ensuring that each side of the firewall knows that the
other IP address is still the same host. Setting $inet_interfaces to a
-single IP address is primarily useful with virtual hosting of domains on
+single IPv4 and/or IPV6 address is primarily useful with virtual
+hosting of domains on
secondary IP addresses, when each IP address serves a different domain
(and has a different $myhostname setting).
.PP
See also the proxy_interfaces parameter, for network addresses that
-are forwarded to us by way of a proxy or address translator.
+are forwarded to Postfix by way of a proxy or address translator.
.PP
-Note: you need to stop and start Postfix when this parameter changes.
+Examples:
+.PP
+.nf
+.na
+.ft C
+inet_interfaces = all (DEFAULT)
+inet_interfaces = loopback-only
+inet_interfaces = 127.0.0.1
+inet_interfaces = 192.168.1.2, 127.0.0.1
+.fi
+.ad
+.ft R
+.SH inet_protocols (default: ipv4)
+The Internet protocols Postfix will attempt to use when making
+or accepting connections. Specify one or more of "ipv4" or "ipv6",
+separated by whitespace or commas. The form "all" is equivalent to
+"ipv4, ipv6".
+.PP
+Note: you MUST stop and start Postfix after changing this
+parameter.
+.PP
+On systems that pre-date IPV6_V6ONLY support (RFC 3493), an
+IPv6 server will also accept IPv4 connections, even when IPv4 is
+turned off with the inet_protocols parameter. On systems with
+IPV6_V6ONLY support, Postfix will use separate server sockets for
+IPv6 and IPv4, and each will accept only connections for the
+corresponding protocol.
+.PP
+When IPv4 support is enabled via the inet_protocols parameter,
+Postfix will to DNS type A record lookups, and will convert
+IPv4-in-IPv6 client IP addresses (::ffff:1.2.3.4) to their original
+IPv4 form (1.2.3.4). The latter is needed on hosts that pre-date
+IPV6_V6ONLY support (RFC 3493).
+.PP
+When IPv6 support is enabled via the inet_protocols parameter,
+Postfix will do DNS type AAAA record lookups.
+.PP
+When both IPv4 and IPv6 support are enabled, the Postfix SMTP
+client will attempt to connect via IPv6 before attempting to use
+IPv4.
+.PP
+This feature is available in Postfix version 2.2 and later.
+.PP
+Examples:
+.PP
+.nf
+.na
+.ft C
+inet_protocols = ipv4 (DEFAULT)
+inet_protocols = all
+inet_protocols = ipv6
+inet_protocols = ipv4, ipv6
+.fi
+.ad
+.ft R
.SH initial_destination_concurrency (default: 5)
The initial per-destination concurrency level for parallel delivery
to the same destination. This limit applies to delivery via smtp(8),
first match. Specify "!pattern" to exclude an address or network
block from the list.
.PP
+Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the mynetworks value, and in files specified with
+"/file/name". IP version 6 addresses contain the ":" character,
+and would otherwise be confused with a "type:table" pattern.
+.PP
Examples:
.PP
.nf
.na
.ft C
-mynetworks = 168.100.189.0/28, 127.0.0.0/8
+mynetworks = 127.0.0.0/8 168.100.189.0/28
mynetworks = !192.168.0.1, 192.168.0.0/28
+mynetworks = 127.0.0.0/8 168.100.189.0/28 [::1]/128 [2001:240:5c7::]/64
mynetworks = $config_directory/mynetworks
mynetworks = hash:/etc/postfix/network_table
.fi
220 spike.porcupine.org ESMTP Postfix).
.SH smtp_bind_address (default: empty)
An optional numerical network address that the SMTP client should
-bind to when making a connection.
+bind to when making an IPv4 connection.
.PP
This can be specified in the main.cf file for all SMTP clients, or
it can be specified in the master.cf file for a specific client,
.ad
.ft R
.PP
-Note: when inet_interfaces specifies exactly one address that
-is a non-loopback address, it is automatically used as the
-smtp_bind_address. This supports virtual IP hosting, but can be
-a problem on multi-homed firewalls. See the inet_interfaces
-documentation for more detail.
+Note 1: when inet_interfaces specifies no more than one IPv4
+address, and that address is a non-loopback address, it is
+automatically used as the smtp_bind_address. This supports virtual
+IP hosting, but can be a problem on multi-homed firewalls. See the
+inet_interfaces documentation for more detail.
+.PP
+Note 2: address information may be enclosed inside <tt>[]</tt>,
+but this form is not recommended.
+.SH smtp_bind_address6 (default: empty)
+An optional numerical network address that the SMTP client should
+bind to when making an IPv6 connection.
+.PP
+This can be specified in the main.cf file for all SMTP clients, or
+it can be specified in the master.cf file for a specific client,
+for example:
+.PP
+.nf
+.na
+.ft C
+ /etc/postfix/master.cf:
+ smtp ... smtp -o smtp_bind_address6=1:2:3:4:5:6:7:8
+.fi
+.ad
+.ft R
+.PP
+Note 1: when inet_interfaces specifies no more than one IPv6
+address, and that address is a non-loopback address, it is
+automatically used as the smtp_bind_address6. This supports virtual
+IP hosting, but can be a problem on multi-homed firewalls. See the
+inet_interfaces documentation for more detail.
+.PP
+Note 2: address information may be enclosed inside <tt>[]</tt>,
+but this form is not recommended.
+.PP
+This feature is available in Postfix version 2.2 and later.
.SH smtp_connect_timeout (default: 30s)
The SMTP client time limit for completing a TCP connection, or
zero (use the operating system built-in time limit).
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
with whitespace.
+.PP
+Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_authorized_verp_clients value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern.
.SH smtpd_authorized_xclient_hosts (default: empty)
What SMTP clients are allowed to use the XCLIENT feature. This
command overrides SMTP client information that is used for access
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
with whitespace.
+.PP
+Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_authorized_xclient_hosts value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern.
.SH smtpd_authorized_xforward_hosts (default: empty)
What SMTP clients are allowed to use the XFORWARD feature. This
command forwards information that is used to improve logging after
is matched when a table entry matches a lookup string (the lookup
result is ignored). Continue long lines by starting the next line
with whitespace.
+.PP
+Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_authorized_xforward_hosts value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern.
.SH smtpd_banner (default: $myhostname ESMTP $mail_name)
The text that follows the 220 status code in the SMTP greeting
banner. Some people like to see the mail version advertised. By
list of network blocks, hostnames or .domain names (the initial
dot causes the domain to match any name below it).
.PP
+Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_client_event_limit_exceptions value, and
+in files specified with "/file/name". IP version 6 addresses
+contain the ":" character, and would otherwise be confused with a
+"type:table" pattern.
+.PP
This feature is available in Postfix 2.2 and later.
.SH smtpd_client_message_rate_limit (default: 0)
The maximal number of message delivery requests that any client is
matches a lookup string (the lookup result is ignored). Continue
long lines by starting the next line with whitespace.
.PP
+Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_sasl_exceptions_networks value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern.
+.PP
Example:
.PP
.nf
Optional lookup tables with a) names of domains for which all
addresses are aliased to addresses in other local or remote domains,
and b) addresses that are aliased to addresses in other local or
-remote domains. Available before Postfix version 2.0. With Postfix 2.1
+remote domains. Available before Postfix version 2.0. With Postfix 2.0
and later, this is replaced by separate controls: virtual_alias_domains
and virtual_alias_maps.
.SH virtual_minimum_uid (default: 100)
.nf
.ad
.fi
-.IP "\fBdaemon_timeout (18000s)\fR"
-How much time a Postfix daemon process may take to handle a
-request before it is terminated by a built-in watchdog timer.
.IP "\fBdefault_process_limit (100)\fR"
The default maximal number of Postfix child processes that provide
a given service.
.IP "\fBinet_interfaces (all)\fR"
The network interface addresses that this mail system receives mail
on.
+.IP "\fBinet_protocols (ipv4)\fR"
+The Internet protocols Postfix will attempt to use when making
+or accepting connections.
.IP "\fBimport_environment (see 'postconf -d' output)\fR"
The list of environment parameters that a Postfix process will
import from a non-Postfix parent process.
it is queued.
.IP "\fBreceive_override_options (empty)\fR"
Enable or disable recipient validation, built-in content
-filtering, or address rewriting.
+filtering, or address mapping.
.SH "RESOURCE AND RATE CONTROLS"
.na
.nf
Optional list of relay hosts for SMTP destinations that can't be
found or that are unreachable.
.IP "\fBinet_interfaces (all)\fR"
-The network interface addresses that this mail system receives mail
-on.
+The network interface addresses that this mail system receives
+mail on.
+.IP "\fBinet_protocols (ipv4)\fR"
+The Internet protocols Postfix will attempt to use when making
+or accepting connections.
.IP "\fBipc_timeout (3600s)\fR"
The time limit for sending or receiving information over an internal
communication channel.
on by way of a proxy or network address translation unit.
.IP "\fBsmtp_bind_address (empty)\fR"
An optional numerical network address that the SMTP client should
-bind to when making a connection.
+bind to when making an IPv4 connection.
+.IP "\fBsmtp_bind_address6 (empty)\fR"
+An optional numerical network address that the SMTP client should
+bind to when making an IPv6 connection.
.IP "\fBsmtp_helo_name ($myhostname)\fR"
The hostname to send in the SMTP EHLO or HELO command.
.IP "\fBsmtp_host_lookup (dns)\fR"
The list of domains that are delivered via the $local_transport
mail delivery transport.
.IP "\fBinet_interfaces (all)\fR"
-The network interface addresses that this mail system receives mail
-on.
+The network interface addresses that this mail system receives
+mail on.
.IP "\fBproxy_interfaces (empty)\fR"
The network interface addresses that this mail system receives mail
on by way of a proxy or network address translation unit.
+.IP "\fBinet_protocols (ipv4)\fR"
+The Internet protocols Postfix will attempt to use when making
+or accepting connections.
.IP "\fBlocal_recipient_maps (proxy:unix:passwd.byname $alias_maps)\fR"
Lookup tables with all names or addresses of local recipients:
a recipient address is local when its domain matches $mydestination,
ERROR=
TROFF=
BCK=
-FLAGS="-st -di8 -npsl -bap -bad -bbb -bc -i4 -d0 -nip -nfc1 -cd41 -c49"
+FLAGS="-st -di8 -npsl -bap -bad -bbb -nbc -i4 -d0 -nip -nfc1 -cd41 -c49"
trap 'rm -f .ind.$$ $TMPF; exit 1' 1 2 3 15
s/<\/*table[^>]*>//g
s/<\/th[^>]*>//g
s/<\/td[^>]*>//g
- s/"\([A-Z_]*\)\.html">/&\1:/
+ s/"\([A-Z0-9_]*\)\.html">/&\1:/
s/All main.cf parameters/postconf(5): &/
/All Postfix manual pages/d
' "$@"
s;\bimport_environment\b;<a href="postconf.5.html#import_environment">$&</a>;g;
s;\bin_flow_delay\b;<a href="postconf.5.html#in_flow_delay">$&</a>;g;
s;\binet_interfaces\b;<a href="postconf.5.html#inet_interfaces">$&</a>;g;
+ s;\binet_protocols\b;<a href="postconf.5.html#inet_protocols">$&</a>;g;
s;\binitial_destination_concurrency\b;<a href="postconf.5.html#initial_destination_concurrency">$&</a>;g;
s;\binvalid_hostname_reject_code\b;<a href="postconf.5.html#invalid_hostname_reject_code">$&</a>;g;
s;\bipc_idle\b;<a href="postconf.5.html#ipc_idle">$&</a>;g;
s;\bshowq_service_name\b;<a href="postconf.5.html#showq_service_name">$&</a>;g;
s;\bsmtp_always_send_ehlo\b;<a href="postconf.5.html#smtp_always_send_ehlo">$&</a>;g;
s;\bsmtp_bind_address\b;<a href="postconf.5.html#smtp_bind_address">$&</a>;g;
+ s;\bsmtp_bind_address6\b;<a href="postconf.5.html#smtp_bind_address6">$&</a>;g;
s;\bsmtp_connect_timeout\b;<a href="postconf.5.html#smtp_connect_timeout">$&</a>;g;
s;\bsmtp_connection_cache_on_demand\b;<a href="postconf.5.html#smtp_connection_cache_on_demand">$&</a>;g;
export_environment
forward_expansion_filter
forward_path
-hash_queue_names
html_directory
import_environment
mail_release_date
# (yes) (yes) (yes) (never) (100)
# =================================================================
1.2.3.5:smtp inet n - n - - smtpd
- -o content_filter=foo:bar
+ -o content_filter=filter-service:filter-destination
-o receive_override_options=no_address_mappings
</pre>
# service type private unpriv chroot wakeup maxproc command
# (yes) (yes) (yes) (never) (100)
# =================================================================
- # SMTP service for domains that are content filtered with foo:bar
+ # SMTP service for domains that are filtered with service1:dest1
1.2.3.4:smtp inet n - n - - smtpd
- -o content_filter=foo:bar
+ -o content_filter=service1:dest1
-o receive_override_options=no_address_mappings
- # SMTP service for domains that are content filtered with xxx:yyy
+ # SMTP service for domains that are filtered with service2:dest2
1.2.3.5:smtp inet n - n - - smtpd
- -o content_filter=xxx:yyy
+ -o content_filter=service2:dest2
-o receive_override_options=no_address_mappings
</pre>
</blockquote>
--- /dev/null
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+<head>
+
+<title>Postfix IPv6 Support</title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix
+IPv6 Support</h1>
+
+<hr>
+
+<h2>Introduction</h2>
+
+<p> Postfix 2.2 introduces support for the IPv6 (IP version 6)
+protocol, whose main feature of interest is that it uses 128-bit
+IP addresses instead of the 32-bit addresses used by IPv4. </p>
+
+<p> With this, Postfix can use the same SMTP protocol over IPv6 as
+it already uses over the older IPv4 network, and Postfix can do
+AAAA record lookups in the DNS in addition to the older A records.
+Information about IPv6 can be found at http://www.ipv6.org/. </p>
+
+<p> This document provides information on the following topics:
+</p>
+
+<ul>
+
+<li><a href="#platforms">Supported platforms</a>
+
+<li><a href="#configuration">Configuration</a>
+
+<li><a href="#limitations">Known limitations</a>
+
+<li><a href="#compat">Compatibility with Postfix <2.2 IPv6 support</a>
+
+<li><a href="#porting">IPv6 Support for unsupported platforms</a>
+
+<li><a href="#credits">Credits</a>
+
+</ul>
+
+<h2><a name="platforms">Supported Platforms</a></h2>
+
+<p> Postfix version 2.2 supports IPv4 and IPv6 on the following
+platforms: </p>
+
+<ul>
+
+<li> AIX 5.1+
+<li> Darwin 7.3+
+<li> FreeBSD 4+
+<li> Linux 2.4+
+<li> NetBSD 1.5+
+<li> OpenBSD 2+
+<li> Solaris 8+
+<li> Tru64Unix V5.1+
+
+</ul>
+
+<p> On other platforms Postfix will simply use IPv4 as it has always
+done. </p>
+
+<p> See <a href="#porting">below</a> for tips how to port Postfix
+IPv6 support to other environments. </p>
+
+<h2><a name="configuration">Configuration</a></h2>
+
+<p> Postfix IPv6 support introduces two new main.cf configuration
+parameters, and introduces an important change in address syntax
+notation in match lists such as <tt>mynetworks</tt> or
+<tt>debug_peer_list</tt>. </p>
+
+<p> Postfix IPv6 address syntax is a little tricky, because there
+are a few places where you must enclose IPv6 address inside
+<tt>[]</tt> characters, and a few places where you must not. It is
+a good idea to use <tt>[]</tt> only in the few places where you
+have to. Check out the postconf(5) manual whenever you do IPv6
+related configuration work with Postfix. </p>
+
+<ul>
+
+<li> <p> The new <tt>inet_protocols</tt> parameter specifies what
+IP protocols Postfix will use. This parameter also controls what
+DNS lookups Postfix will do. </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ # You must stop/start Postfix after changing this parameter.
+ inet_protocols = ipv4 (DEFAULT: enable IPv4 only)
+ inet_protocols = all (enable both IPv4 and IPv6)
+ inet_protocols = ipv4, ipv6 (enable both IPv4 and IPv6)
+ inet_protocols = ipv6 (enable IPv6 only)
+</pre>
+</blockquote>
+
+<p> By default, Postfix uses IPv4 only, because most systems aren't
+attached to an IPv6 network. </p>
+
+<ul>
+
+<li> <p> On systems with combined IPv4/IPv6 stacks, attempts to
+deliver mail via IPv6 would always fail with "network unreachable",
+and those attempts would only slow down Postfix. </p>
+
+<li> <p> Linux kernels don't even load IPv6 protocol support by
+default. Any attempt to use it would fail immediately. </p>
+
+</ul>
+
+<p> Note 1: you must stop and start Postfix after changing the
+<tt>inet_protocols</tt> configuration parameter. </p>
+
+<p> Note 2: if you see error messages like the following, then
+you're running Linux and need to turn on IPv6 in the kernel: see
+http://www.ipv6.org/ for hints and tips. Unlike other systems,
+Linux does not have a combined stack for IPv4 and IPv6, and IPv6
+protocol support is not loaded by default. </p>
+
+<blockquote>
+<pre>
+postconf: warning: inet_protocols: IPv6 support is disabled: Address family not supported by protocol
+postconf: warning: inet_protocols: configuring for IPv4 support only
+</pre>
+</blockquote>
+
+<p> Note 3: on older Linux and Solaris systems, the setting
+"<tt>inet_protocols = ipv6</tt>" will not prevent Postfix from
+accepting IPv4 connections. Postfix will present the client IP
+addresses in IPv6 format, though. In all other cases, Postfix always
+presents IPv4 client IP addresses in the traditional dotted quad
+IPv4 format. </p>
+
+<li> <p> The other new parameter is <tt>smtp_bind_address6</tt>.
+This sets the local interface address for outgoing IPv6 SMTP
+connections, just like the <tt>smtp_bind_address</tt> parameter
+does for IPv4: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ smtp_bind_address6 = 2001:240:5c7:0:250:56ff:fe89:1
+</pre>
+</blockquote>
+
+<li> <p> If you left the value of the <tt>mynetworks</tt> parameter at its
+default (i.e. no <tt>mynetworks</tt> setting in main.cf) Postfix will figure
+out by itself what its network addresses are. This is what a typical
+setting looks like: </p>
+
+<blockquote>
+<pre>
+% postconf mynetworks
+mynetworks = 127.0.0.0/8 168.100.189.0/28 [::1]/128 [fe80::]/10 [2001:240:5c7::]/64
+</pre>
+</blockquote>
+
+<p> If you did specify the <tt>mynetworks</tt> parameter value in
+main.cf, you need update the <tt>mynetworks</tt> value to include
+the IPv6 networks the system is in. Be sure to specify IPv6 address
+information inside <tt>[]</tt>, like this: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ mynetworks = ...<i>IPv4 networks</i>... [::1]/128 [2001:240:5c7::]/64 ...
+</pre>
+</blockquote>
+
+</ul>
+
+<p> <b> NOTE: when configuring Postfix match lists such as
+<tt>mynetworks</tt> or <tt>debug_peer_list</tt>, you must specify
+IPv6 address information inside <tt>[]</tt> in the main.cf parameter
+value and in files specified with a "<i>/file/name</i>" pattern.
+IPv6 addresses contain the ":" character, and would otherwise be
+confused with a "<i>type:table</i>" pattern. </b> </p>
+
+<h2><a name="limitations">Known Limitations</a></h2>
+
+<ul>
+
+<li> <p> The order of IPv6/IPv4 outgoing connection attempts is
+not yet configurable. Currently, IPv6 is tried before IPv4. </p>
+
+<li> <p> Postfix currently does not support DNSBL (real-time
+blackhole list) lookups for IPv6 client IP addresses; currently
+there are no blacklists that cover the IPv6 address space. </p>
+
+<li> <p> IPv6 does not have class A, B, C, etc. networks. With IPv6
+networks, the setting "<tt>mynetworks_style = class</tt>" has the
+same effect as the setting "<tt>mynetworks_style = subnet</tt>".
+</p>
+
+<li> <p> On Tru64Unix, Postfix can't figure out the local subnet mask
+and always assumes a /128 network. This is a problem only with
+"<tt>mynetworks_style = subnet</tt>" and no explicit <tt>mynetworks</tt>
+setting in main.cf. </p>
+
+</ul>
+
+<h2> <a name="compat">Compatibility with Postfix <2.2 IPv6 support</a>
+</h2>
+
+<p> Postfix version 2.2 IPv6 support is based on the Postfix/IPv6 patch
+by Dean Strik and others, but differs in a few minor ways. </p>
+
+<ul>
+
+<li> <p> main.cf: The <tt>inet_interfaces</tt> parameter does not support
+the notation "<tt>ipv6:all</tt>" or "<tt>ipv4:all</tt>". Use the
+<tt>inet_protocols</tt> parameter instead. </p>
+
+<li> <p> main.cf: Specify "<tt>inet_protocols = all</tt>" or
+"<tt>inet_protocols = ipv4, ipv6</tt>" in order to enable both IPv4
+and IPv6 support. </p>
+
+<li> <p> main.cf: The <tt>inet_protocols</tt> parameter also controls
+what DNS lookups Postfix will attempt to make when delivering or
+receiving mail. </p>
+
+<li> <p> main.cf: Specify "<tt>inet_interfaces = loopback-only</tt>"
+to listen on loopback network interfaces only. </p>
+
+<li> <p> The <tt>lmtp_bind_address</tt> and <tt>lmtp_bind_address6</tt>
+features were omitted. The Postfix LMTP client will be absorbed
+into the SMTP client, so there is no reason to keep adding features
+to the LMTP client. </p>
+
+<li> <p> The SMTP server now requires that IPv6 addresses in SMTP
+commands are specified as <tt>[ipv6:<i>ipv6address</i>]</tt>, as
+described in RFC 2821. </p>
+
+<li> <p> The IPv6 network address matching code was rewritten from
+the ground up, and is expected to be closer to the specification.
+The result may be incompatible with the Postfix/IPv6 patch.
+</p>
+
+</ul>
+
+<h2><a name="porting">IPv6 Support for unsupported platforms</a></h2>
+
+<p> Getting Postfix IPv6 working on other platforms involves the
+following steps: </p>
+
+<ul>
+
+<li> <p> Specify how Postfix should find the local network interfaces.
+Postfix needs this information to avoid mailer loops and to find out
+if mail for <i>user@[ipaddress]</i> is a local or remote destination. </p>
+
+<p> If your system has the <tt>getifaddrs()</tt> routine then add
+the following to your platform-specific section in
+<tt>src/util/sys_defs.h</tt>: </p>
+
+<blockquote>
+<pre>
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAVE_GETIFADDRS
+#endif
+</pre>
+</blockquote>
+
+<p> Otherwise, if your system has the SIOCGLIF <tt>ioctl()</tt>
+command in <tt>/usr/include/*/*.h</tt>, add the following to your
+platform-specific section in <tt>src/util/sys_defs.h</tt>: </p>
+
+<blockquote>
+<pre>
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAS_SIOCGLIF
+#endif
+</pre>
+</blockquote>
+
+<p> Otherwise, Postfix will have to use the old SIOCGIF commands
+and get along with reduced IPv6 functionality (it won't be able to
+figure out your IPv6 netmasks, which are needed for "<tt>mynetworks_style
+= subnet</tt>". Add this to your platform-specific section in
+<tt>src/util/sys_defs.h</tt>: </p>
+
+<blockquote>
+<pre>
+#ifndef NO_IPV6
+# define HAS_IPV6
+#endif
+</pre>
+</blockquote>
+
+<li> <p> Test if Postfix can figure out its interface information. </p>
+
+<p> After compiling Postfix in the usual manner, step into the
+<tt>src/util</tt> directory and type "<tt>make inet_addr_local</tt>".
+Running this file by hand should produce all the interface addresses
+and network masks, for example: </p>
+
+<blockquote>
+<pre>
+% make
+% cd src/util
+% make inet_addr_local
+[... some messages ...]
+% ./inet_addr_local
+[... some messages ...]
+./inet_addr_local: inet_addr_local: configured 2 IPv4 addresses
+./inet_addr_local: inet_addr_local: configured 4 IPv6 addresses
+168.100.189.2/255.255.255.224
+127.0.0.1/255.0.0.0
+fe80:1::2d0:b7ff:fe88:2ca7/ffff:ffff:ffff:ffff::
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7/ffff:ffff:ffff:ffff::
+fe80:5::1/ffff:ffff:ffff:ffff::
+::1/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+</pre>
+</blockquote>
+
+<p> The above is for an old FreeBSD machine. Other systems produce
+slightly different results, but you get the idea. </p>
+
+</ul>
+
+<p> If none of all this produces a usable result, send email to the
+postfix-users@postfix.org mailing list and we'll try to help you
+through this. </p>
+
+<h2><a name="credits">Credits</a></h2>
+
+<p> The following information is in part based on information that
+was compiled by Dean Strik. </p>
+
+<ul>
+
+<li> <p> Mark Huizer wrote the original Postfix IPv6 patch. </p>
+
+<li> <p> Jun-ichiro 'itojun' Hagino of the KAME project made
+substantial improvements. Since then, we speak of the KAME patch.
+</p>
+
+<li> <p> The PLD Linux Distribution ported the code to other stacks
+(notably USAGI). We speak of the PLD patch. A very important
+feature of the PLD patch was that it can work with Lutz Jaenicke's
+TLS patch for Postfix. </p>
+
+<li> <p> Dean Strik extended IPv6 support to platforms other than
+KAME and USAGI, updated the patch to keep up with Postfix development,
+and provided a combined IPv6 + TLS patch. Information about his
+effort can be found on Dean Strik's Postfix website at
+http://www.ipnet6.org/postfix/. </p>
+
+<li> <p> Wietse Venema took Dean Strik's IPv6 patch, merged it into
+Postfix 2.2, and took the opportunity to eliminate all IPv4-specific
+code from Postfix that could be removed. For systems without IPv6
+support in the kernel and system libraries, Postfix has a simple
+compatibility layer, so that it will use IPv4 as before. </p>
+
+</ul>
+
+</body>
+
+</html>
../html/DATABASE_README.html ../html/DB_README.html \
../html/DEBUG_README.html \
../html/ETRN_README.html ../html/FILTER_README.html \
- ../html/INSTALL.html ../html/LDAP_README.html \
+ ../html/INSTALL.html ../html/IPV6_README.html \
+ ../html/LDAP_README.html \
../html/LINUX_README.html ../html/LMTP_README.html \
../html/LOCAL_RECIPIENT_README.html ../html/MAILDROP_README.html \
../html/MYSQL_README.html ../html/NFS_README.html \
../README_FILES/DATABASE_README ../README_FILES/DB_README \
../README_FILES/DEBUG_README \
../README_FILES/ETRN_README ../README_FILES/FILTER_README \
- ../README_FILES/INSTALL ../README_FILES/LDAP_README \
+ ../README_FILES/INSTALL ../README_FILES/IPV6_README \
+ ../README_FILES/LDAP_README \
../README_FILES/LINUX_README ../README_FILES/LMTP_README \
../README_FILES/LOCAL_RECIPIENT_README ../README_FILES/MAILDROP_README \
../README_FILES/MYSQL_README ../README_FILES/NFS_README \
../html/INSTALL.html: INSTALL.html
$(POSTLINK) $? >$@
+../html/IPV6_README.html: IPV6_README.html
+ $(POSTLINK) $? >$@
+
../html/LDAP_README.html: LDAP_README.html
$(POSTLINK) $? >$@
../README_FILES/INSTALL: INSTALL.html
$(HT2READ) $? >$@
+../README_FILES/IPV6_README: IPV6_README.html
+ $(HT2READ) $? >$@
+
../README_FILES/LDAP_README: LDAP_README.html
$(HT2READ) $? >$@
either does not send the attribute, or sends the attribute with
an empty value ("name="). </p>
+ <li> <p> The client address is an IPv4 dotted quad in the form
+ 1.2.3.4 or it is an IPv6 address in the form 1:2:3::4:5:6.
+ </p>
+
<li> <p> An attribute name must not contain "=", null or newline,
and an attribute value must not contain null or newline. </p>
<li> <p> smtpd_proxy_filter (syntax: host:port): The host and TCP
port of the before-queue content filter. When no host or host:
-is specified in client context, localhost is assumed. </p>
+is specified here, localhost is assumed. </p>
<li> <p> smtpd_proxy_timeout (default: 100s): Timeout for connecting
to the before-queue content filter and for sending and receiving
# The optional \fBaccess\fR table directs the Postfix SMTP server
# to selectively reject or accept mail. Access can be allowed or
# denied for specific host names, domain names, networks, host
-# network addresses or mail addresses.
+# addresses or mail addresses.
#
# For an example, see the EXAMPLE section at the end of this
# manual page.
# .IP \fInet.work.addr\fR
# .IP \fInet.work\fR
# .IP \fInet\fR
-# Matches any host address in the specified network. A network
-# address is a sequence of one or more octets separated by ".".
+# Matches the specified IPv4 host address or subnetwork. An
+# IPv4 host address is a sequence of four decimal octets
+# separated by ".".
#
-# NOTE: use the \fBcidr\fR lookup table type to specify
+# Subnetworks are matched by repeatedly truncating the last
+# ".octet" from the remote IPv4 host address string until a
+# match is found in the access table, or until further
+# truncation is not possible.
+#
+# NOTE 1: The information in the access map should be in
+# canonical form, with unnecessary null characters eliminated.
+# Address information must not be enclosed with "[]" characters.
+#
+# NOTE 2: use the \fBcidr\fR lookup table type to specify
# network/netmask patterns. See cidr_table(5) for details.
+# .IP \fInet:work:addr:ess\fR
+# .IP \fInet:work:addr\fR
+# .IP \fInet:work\fR
+# .IP \fInet\fR
+# Matches the specified IPv6 host address or subnetwork. An
+# IPv6 host address is a sequence of three to eight hexadecimal
+# octet pairs separated by ":".
+#
+# Subnetworks are matched by repeatedly truncating the last
+# ":octetpair" from the remote IPv6 host address string until
+# a match is found in the access table, or until further
+# truncation is not possible.
+#
+# NOTE 1: the truncation and comparison are done with the
+# string representation of the IPv6 host address. Thus, not
+# all the ":" subnetworks will be tried.
+#
+# NOTE 2: The information in the access map should be in
+# canonical form, with unnecessary null characters eliminated.
+# Address information must not be enclosed with "[]" characters.
+#
+# NOTE 3: use the \fBcidr\fR lookup table type to specify
+# network/netmask patterns. See cidr_table(5) for details.
+#
+# IPv6 support is available in Postfix 2.2 and later.
# ACCEPT ACTIONS
# .ad
# .fi
# .IP "\fInetwork_address\fB/\fInetwork_mask result\fR"
# When a search string matches the specified network block,
# use the corresponding \fIresult\fR value. Specify
-# 0.0.0.0/0 to match every address.
+# 0.0.0.0/0 to match every IPv4 address, and ::/0 to match
+# every IPv6 address.
+#
+# Note: address information may be enclosed inside "[]" but
+# this form is not recommended.
+#
+# IPv6 support is available in Postfix 2.2 and later.
# .IP "\fInetwork_address result\fR"
# When a search string matches the specified network address,
# use the corresponding \fIresult\fR value.
execute the command "<b>postfix reload</b>".
</p>
-%PARAM hash_queue_names see "postconf -d" output
+%PARAM hash_queue_names deferred, defer
<p>
The names of queue directories that are split across multiple
subdirectory levels.
</p>
+<p> Before Postfix version 2.2, the default list of hashed queues
+was significantly larger. Claims about improvements in file system
+technology suggest that hashing of the incoming and active queues
+is no longer needed. Fewer hashed directories speed up the time
+needed to restart Postfix. </p>
+
<p>
After changing the hash_queue_names or hash_queue_depth parameter,
execute the command "<b>postfix reload</b>".
%PARAM inet_interfaces all
+<p> The network interface addresses that this mail system receives
+mail on. By default, the software claims all active interfaces on
+the machine; with Postfix 2.2 and later, specify "<b>loopback-only</b>"
+to select only local interfaces. The parameter also controls
+delivery of mail to user@[ip.address]. </p>
+
<p>
-The network interface addresses that this mail system receives mail
-on. By default, the software claims all active interfaces on the
-machine. The parameter also controls delivery of mail to
-user@[ip.address].
+Note: you need to stop and start Postfix when this parameter changes.
</p>
-<p>
-When inet_interfaces consists of just one IP address that is not a
-loopback (net 127) address, the Postfix SMTP client will use this address
-as the IP source address for outbound mail. </p>
+<p> When inet_interfaces specifies just one IPv4 and/or IPv6 address
+that is not a loopback address, the Postfix SMTP client will use
+this address as the IP source address for outbound mail. </p>
<p>
On a multi-homed firewall with separate Postfix instances listening on the
"inside" and "outside" interfaces, this can prevent each instance from
being able to reach servers on the "other side" of the firewall. Setting
-smtp_bind_address to 0.0.0.0 avoids the potential problem. </p>
+smtp_bind_address to 0.0.0.0 avoids the potential problem for
+IPv4, and setting smtp_bind_address6 to :: solves the problem
+for IPv6. </p>
<p>
-A better solution is to leave inet_interfaces at the default value
+A better solution for multi-homed firewalls is to leave inet_interfaces
+at the default value
and instead use explicit IP addresses in master.cf. This preserves SMTP
loop detection, by ensuring that each side of the firewall knows that the
other IP address is still the same host. Setting $inet_interfaces to a
-single IP address is primarily useful with virtual hosting of domains on
+single IPv4 and/or IPV6 address is primarily useful with virtual
+hosting of domains on
secondary IP addresses, when each IP address serves a different domain
(and has a different $myhostname setting). </p>
<p>
See also the proxy_interfaces parameter, for network addresses that
-are forwarded to us by way of a proxy or address translator.
+are forwarded to Postfix by way of a proxy or address translator.
</p>
<p>
-Note: you need to stop and start Postfix when this parameter changes.
+Examples:
+</p>
+
+<pre>
+inet_interfaces = all (DEFAULT)
+inet_interfaces = loopback-only
+inet_interfaces = 127.0.0.1
+inet_interfaces = 192.168.1.2, 127.0.0.1
+</pre>
+
+%PARAM inet_protocols ipv4
+
+<p> The Internet protocols Postfix will attempt to use when making
+or accepting connections. Specify one or more of "ipv4" or "ipv6",
+separated by whitespace or commas. The form "all" is equivalent to
+"ipv4, ipv6". </p>
+
+<p> Note: you MUST stop and start Postfix after changing this
+parameter. </p>
+
+<p> On systems that pre-date IPV6_V6ONLY support (RFC 3493), an
+IPv6 server will also accept IPv4 connections, even when IPv4 is
+turned off with the inet_protocols parameter. On systems with
+IPV6_V6ONLY support, Postfix will use separate server sockets for
+IPv6 and IPv4, and each will accept only connections for the
+corresponding protocol. </p>
+
+<p> When IPv4 support is enabled via the inet_protocols parameter,
+Postfix will to DNS type A record lookups, and will convert
+IPv4-in-IPv6 client IP addresses (::ffff:1.2.3.4) to their original
+IPv4 form (1.2.3.4). The latter is needed on hosts that pre-date
+IPV6_V6ONLY support (RFC 3493). </p>
+
+<p> When IPv6 support is enabled via the inet_protocols parameter,
+Postfix will do DNS type AAAA record lookups. </p>
+
+<p> When both IPv4 and IPv6 support are enabled, the Postfix SMTP
+client will attempt to connect via IPv6 before attempting to use
+IPv4. </p>
+
+<p> This feature is available in Postfix version 2.2 and later. </p>
+
+<p>
+Examples:
</p>
+<pre>
+inet_protocols = ipv4 (DEFAULT)
+inet_protocols = all
+inet_protocols = ipv6
+inet_protocols = ipv4, ipv6
+</pre>
+
%PARAM initial_destination_concurrency 5
<p>
first match. Specify "!pattern" to exclude an address or network
block from the list. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the mynetworks value, and in files specified with
+"/file/name". IP version 6 addresses contain the ":" character,
+and would otherwise be confused with a "type:table" pattern. </p>
+
<p> Examples: </p>
<pre>
-mynetworks = 168.100.189.0/28, 127.0.0.0/8
+mynetworks = 127.0.0.0/8 168.100.189.0/28
mynetworks = !192.168.0.1, 192.168.0.0/28
+mynetworks = 127.0.0.0/8 168.100.189.0/28 [::1]/128 [2001:240:5c7::]/64
mynetworks = $config_directory/mynetworks
mynetworks = hash:/etc/postfix/network_table
</pre>
<p>
An optional numerical network address that the SMTP client should
-bind to when making a connection.
+bind to when making an IPv4 connection.
</p>
<p>
smtp ... smtp -o smtp_bind_address=11.22.33.44
</pre>
-<p> Note: when inet_interfaces specifies exactly one address that
-is a non-loopback address, it is automatically used as the
-smtp_bind_address. This supports virtual IP hosting, but can be
-a problem on multi-homed firewalls. See the inet_interfaces
-documentation for more detail. </p>
+<p> Note 1: when inet_interfaces specifies no more than one IPv4
+address, and that address is a non-loopback address, it is
+automatically used as the smtp_bind_address. This supports virtual
+IP hosting, but can be a problem on multi-homed firewalls. See the
+inet_interfaces documentation for more detail. </p>
+
+<p> Note 2: address information may be enclosed inside <tt>[]</tt>,
+but this form is not recommended. </p>
+
+%PARAM smtp_bind_address6
+
+<p>
+An optional numerical network address that the SMTP client should
+bind to when making an IPv6 connection.
+</p>
+
+<p>
+This can be specified in the main.cf file for all SMTP clients, or
+it can be specified in the master.cf file for a specific client,
+for example:
+</p>
+
+<pre>
+ /etc/postfix/master.cf:
+ smtp ... smtp -o smtp_bind_address6=1:2:3:4:5:6:7:8
+</pre>
+
+<p> Note 1: when inet_interfaces specifies no more than one IPv6
+address, and that address is a non-loopback address, it is
+automatically used as the smtp_bind_address6. This supports virtual
+IP hosting, but can be a problem on multi-homed firewalls. See the
+inet_interfaces documentation for more detail. </p>
+
+<p> Note 2: address information may be enclosed inside <tt>[]</tt>,
+but this form is not recommended. </p>
+
+<p> This feature is available in Postfix version 2.2 and later. </p>
%PARAM smtp_connection_cache_time_limit 2s
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the authorized_verp_clients value, and in files
+specified with "/file/name". IP version 6 addresses contain the
+":" character, and would otherwise be confused with a "type:table"
+pattern. </p>
+
%PARAM smtpd_authorized_verp_clients $authorized_verp_clients
<p> What SMTP clients are allowed to specify the XVERP command.
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_authorized_verp_clients value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern. </p>
+
%PARAM smtpd_authorized_xclient_hosts
<p>
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_authorized_xclient_hosts value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern. </p>
+
%PARAM smtpd_authorized_xforward_hosts
<p>
result is ignored). Continue long lines by starting the next line
with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_authorized_xforward_hosts value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern. </p>
+
%PARAM smtpd_banner $myhostname ESMTP $mail_name
<p>
dot causes the domain to match any name below it).
</p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_client_event_limit_exceptions value, and
+in files specified with "/file/name". IP version 6 addresses
+contain the ":" character, and would otherwise be confused with a
+"type:table" pattern. </p>
+
<p>
This feature is available in Postfix 2.2 and later.
</p>
matches a lookup string (the lookup result is ignored). Continue
long lines by starting the next line with whitespace. </p>
+<p> Note: IP version 6 address information must be specified inside
+<tt>[]</tt> in the smtpd_sasl_exceptions_networks value, and in
+files specified with "/file/name". IP version 6 addresses contain
+the ":" character, and would otherwise be confused with a "type:table"
+pattern. </p>
+
<p>
Example:
</p>
<p> Optional lookup tables with a) names of domains for which all
addresses are aliased to addresses in other local or remote domains,
and b) addresses that are aliased to addresses in other local or
-remote domains. Available before Postfix version 2.0. With Postfix 2.1
+remote domains. Available before Postfix version 2.0. With Postfix 2.0
and later, this is replaced by separate controls: virtual_alias_domains
and virtual_alias_maps. </p>
Verisign's
dd
itd
+AAAA
+DNSBL
+GETIFADDRS
+Hagino
+Huizer
+Jaenicke's
+Lutz
+PLD
+SIOCGIF
+SIOCGLIF
+Strik
+Strik's
+Tru
+USAGI
+compat
+ff
+ffff
+getifaddrs
+ichiro
+ifndef
+ipnet
+ipv
+itojun
+netmasks
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
cleanup_envelope.o: ../../include/stringops.h
cleanup_envelope.o: ../../include/nvtable.h
cleanup_envelope.o: ../../include/htable.h
-cleanup_envelope.o: ../../include/name_code.h
cleanup_envelope.o: ../../include/record.h
cleanup_envelope.o: ../../include/rec_type.h
cleanup_envelope.o: ../../include/cleanup_user.h
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
SHELL = /bin/sh
-SRCS = dns_lookup.c dns_rr.c dns_strerror.c dns_strtype.c
-OBJS = dns_lookup.o dns_rr.o dns_strerror.o dns_strtype.o
+SRCS = dns_lookup.c dns_rr.c dns_strerror.c dns_strtype.c dns_rr_to_pa.c \
+ dns_sa_to_rr.c dns_rr_eq_sa.c dns_rr_to_sa.c
+OBJS = dns_lookup.o dns_rr.o dns_strerror.o dns_strtype.o dns_rr_to_pa.o \
+ dns_sa_to_rr.o dns_rr_eq_sa.o dns_rr_to_sa.o
HDRS = dns.h
TESTSRC = test_dns_lookup.c test_alias_token.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
INCL =
LIB = libdns.a
-TESTPROG= test_dns_lookup
+TESTPROG= test_dns_lookup dns_rr_to_pa dns_rr_to_sa dns_sa_to_rr dns_rr_eq_sa
LIBS = ../../lib/libutil.a
LIB_DIR = ../../lib
INC_DIR = ../../include
all: $(LIB)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
-tests: test
+tests: test dns_rr_to_pa_test dns_rr_to_sa_test dns_sa_to_rr_test \
+ dns_rr_eq_sa_test
$(LIB): $(OBJS)
$(AR) $(ARFL) $(LIB) $?
test_dns_lookup: test_dns_lookup.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+dns_rr_to_pa: $(LIB) $(LIBS)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+ mv junk $@.o
+
+dns_rr_to_sa: $(LIB) $(LIBS)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+ mv junk $@.o
+
+dns_sa_to_rr: $(LIB) $(LIBS)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+ mv junk $@.o
+
+dns_rr_eq_sa: $(LIB) $(LIBS)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+ mv junk $@.o
+
+dns_rr_to_pa_test: dns_rr_to_pa dns_rr_to_pa.in dns_rr_to_pa.ref
+ ./dns_rr_to_pa `cat dns_rr_to_pa.in` >dns_rr_to_pa.tmp
+ diff dns_rr_to_pa.ref dns_rr_to_pa.tmp
+ rm -f dns_rr_to_pa.tmp
+
+dns_rr_to_sa_test: dns_rr_to_sa dns_rr_to_sa.in dns_rr_to_sa.ref
+ ./dns_rr_to_sa `cat dns_rr_to_sa.in` >dns_rr_to_sa.tmp
+ diff dns_rr_to_sa.ref dns_rr_to_sa.tmp
+ rm -f dns_rr_to_sa.tmp
+
+dns_sa_to_rr_test: dns_sa_to_rr dns_sa_to_rr.in dns_sa_to_rr.ref
+ ./dns_sa_to_rr `cat dns_sa_to_rr.in` >dns_sa_to_rr.tmp
+ diff dns_sa_to_rr.ref dns_sa_to_rr.tmp
+ rm -f dns_sa_to_rr.tmp
+
+dns_rr_eq_sa_test: dns_rr_eq_sa dns_rr_eq_sa.in dns_rr_eq_sa.ref
+ ./dns_rr_eq_sa `cat dns_rr_eq_sa.in` >dns_rr_eq_sa.tmp
+ diff dns_rr_eq_sa.ref dns_rr_eq_sa.tmp
+ rm -f dns_rr_eq_sa.tmp
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
dns_lookup.o: ../../include/valid_hostname.h
dns_lookup.o: ../../include/stringops.h
dns_lookup.o: dns.h
+dns_lookup.o: ../../include/sock_addr.h
+dns_lookup.o: ../../include/myaddrinfo.h
dns_rr.o: dns_rr.c
dns_rr.o: ../../include/sys_defs.h
dns_rr.o: ../../include/msg.h
dns_rr.o: dns.h
dns_rr.o: ../../include/vstring.h
dns_rr.o: ../../include/vbuf.h
+dns_rr.o: ../../include/sock_addr.h
+dns_rr.o: ../../include/myaddrinfo.h
+dns_rr_eq_sa.o: dns_rr_eq_sa.c
+dns_rr_eq_sa.o: ../../include/sys_defs.h
+dns_rr_eq_sa.o: ../../include/msg.h
+dns_rr_eq_sa.o: ../../include/sock_addr.h
+dns_rr_eq_sa.o: dns.h
+dns_rr_eq_sa.o: ../../include/vstring.h
+dns_rr_eq_sa.o: ../../include/vbuf.h
+dns_rr_eq_sa.o: ../../include/myaddrinfo.h
+dns_rr_to_pa.o: dns_rr_to_pa.c
+dns_rr_to_pa.o: ../../include/sys_defs.h
+dns_rr_to_pa.o: ../../include/msg.h
+dns_rr_to_pa.o: dns.h
+dns_rr_to_pa.o: ../../include/vstring.h
+dns_rr_to_pa.o: ../../include/vbuf.h
+dns_rr_to_pa.o: ../../include/sock_addr.h
+dns_rr_to_pa.o: ../../include/myaddrinfo.h
+dns_rr_to_sa.o: dns_rr_to_sa.c
+dns_rr_to_sa.o: ../../include/sys_defs.h
+dns_rr_to_sa.o: ../../include/msg.h
+dns_rr_to_sa.o: dns.h
+dns_rr_to_sa.o: ../../include/vstring.h
+dns_rr_to_sa.o: ../../include/vbuf.h
+dns_rr_to_sa.o: ../../include/sock_addr.h
+dns_rr_to_sa.o: ../../include/myaddrinfo.h
+dns_sa_to_rr.o: dns_sa_to_rr.c
+dns_sa_to_rr.o: ../../include/sys_defs.h
+dns_sa_to_rr.o: ../../include/msg.h
+dns_sa_to_rr.o: dns.h
+dns_sa_to_rr.o: ../../include/vstring.h
+dns_sa_to_rr.o: ../../include/vbuf.h
+dns_sa_to_rr.o: ../../include/sock_addr.h
+dns_sa_to_rr.o: ../../include/myaddrinfo.h
dns_strerror.o: dns_strerror.c
dns_strerror.o: ../../include/sys_defs.h
dns_strerror.o: ../../include/vstring.h
dns_strerror.o: ../../include/vbuf.h
dns_strerror.o: dns.h
+dns_strerror.o: ../../include/sock_addr.h
+dns_strerror.o: ../../include/myaddrinfo.h
dns_strtype.o: dns_strtype.c
dns_strtype.o: ../../include/sys_defs.h
dns_strtype.o: ../../include/vstring.h
dns_strtype.o: ../../include/vbuf.h
dns_strtype.o: dns.h
+dns_strtype.o: ../../include/sock_addr.h
+dns_strtype.o: ../../include/myaddrinfo.h
test_dns_lookup.o: test_dns_lookup.c
test_dns_lookup.o: ../../include/sys_defs.h
test_dns_lookup.o: ../../include/vstring.h
test_dns_lookup.o: ../../include/msg_vstream.h
test_dns_lookup.o: ../../include/vstream.h
test_dns_lookup.o: dns.h
+test_dns_lookup.o: ../../include/sock_addr.h
+test_dns_lookup.o: ../../include/myaddrinfo.h
* Utility library.
*/
#include <vstring.h>
+#include <sock_addr.h>
+#include <myaddrinfo.h>
/*
* Structure for fixed resource record data.
/*
* dns_rr.c
*/
-extern DNS_RR *dns_rr_create(const char *, DNS_FIXED *, unsigned,
+extern DNS_RR *dns_rr_create(const char *, ushort, ushort,
+ unsigned, unsigned,
const char *, unsigned);
extern void dns_rr_free(DNS_RR *);
extern DNS_RR *dns_rr_copy(DNS_RR *);
extern DNS_RR *dns_rr_shuffle(DNS_RR *);
extern DNS_RR *dns_rr_remove(DNS_RR *, DNS_RR *);
+ /*
+ * dns_rr_to_pa.c
+ */
+extern const char *dns_rr_to_pa(DNS_RR *, MAI_HOSTADDR_STR *);
+
+ /*
+ * dns_sa_to_rr.c
+ */
+extern DNS_RR *dns_sa_to_rr(const char *, unsigned, struct sockaddr *);
+
+ /*
+ * dns_rr_to_sa.c
+ */
+extern int dns_rr_to_sa(DNS_RR *, unsigned, struct sockaddr *, SOCKADDR_SIZE *);
+
+ /*
+ * dns_rr_eq_sa.c
+ */
+extern int dns_rr_eq_sa(DNS_RR *, struct sockaddr *);
+
+#ifdef HAS_IPV6
+#define DNS_RR_EQ_SA(rr, sa) \
+ ((SOCK_ADDR_IN_FAMILY(sa) == AF_INET && (rr)->type == T_A \
+ && SOCK_ADDR_IN_ADDR(sa).s_addr == IN_ADDR((rr)->data).s_addr) \
+ || (SOCK_ADDR_IN_FAMILY(sa) == AF_INET6 && (rr)->type == T_AAAA \
+ && memcmp((char *) &(SOCK_ADDR_IN6_ADDR(sa)), \
+ (rr)->data, (rr)->data_len) == 0))
+#else
+#define DNS_RR_EQ_SA(rr, sa) \
+ (SOCK_ADDR_IN_FAMILY(sa) == AF_INET && (rr)->type == T_A \
+ && SOCK_ADDR_IN_ADDR(sa).s_addr == IN_ADDR((rr)->data).s_addr)
+#endif
+
/*
* dns_lookup.c
*/
extern int dns_lookup(const char *, unsigned, unsigned, DNS_RR **,
VSTRING *, VSTRING *);
-extern int dns_lookup_types(const char *, unsigned, DNS_RR **,
- VSTRING *, VSTRING *,...);
+extern int dns_lookup_l(const char *, unsigned, DNS_RR **, VSTRING *,
+ VSTRING *, int,...);
+extern int dns_lookup_v(const char *, unsigned, DNS_RR **, VSTRING *,
+ VSTRING *, int, unsigned *);
+
+ /*
+ * Request flags.
+ */
+#define DNS_REQ_FLAG_ANY (1<<0)
+#define DNS_REQ_FLAG_ALL (1<<1)
/*
* Status codes. Failures must have negative codes so they will not collide
/* SYNOPSIS
/* #include <dns.h>
/*
-/* int dns_lookup(name, type, flags, list, fqdn, why)
+/* int dns_lookup(name, type, rflags, list, fqdn, why)
/* const char *name;
/* unsigned type;
-/* unsigned flags;
+/* unsigned rflags;
/* DNS_RR **list;
/* VSTRING *fqdn;
/* VSTRING *why;
/*
-/* int dns_lookup_types(name, flags, list, fqdn, why, type, ...)
+/* int dns_lookup_l(name, rflags, list, fqdn, why, lflags, ltype, ...)
/* const char *name;
-/* unsigned flags;
+/* unsigned rflags;
/* DNS_RR **list;
/* VSTRING *fqdn;
/* VSTRING *why;
-/* unsigned type;
+/* int lflags;
+/* unsigned ltype;
+/*
+/* int dns_lookup_v(name, rflags, list, fqdn, why, lflags, ltype)
+/* const char *name;
+/* unsigned rflags;
+/* DNS_RR **list;
+/* VSTRING *fqdn;
+/* VSTRING *why;
+/* int lflags;
+/* unsigned *ltype;
/* DESCRIPTION
/* dns_lookup() looks up DNS resource records. When requested to
/* look up data other than type CNAME, it will follow a limited
/* All name results are validated by \fIvalid_hostname\fR();
/* an invalid name is reported as a transient error.
/*
-/* dns_lookup_types() allows the user to specify a null-terminated
-/* list of resource types. This function calls dns_lookup() for each
-/* listed type in the specified order, until the list is exhausted or
-/* until the search result becomes not equal to DNS_NOTFOUND.
+/* dns_lookup_l() and dns_lookup_v() allow the user to specify
+/* a list of resource types.
/* INPUTS
/* .ad
/* .fi
/* The name to be looked up in the domain name system.
/* .IP type
/* The resource record type to be looked up (T_A, T_MX etc.).
-/* .IP flags
-/* A bitwise OR of:
+/* .IP rflags
+/* Resolver flags. These are a bitwise OR of:
/* .RS
/* .IP RES_DEBUG
/* Print debugging information.
/* .IP RES_DEFNAMES
/* Append local domain to unqualified names.
/* .RE
+/* .IP lflags
+/* Multi-type request control for dns_lookup_l() and
+/* dns_lookup_v(). This is one of the following:
+/* .RS
+/* .IP DNS_REQ_FLAG_ANY
+/* Call dns_lookup() for each specified resource record type
+/* in the specified order, until the list is exhausted or
+/* until some result is DNS_OK.
+/* .IP DNS_REQ_FLAG_ALL
+/* Call dns_lookup() for all specified resource record types
+/* in the specified order, and merge their results.
+/* .RE
+/* .IP ltype
+/* The resource record types to be looked up. In the case of
+/* dns_lookup_l(), this is a null-terminated argument list.
+/* In the case of dns_lookup_v(), this is a null-terminated
+/* integer array.
/* OUTPUTS
/* .ad
/* .fi
#include <sys_defs.h>
#include <netdb.h>
-#include <stdlib.h> /* BSDI stdarg.h uses abort() */
-#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <msg.h>
#include <valid_hostname.h>
#include <stringops.h>
-#include <valid_hostname.h>
/* DNS library. */
*dst = 0;
break;
}
- return (dns_rr_create(rr_name, fixed, pref, temp, data_len));
+ return (dns_rr_create(rr_name, fixed->type, fixed->class, fixed->ttl,
+ pref, temp, data_len));
}
/* dns_get_alias - extract CNAME from name server reply */
int status;
/*
- * The Linux resolver misbehaves when given an invalid domain name.
+ * DJBDNS produces a bogus A record when given a numerical hostname.
*/
- if (!valid_hostname(name, DONT_GRIPE)) {
+ if (valid_hostaddr(name, DONT_GRIPE)) {
if (why)
vstring_sprintf(why,
"Name service error for %s: invalid host or domain name",
}
/*
- * DJBDNS produces a bogus A record when given a numerical hostname.
+ * The Linux resolver misbehaves when given an invalid domain name.
*/
- if (valid_hostaddr(name, DONT_GRIPE)) {
+ if (!valid_hostname(name, DONT_GRIPE)) {
if (why)
vstring_sprintf(why,
"Name service error for %s: invalid host or domain name",
return (DNS_NOTFOUND);
}
-/* dns_lookup_types - DNS lookup interface with multiple types */
+/* dns_lookup_l - DNS lookup interface with types list */
-int dns_lookup_types(const char *name, unsigned flags, DNS_RR **rrlist,
- VSTRING *fqdn, VSTRING *why,...)
+int dns_lookup_l(const char *name, unsigned flags, DNS_RR **rrlist,
+ VSTRING *fqdn, VSTRING *why, int lflags,...)
{
va_list ap;
unsigned type;
int status = DNS_NOTFOUND;
+ DNS_RR *rr;
+ int non_err = 0;
int soft_err = 0;
- va_start(ap, why);
+ if (rrlist)
+ *rrlist = 0;
+ va_start(ap, lflags);
while ((type = va_arg(ap, unsigned)) != 0) {
if (msg_verbose)
- msg_info("lookup %s type %d flags %d", name, type, flags);
- status = dns_lookup(name, type, flags, rrlist, fqdn, why);
- if (status == DNS_OK)
- break;
- if (status == DNS_RETRY)
+ msg_info("lookup %s type %s flags %d",
+ name, dns_strtype(type), flags);
+ status = dns_lookup(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
+ fqdn, why);
+ if (status == DNS_OK) {
+ non_err = 1;
+ if (rrlist)
+ *rrlist = dns_rr_append(*rrlist, rr);
+ if (lflags == DNS_REQ_FLAG_ANY)
+ break;
+ } else if (status == DNS_RETRY) {
soft_err = 1;
+ }
}
va_end(ap);
- return ((status == DNS_OK || soft_err == 0) ? status : DNS_RETRY);
+ return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status);
+}
+
+/* dns_lookup_v - DNS lookup interface with types vector */
+
+int dns_lookup_v(const char *name, unsigned flags, DNS_RR **rrlist,
+ VSTRING *fqdn, VSTRING *why, int lflags,
+ unsigned *types)
+{
+ unsigned type;
+ int status = DNS_NOTFOUND;
+ DNS_RR *rr;
+ int non_err = 0;
+ int soft_err = 0;
+
+ if (rrlist)
+ *rrlist = 0;
+ while ((type = *types++) != 0) {
+ if (msg_verbose)
+ msg_info("lookup %s type %s flags %d",
+ name, dns_strtype(type), flags);
+ status = dns_lookup(name, type, flags, rrlist ? &rr : (DNS_RR **) 0,
+ fqdn, why);
+ if (status == DNS_OK) {
+ non_err = 1;
+ if (rrlist)
+ *rrlist = dns_rr_append(*rrlist, rr);
+ if (lflags == DNS_REQ_FLAG_ANY)
+ break;
+ } else if (status == DNS_RETRY) {
+ soft_err = 1;
+ }
+ }
+ return (non_err ? DNS_OK : soft_err ? DNS_RETRY : status);
}
/* SYNOPSIS
/* #include <dns.h>
/*
-/* DNS_RR *dns_rr_create(name, fixed, preference, data, data_len)
+/* DNS_RR *dns_rr_create(name, type, class, ttl, preference,
+/* data, data_len)
/* const char *name;
-/* DNS_FIXED *fixed;
+/* unsigned short type;
+/* unsigned short class;
+/* unsigned int ttl;
/* unsigned preference;
/* const char *data;
/* unsigned len;
/*
/* dns_rr_create() creates and initializes one resource record.
/* The \fIname\fR record specifies the record name.
-/* The \fIfixed\fR argument specifies generic resource record
-/* information such as resource type and time to live;
/* \fIpreference\fR is used for MX records; \fIdata\fR is a null
/* pointer or specifies optional resource-specific data;
/* \fIdata_len\fR is the amount of resource-specific data.
/* dns_rr_create - fill in resource record structure */
-DNS_RR *dns_rr_create(const char *name, DNS_FIXED *fixed, unsigned pref,
+DNS_RR *dns_rr_create(const char *name, ushort type, ushort class,
+ unsigned int ttl, unsigned pref,
const char *data, unsigned data_len)
{
DNS_RR *rr;
rr = (DNS_RR *) mymalloc(sizeof(*rr) + data_len - 1);
rr->name = mystrdup(name);
- rr->type = fixed->type;
- rr->class = fixed->class;
- rr->ttl = fixed->ttl;
+ rr->type = type;
+ rr->class = class;
+ rr->ttl = ttl;
rr->pref = pref;
if (data && data_len > 0)
memcpy(rr->data, data, data_len);
DNS_RR *dns_rr_remove(DNS_RR *list, DNS_RR *record)
{
- if (list == 0)
+ if (list == 0)
msg_panic("dns_rr_remove: record not found");
if (list == record) {
--- /dev/null
+/*++
+/* NAME
+/* dns_rr_eq_sa 3
+/* SUMMARY
+/* compare resource record with socket address
+/* SYNOPSIS
+/* #include <dns.h>
+/*
+/* int dns_rr_eq_sa(DNS_RR *rr, struct sockaddr *sa)
+/* DNS_RR *rr;
+/* struct sockaddr *sa;
+/*
+/* int DNS_RR_EQ_SA(DNS_RR *rr, struct sockaddr *sa)
+/* DNS_RR *rr;
+/* struct sockaddr *sa;
+/* DESCRIPTION
+/* dns_rr_eq_sa() compares a DNS resource record with a socket
+/* address. The result is non-zero when the resource type
+/* matches the socket address family, and when the network
+/* address information is identical.
+/*
+/* DNS_RR_EQ_SA() is an unsafe macro version for those who live fast.
+/*
+/* Arguments:
+/* .IP rr
+/* DNS resource record pointer.
+/* .IP sa
+/* Binary address pointer.
+/* DIAGNOSTICS
+/* Panic: unknown socket address family.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <sock_addr.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* dns_rr_eq_sa - compare resource record with socket address */
+
+int dns_rr_eq_sa(DNS_RR *rr, struct sockaddr * sa)
+{
+ const char *myname = "dns_rr_eq_sa";
+
+ if (sa->sa_family == AF_INET) {
+ return (rr->type == T_A
+ && SOCK_ADDR_IN_ADDR(sa).s_addr == IN_ADDR(rr->data).s_addr);
+#ifdef HAS_IPV6
+ } else if (sa->sa_family == AF_INET6) {
+ return (rr->type == T_AAAA
+ && memcmp((char *) &SOCK_ADDR_IN6_ADDR(sa),
+ rr->data, rr->data_len) == 0);
+#endif
+ } else {
+ msg_panic("%s: unsupported socket address family type: %d",
+ myname, sa->sa_family);
+ }
+}
+
+ /*
+ * Stand-alone test program.
+ */
+#ifdef TEST
+#include <vstream.h>
+#include <myaddrinfo.h>
+#include <inet_proto.h>
+
+static const char *myname;
+
+static NORETURN usage(void)
+{
+ msg_fatal("usage: %s hostname address", myname);
+}
+
+int main(int argc, char **argv)
+{
+ MAI_HOSTADDR_STR hostaddr;
+ DNS_RR *rr;
+ struct addrinfo *res0;
+ struct addrinfo *res1;
+ struct addrinfo *res;
+ int aierr;
+
+ myname = argv[0];
+
+ if (argc < 3)
+ usage();
+
+ inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
+
+ while (*++argv) {
+ if (argv[1] == 0)
+ usage();
+
+ if ((aierr = hostaddr_to_sockaddr(argv[1], (char *) 0, 0, &res1)) != 0)
+ msg_fatal("host address %s: %s", argv[1], MAI_STRERROR(aierr));
+ if ((rr = dns_sa_to_rr(argv[1], 0, res1->ai_addr)) == 0)
+ msg_fatal("dns_sa_to_rr: %m");
+ freeaddrinfo(res1);
+
+ if ((aierr = hostname_to_sockaddr(argv[0], (char *) 0, 0, &res0)) != 0)
+ msg_fatal("host name %s: %s", argv[0], MAI_STRERROR(aierr));
+ for (res = res0; res != 0; res = res->ai_next) {
+ SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ vstream_printf("%s =?= %s\n", hostaddr.buf, argv[1]);
+ vstream_printf("tested by function: %s\n",
+ dns_rr_eq_sa(rr, res->ai_addr) ?
+ "yes" : "no");
+ vstream_printf("tested by macro: %s\n",
+ DNS_RR_EQ_SA(rr, res->ai_addr) ?
+ "yes" : "no");
+ }
+ dns_rr_free(rr);
+ freeaddrinfo(res0);
+ vstream_fflush(VSTREAM_OUT);
+ argv += 1;
+ }
+}
+
+#endif
--- /dev/null
+spike.porcupine.org 168.100.189.2
+spike.porcupine.org 168.100.189.3
+spike.porcupine.org 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+spike.porcupine.org 2001:240:5c7:0:2d0:b7ff:febe:ca9f
--- /dev/null
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7 =?= 168.100.189.2
+tested by function: no
+tested by macro: no
+168.100.189.2 =?= 168.100.189.2
+tested by function: yes
+tested by macro: yes
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7 =?= 168.100.189.3
+tested by function: no
+tested by macro: no
+168.100.189.2 =?= 168.100.189.3
+tested by function: no
+tested by macro: no
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7 =?= 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+tested by function: yes
+tested by macro: yes
+168.100.189.2 =?= 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+tested by function: no
+tested by macro: no
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7 =?= 2001:240:5c7:0:2d0:b7ff:febe:ca9f
+tested by function: no
+tested by macro: no
+168.100.189.2 =?= 2001:240:5c7:0:2d0:b7ff:febe:ca9f
+tested by function: no
+tested by macro: no
--- /dev/null
+/*++
+/* NAME
+/* dns_rr_to_pa 3
+/* SUMMARY
+/* resource record to printable address
+/* SYNOPSIS
+/* #include <dns.h>
+/*
+/* const char *dns_rr_to_pa(rr, hostaddr)
+/* DNS_RR *rr;
+/* MAI_HOSTADDR_STR *hostaddr;
+/* DESCRIPTION
+/* dns_rr_to_pa() converts the address in a DNS resource record
+/* into printable form and returns a pointer to the result.
+/*
+/* Arguments:
+/* .IP rr
+/* The DNS resource record.
+/* .IP hostaddr
+/* Storage for the printable address.
+/* DIAGNOSTICS
+/* The result is null in case of problems, with errno set
+/* to indicate the nature of the problem.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* dns_rr_to_pa - resource record to printable address */
+
+const char *dns_rr_to_pa(DNS_RR *rr, MAI_HOSTADDR_STR *hostaddr)
+{
+ if (rr->type == T_A) {
+ return (inet_ntop(AF_INET, rr->data, hostaddr->buf,
+ sizeof(hostaddr->buf)));
+#ifdef HAS_IPV6
+ } else if (rr->type == T_AAAA) {
+ return (inet_ntop(AF_INET6, rr->data, hostaddr->buf,
+ sizeof(hostaddr->buf)));
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ return (0);
+ }
+}
+
+ /*
+ * Stand-alone test program.
+ */
+#ifdef TEST
+#include <vstream.h>
+#include <myaddrinfo.h>
+
+static const char *myname;
+
+static NORETURN usage(void)
+{
+ msg_fatal("usage: %s dnsaddrtype hostname", myname);
+}
+
+int main(int argc, char **argv)
+{
+ DNS_RR *rr;
+ MAI_HOSTADDR_STR hostaddr;
+ VSTRING *why;
+ int type;
+
+ myname = argv[0];
+ if (argc < 3)
+ usage();
+ why = vstring_alloc(1);
+
+ while (*++argv) {
+ if (argv[1] == 0)
+ usage();
+ if ((type = dns_type(argv[0])) == 0)
+ usage();
+ if (dns_lookup(argv[1], type, 0, &rr, (VSTRING *) 0, why) != DNS_OK)
+ msg_fatal("%s: %s", argv[1], vstring_str(why));
+ if (dns_rr_to_pa(rr, &hostaddr) == 0)
+ msg_fatal("dns_rr_to_sa: %m");
+ vstream_printf("%s -> %s\n", argv[1], hostaddr.buf);
+ vstream_fflush(VSTREAM_OUT);
+ argv += 1;
+ dns_rr_free(rr);
+ }
+ vstring_free(why);
+ return (0);
+}
+
+#endif
--- /dev/null
+a spike.porcupine.org
+aaaa spike.porcupine.org
--- /dev/null
+spike.porcupine.org -> 168.100.189.2
+spike.porcupine.org -> 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
--- /dev/null
+/*++
+/* NAME
+/* dns_rr_to_sa 3
+/* SUMMARY
+/* resource record to socket address
+/* SYNOPSIS
+/* #include <dns.h>
+/*
+/* int dns_rr_to_sa(rr, port, sa, sa_len)
+/* DNS_RR *rr;
+/* unsigned port;
+/* struct sockaddr *sa;
+/* SOCKADDR_SIZE *sa_len;
+/* DESCRIPTION
+/* dns_rr_to_sa() converts the address in a DNS resource record into
+/* a socket address of the corresponding type.
+/*
+/* Arguments:
+/* .IP rr
+/* DNS resource record pointer.
+/* .IP port
+/* TCP or UDP port, network byte order.
+/* .IP sa
+/* Socket address pointer.
+/* .IP sa_len
+/* On input, the available socket address storage space.
+/* On output, the amount of space actually used.
+/* DIAGNOSTICS
+/* The result is non-zero in case of problems, with the
+/* error type returned via the errno variable.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* dns_rr_to_sa - resource record to socket address */
+
+int dns_rr_to_sa(DNS_RR *rr, unsigned port, struct sockaddr * sa,
+ SOCKADDR_SIZE *sa_len)
+{
+ SOCKADDR_SIZE sock_addr_len;
+
+ if (rr->type == T_A) {
+ if (rr->data_len != sizeof(SOCK_ADDR_IN_ADDR(sa))) {
+ errno = EINVAL;
+ return (-1);
+ } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN_PTR(sa))) > *sa_len) {
+ errno = ENOSPC;
+ return (-1);
+ } else {
+ memset((char *) SOCK_ADDR_IN_PTR(sa), 0, sock_addr_len);
+ SOCK_ADDR_IN_FAMILY(sa) = AF_INET;
+ SOCK_ADDR_IN_PORT(sa) = port;
+ SOCK_ADDR_IN_ADDR(sa) = IN_ADDR(rr->data);
+#ifdef HAS_SA_LEN
+ sa->sa_len = sock_addr_len;
+#endif
+ *sa_len = sock_addr_len;
+ return (0);
+ }
+#ifdef HAS_IPV6
+ } else if (rr->type == T_AAAA) {
+ if (rr->data_len != sizeof(SOCK_ADDR_IN6_ADDR(sa))) {
+ errno = EINVAL;
+ return (-1);
+ } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN6_PTR(sa))) > *sa_len) {
+ errno = ENOSPC;
+ return (-1);
+ } else {
+ memset((char *) SOCK_ADDR_IN6_PTR(sa), 0, sock_addr_len);
+ SOCK_ADDR_IN6_FAMILY(sa) = AF_INET6;
+ SOCK_ADDR_IN6_PORT(sa) = port;
+ SOCK_ADDR_IN6_ADDR(sa) = IN6_ADDR(rr->data);
+#ifdef HAS_SA_LEN
+ sa->sa_len = sock_addr_len;
+#endif
+ *sa_len = sock_addr_len;
+ return (0);
+ }
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+}
+
+ /*
+ * Stand-alone test program.
+ */
+#ifdef TEST
+#include <stdlib.h>
+
+#include <stringops.h>
+#include <vstream.h>
+#include <myaddrinfo.h>
+
+static const char *myname;
+
+static NORETURN usage(void)
+{
+ msg_fatal("usage: %s dnsaddrtype hostname portnumber", myname);
+}
+
+int main(int argc, char **argv)
+{
+ DNS_RR *rr;
+ MAI_HOSTADDR_STR hostaddr;
+ MAI_SERVPORT_STR portnum;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = (struct sockaddr *) & ss;
+ SOCKADDR_SIZE sa_len = sizeof(ss);
+ VSTRING *why;
+ int type;
+ int port;
+
+ myname = argv[0];
+ if (argc < 4)
+ usage();
+ why = vstring_alloc(1);
+
+ while (*++argv) {
+ if (argv[1] == 0 || argv[2] == 0)
+ usage();
+ if ((type = dns_type(argv[0])) == 0)
+ usage();
+ if (!alldig(argv[2]) || (port = atoi(argv[2])) > 65535)
+ usage();
+ if (dns_lookup(argv[1], type, 0, &rr, (VSTRING *) 0, why) != DNS_OK)
+ msg_fatal("%s: %s", argv[1], vstring_str(why));
+ sa_len = sizeof(ss);
+ if (dns_rr_to_sa(rr, htons(port), sa, &sa_len) != 0)
+ msg_fatal("dns_rr_to_sa: %m");
+ SOCKADDR_TO_HOSTADDR(sa, sa_len, &hostaddr, &portnum, 0);
+ vstream_printf("%s %s -> %s %s\n",
+ argv[1], argv[2], hostaddr.buf, portnum.buf);
+ vstream_fflush(VSTREAM_OUT);
+ argv += 2;
+ dns_rr_free(rr);
+ }
+ vstring_free(why);
+ return (0);
+}
+
+#endif
--- /dev/null
+a spike.porcupine.org 25
+aaaa spike.porcupine.org 25
--- /dev/null
+spike.porcupine.org 25 -> 168.100.189.2 25
+spike.porcupine.org 25 -> 2001:240:5c7:0:2d0:b7ff:fe88:2ca7 25
--- /dev/null
+/*++
+/* NAME
+/* dns_sa_to_rr 3
+/* SUMMARY
+/* socket address to resource record
+/* SYNOPSIS
+/* #include <dns.h>
+/*
+/* DNS_RR *dns_sa_to_rr(hostname, pref, sa)
+/* const char *hostname;
+/* unsigned pref;
+/* struct sockaddr *sa;
+/* DESCRIPTION
+/* dns_sa_to_rr() converts a socket address into a DNS resource record.
+/*
+/* Arguments:
+/* .IP hostname
+/* The resource record host name.
+/* .IP pref
+/* The resource record MX host preference, if applicable.
+/* .IP sa
+/* Binary address.
+/* DIAGNOSTICS
+/* The result is a null pointer in case of problems, with the
+/* errno variable set to indicate the problem type.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System libraries. */
+
+#include <sys_defs.h>
+#include <errno.h>
+
+/* Utility library. */
+
+#include <msg.h>
+
+/* DNS library. */
+
+#include <dns.h>
+
+/* dns_sa_to_rr - socket address to resource record */
+
+DNS_RR *dns_sa_to_rr(const char *hostname, unsigned pref, struct sockaddr * sa)
+{
+#define DUMMY_TTL 0
+
+ if (sa->sa_family == AF_INET) {
+ return (dns_rr_create(hostname, T_A, C_IN, DUMMY_TTL, pref,
+ (char *) &SOCK_ADDR_IN_ADDR(sa),
+ sizeof(SOCK_ADDR_IN_ADDR(sa))));
+#ifdef HAS_IPV6
+ } else if (sa->sa_family == AF_INET6) {
+ return (dns_rr_create(hostname, T_AAAA, C_IN, DUMMY_TTL, pref,
+ (char *) &SOCK_ADDR_IN6_ADDR(sa),
+ sizeof(SOCK_ADDR_IN6_ADDR(sa))));
+#endif
+ } else {
+ errno = EAFNOSUPPORT;
+ return (0);
+ }
+}
+
+ /*
+ * Stand-alone test program.
+ */
+#ifdef TEST
+#include <vstream.h>
+#include <myaddrinfo.h>
+#include <inet_proto.h>
+
+static const char *myname;
+
+static NORETURN usage(void)
+{
+ msg_fatal("usage: %s hostname", myname);
+}
+
+int main(int argc, char **argv)
+{
+ MAI_HOSTADDR_STR hostaddr;
+ struct addrinfo *res0;
+ struct addrinfo *res;
+ DNS_RR *rr;
+ int aierr;
+
+ myname = argv[0];
+ if (argc < 2)
+ usage();
+
+ inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
+
+ while (*++argv) {
+ if ((aierr = hostname_to_sockaddr(argv[0], (char *) 0, 0, &res0)) != 0)
+ msg_fatal("%s: %s", argv[0], MAI_STRERROR(aierr));
+ for (res = res0; res != 0; res = res->ai_next) {
+ if ((rr = dns_sa_to_rr(argv[0], 0, res->ai_addr)) == 0)
+ msg_fatal("dns_sa_to_rr: %m");
+ if (dns_rr_to_pa(rr, &hostaddr) == 0)
+ msg_fatal("dns_rr_to_pa: %m");
+ vstream_printf("%s -> %s\n", argv[0], hostaddr.buf);
+ vstream_fflush(VSTREAM_OUT);
+ dns_rr_free(rr);
+ }
+ freeaddrinfo(res0);
+ }
+ return (0);
+}
+
+#endif
--- /dev/null
+spike.porcupine.org
--- /dev/null
+spike.porcupine.org -> 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+spike.porcupine.org -> 168.100.189.2
static void print_rr(DNS_RR *rr)
{
- struct in_addr addr;
+ MAI_HOSTADDR_STR host;
while (rr) {
printf("%s: ttl: %9d ", rr->name, rr->ttl);
switch (rr->type) {
case T_A:
- memcpy((char *) &addr.s_addr, rr->data, sizeof(addr.s_addr));
- printf("%s: %s\n", dns_strtype(rr->type), inet_ntoa(addr));
+#ifdef T_AAAA
+ case T_AAAA:
+#endif
+ if (dns_rr_to_pa(rr, &host) == 0)
+ msg_fatal("conversion error for resource record type %s: %m",
+ dns_strtype(rr->type));
+ printf("%s: %s\n", dns_strtype(rr->type), host.buf);
break;
case T_CNAME:
case T_MB:
msg_fatal("invalid query type: %s", argv[1]);
name = argv[2];
msg_verbose = 1;
- switch (dns_lookup_types(name, RES_DEFNAMES | RES_DEBUG, &rr, fqdn, why, type, 0)) {
+ switch (dns_lookup_l(name, RES_DEFNAMES | RES_DEBUG, &rr, fqdn, why,
+ DNS_REQ_FLAG_ALL, type, 0)) {
default:
msg_fatal("%s", vstring_str(why));
case DNS_OK:
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
all: $(PROG)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
fsstone: fsstone.o $(LIBS)
$(CC) $(CFLAGS) -o $@ fsstone.o $(LIBS) $(SYSLIBS)
tok822_resolve.c tok822_rewrite.c tok822_tree.c trace.c verify.c \
verify_clnt.c verp_sender.c virtual8_maps.c xtext.c scache_single.c \
scache_clnt.c scache_multi.c user_acl.c mkmap_cdb.c mkmap_sdbm.c \
- ehlo_mask.c
+ ehlo_mask.c \
+ wildcard_inet_addr.c valid_mailhost_addr.c
OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
clnt_stream.o debug_peer.o debug_process.o defer.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o trace.o verify.o \
verify_clnt.o verp_sender.o virtual8_maps.o xtext.o scache_single.o \
scache_clnt.o scache_multi.o user_acl.o mkmap_cdb.o mkmap_sdbm.o \
- ehlo_mask.o
+ ehlo_mask.o \
+ wildcard_inet_addr.o valid_mailhost_addr.o
HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
debug_peer.h debug_process.h defer.h deliver_completed.h \
resolve_local.h rewrite_clnt.h sent.h smtp_stream.h split_addr.h \
string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \
trace.h verify.h verify_clnt.h verp_sender.h virtual8_maps.h \
- xtext.h scache.h user_acl.h ehlo_mask.h
+ xtext.h scache.h user_acl.h ehlo_mask.h \
+ wildcard_inet_addr.h valid_mailhost_addr.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
off_cvt quote_822_local rec2stream recdump resolve_clnt \
resolve_local rewrite_clnt stream2rec string_list tok822_parse \
quote_821_local mail_conf_time mime_state strip_addr \
- virtual8_maps verify_clnt xtext anvil_clnt scache ehlo_mask
+ virtual8_maps verify_clnt xtext anvil_clnt scache ehlo_mask \
+ valid_mailhost_addr
LIBS = ../../lib/libutil.a
LIB_DIR = ../../lib
all: $(LIB)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
ehlo_mask: ehlo_mask.c $(LIB) $(LIBS)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+valid_mailhost_addr: valid_mailhost_addr.c $(LIB) $(LIBS)
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+
tests: tok822_test mime_test mime_nest mime_8bit mime_dom mime_trunc \
mime_cvt mime_cvt2 mime_cvt3 strip_addr_test tok822_limit_test \
- virtual8_test xtext_test scache_multi_test ehlo_mask_test
+ virtual8_test xtext_test scache_multi_test ehlo_mask_test \
+ namadr_list_test
tok822_test: tok822_parse tok822_parse.in tok822_parse.ref
./tok822_parse <tok822_parse.in >tok822_parse.tmp 2>&1
diff ehlo_mask.ref ehlo_mask.tmp
rm -f ehlo_mask.tmp
+namadr_list_test: namadr_list namadr_list.in namadr_list.ref
+ -sh namadr_list.in >namadr_list.tmp 2>&1
+ diff namadr_list.ref namadr_list.tmp
+ rm -f namadr_list.tmp
+
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
mail_params.o: ../../include/dict.h
mail_params.o: ../../include/vstream.h
mail_params.o: ../../include/argv.h
+mail_params.o: ../../include/inet_proto.h
mail_params.o: mynetworks.h
mail_params.o: mail_conf.h
mail_params.o: mail_version.h
mail_params.o: ../../include/iostuff.h
mail_params.o: ../../include/attr.h
mail_params.o: verp_sender.h
+mail_params.o: own_inet_addr.h
+mail_params.o: ../../include/inet_addr_list.h
+mail_params.o: ../../include/myaddrinfo.h
mail_params.o: mail_params.h
mail_pathname.o: mail_pathname.c
mail_pathname.o: ../../include/sys_defs.h
mynetworks.o: ../../include/vstring.h
mynetworks.o: ../../include/vbuf.h
mynetworks.o: ../../include/inet_addr_list.h
+mynetworks.o: ../../include/myaddrinfo.h
mynetworks.o: ../../include/name_mask.h
+mynetworks.o: ../../include/mask_addr.h
+mynetworks.o: ../../include/argv.h
mynetworks.o: own_inet_addr.h
mynetworks.o: mail_params.h
mynetworks.o: mynetworks.h
+mynetworks.o: ../../include/sock_addr.h
+mynetworks.o: been_here.h
mypwd.o: mypwd.c
mypwd.o: ../../include/sys_defs.h
mypwd.o: ../../include/mymalloc.h
own_inet_addr.o: ../../include/msg.h
own_inet_addr.o: ../../include/mymalloc.h
own_inet_addr.o: ../../include/inet_addr_list.h
+own_inet_addr.o: ../../include/myaddrinfo.h
own_inet_addr.o: ../../include/inet_addr_local.h
own_inet_addr.o: ../../include/inet_addr_host.h
own_inet_addr.o: ../../include/stringops.h
own_inet_addr.o: ../../include/vstring.h
own_inet_addr.o: ../../include/vbuf.h
+own_inet_addr.o: ../../include/sock_addr.h
+own_inet_addr.o: ../../include/inet_proto.h
own_inet_addr.o: mail_params.h
own_inet_addr.o: own_inet_addr.h
pipe_command.o: pipe_command.c
resolve_local.o: string_list.h
resolve_local.o: ../../include/match_list.h
resolve_local.o: ../../include/match_ops.h
+resolve_local.o: ../../include/myaddrinfo.h
+resolve_local.o: valid_mailhost_addr.h
+resolve_local.o: ../../include/valid_hostname.h
resolve_local.o: mail_params.h
resolve_local.o: own_inet_addr.h
+resolve_local.o: ../../include/inet_addr_list.h
resolve_local.o: resolve_local.h
-resolve_local.o: match_parent_style.h
rewrite_clnt.o: rewrite_clnt.c
rewrite_clnt.o: ../../include/sys_defs.h
rewrite_clnt.o: ../../include/msg.h
user_acl.o: mypwd.h
user_acl.o: mail_params.h
user_acl.o: user_acl.h
+valid_mailhost_addr.o: valid_mailhost_addr.c
+valid_mailhost_addr.o: ../../include/sys_defs.h
+valid_mailhost_addr.o: ../../include/msg.h
+valid_mailhost_addr.o: ../../include/myaddrinfo.h
+valid_mailhost_addr.o: valid_mailhost_addr.h
+valid_mailhost_addr.o: ../../include/valid_hostname.h
verify.o: verify.c
verify.o: ../../include/sys_defs.h
verify.o: ../../include/msg.h
virtual8_maps.o: mail_params.h
virtual8_maps.o: strip_addr.h
virtual8_maps.o: virtual8_maps.h
+wildcard_inet_addr.o: wildcard_inet_addr.c
+wildcard_inet_addr.o: ../../include/sys_defs.h
+wildcard_inet_addr.o: ../../include/msg.h
+wildcard_inet_addr.o: ../../include/inet_addr_list.h
+wildcard_inet_addr.o: ../../include/myaddrinfo.h
+wildcard_inet_addr.o: ../../include/inet_addr_host.h
+wildcard_inet_addr.o: wildcard_inet_addr.h
xtext.o: xtext.c
xtext.o: ../../include/sys_defs.h
xtext.o: ../../include/msg.h
/* int var_dont_remove;
/* char *var_inet_interfaces;
/* char *var_proxy_interfaces;
+/* char *var_inet_protocols;
/* char *var_mynetworks;
/* char *var_double_bounce_sender;
/* int var_line_limit;
#ifdef HAS_DB
#include <dict_db.h>
#endif
+#include <inet_proto.h>
/* Global library. */
-#include "mynetworks.h"
-#include "mail_conf.h"
-#include "mail_version.h"
-#include "mail_proto.h"
-#include "verp_sender.h"
-#include "mail_params.h"
+#include <mynetworks.h>
+#include <mail_conf.h>
+#include <mail_version.h>
+#include <mail_proto.h>
+#include <verp_sender.h>
+#include <own_inet_addr.h>
+#include <mail_params.h>
/*
* Special configuration variables.
int var_dont_remove;
char *var_inet_interfaces;
char *var_proxy_interfaces;
+char *var_inet_protocols;
char *var_mynetworks;
char *var_double_bounce_sender;
int var_line_limit;
{
static CONFIG_STR_TABLE first_str_defaults[] = {
VAR_SYSLOG_FACILITY, DEF_SYSLOG_FACILITY, &var_syslog_facility, 1, 0,
+ VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 1, 0,
0,
};
static CONFIG_STR_FN_TABLE function_str_defaults[] = {
0,
};
const char *cp;
+ INET_PROTO_INFO *proto_info;
/*
* Extract syslog_facility early, so that from here on all errors are
var_config_dir, MAIN_CONF_FILE,
VAR_SYSLOG_FACILITY, var_syslog_facility);
+ /*
+ * What protocols should we attempt to support? The result is stored in
+ * the global inet_proto_table variable.
+ */
+ proto_info = inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols);
+
/*
* Variables whose defaults are determined at runtime. Some sites use
* short hostnames in the host table; some sites name their system after
*/
get_mail_conf_str_fn_table(function_str_defaults_2);
+ /*
+ * FIX 200412 The IPv6 patch did not call own_inet_addr_list() before
+ * entering the chroot jail on Linux IPv6 systems. Linux has the IPv6
+ * interface list in /proc, which is not available after chrooting.
+ */
+ (void) own_inet_addr_list();
+
/*
* The PID variable cannot be set from the configuration file!!
*/
* Virtual host support. Default is to listen on all machine interfaces.
*/
#define VAR_INET_INTERFACES "inet_interfaces" /* listen addresses */
-#define DEF_INET_INTERFACES "all"
+#define INET_INTERFACES_ALL "all"
+#define INET_INTERFACES_LOCAL "loopback-only"
+#define DEF_INET_INTERFACES INET_INTERFACES_ALL
extern char *var_inet_interfaces;
#define VAR_PROXY_INTERFACES "proxy_interfaces" /* proxies, NATs */
* subdirectories, and how deep the forest is.
*/
#define VAR_HASH_QUEUE_NAMES "hash_queue_names"
-#define DEF_HASH_QUEUE_NAMES "incoming, active, deferred, bounce, defer, flush, hold, trace"
+#define DEF_HASH_QUEUE_NAMES "deferred, defer"
extern char *var_hash_queue_names;
#define VAR_HASH_QUEUE_DEPTH "hash_queue_depth"
#define DEF_HASH_QUEUE_DEPTH 1
extern int var_hash_queue_depth;
+ /*
+ * Multi-protocol support.
+ */
+#define INET_PROTO_NAME_IPV4 "ipv4"
+#define INET_PROTO_NAME_IPV6 "ipv6"
+#define INET_PROTO_NAME_ALL "all"
+#define VAR_INET_PROTOCOLS "inet_protocols"
+extern char *var_inet_protocols;
+
/*
* SMTP client. Timeouts inspired by RFC 1123. The SMTP recipient limit
* determines how many recipient addresses the SMTP client sends along with
#define DEF_SMTP_BIND_ADDR ""
extern char *var_smtp_bind_addr;
+#define VAR_SMTP_BIND_ADDR6 "smtp_bind_address6"
+#define DEF_SMTP_BIND_ADDR6 ""
+extern char *var_smtp_bind_addr6;
+
#define VAR_SMTP_HELO_NAME "smtp_helo_name"
#define DEF_SMTP_HELO_NAME "$myhostname"
extern char *var_smtp_helo_name;
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
-#define MAIL_RELEASE_DATE "20041230"
+#define MAIL_RELEASE_DATE "20050117"
#define MAIL_VERSION_NUMBER "2.2"
#define VAR_MAIL_VERSION "mail_version"
vstream_fprintf(stream, "BODY END\n");
}
-static void err_print(void *context, int err_flag, const char *text)
+static void err_print(void *unused_context, int err_flag, const char *text)
{
msg_warn("%s: %.100s", mime_state_error(err_flag), text);
}
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Dean C. Strik
+/* Department ICT Services
+/* Eindhoven University of Technology
+/* P.O. Box 513
+/* 5600 MB Eindhoven, Netherlands
+/* E-mail: <dean@ipnet6.org>
/*--*/
/* System library. */
#define IN_CLASSD_NSHIFT 28
#endif
-#define BITS_PER_ADDR 32
-
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <inet_addr_list.h>
#include <name_mask.h>
+#include <myaddrinfo.h>
+#include <mask_addr.h>
+#include <argv.h>
/* Global library. */
#include <own_inet_addr.h>
#include <mail_params.h>
#include <mynetworks.h>
+#include <sock_addr.h>
+#include <been_here.h>
/* Application-specific. */
char *myname = "mynetworks";
INET_ADDR_LIST *my_addr_list;
INET_ADDR_LIST *my_mask_list;
- unsigned long addr;
- unsigned long mask;
- struct in_addr net;
int shift;
int junk;
int i;
int mask_style;
+ struct sockaddr_storage *sa;
+ struct sockaddr_storage *ma;
+ int net_mask_count = 0;
+ ARGV *argv;
+ BH_TABLE *dup_filter;
+ char **cpp;
mask_style = name_mask("mynetworks mask style", mask_styles,
var_mynetworks_style);
my_addr_list = own_inet_addr_list();
my_mask_list = own_inet_mask_list();
- for (i = 0; i < my_addr_list->used; i++) {
- addr = ntohl(my_addr_list->addrs[i].s_addr);
- mask = ntohl(my_mask_list->addrs[i].s_addr);
-
- switch (mask_style) {
-
- /*
- * Natural mask. This is dangerous if you're customer of an
- * ISP who gave you a small portion of their network.
- */
- case MASK_STYLE_CLASS:
- if (IN_CLASSA(addr)) {
- mask = IN_CLASSA_NET;
- shift = IN_CLASSA_NSHIFT;
- } else if (IN_CLASSB(addr)) {
- mask = IN_CLASSB_NET;
- shift = IN_CLASSB_NSHIFT;
- } else if (IN_CLASSC(addr)) {
- mask = IN_CLASSC_NET;
- shift = IN_CLASSC_NSHIFT;
- } else if (IN_CLASSD(addr)) {
- mask = IN_CLASSD_NET;
- shift = IN_CLASSD_NSHIFT;
- } else {
- msg_fatal("%s: bad address class: %s",
- myname, inet_ntoa(my_addr_list->addrs[i]));
+ for (sa = my_addr_list->addrs, ma = my_mask_list->addrs;
+ sa < my_addr_list->addrs + my_addr_list->used;
+ sa++, ma++) {
+ unsigned long addr;
+ unsigned long mask;
+ struct in_addr net;
+
+ if (SOCK_ADDR_FAMILY(sa) == AF_INET) {
+ addr = ntohl(SOCK_ADDR_IN_ADDR(sa).s_addr);
+ mask = ntohl(SOCK_ADDR_IN_ADDR(ma).s_addr);
+
+ switch (mask_style) {
+
+ /*
+ * Natural mask. This is dangerous if you're customer of
+ * an ISP who gave you a small portion of their network.
+ */
+ case MASK_STYLE_CLASS:
+ if (IN_CLASSA(addr)) {
+ mask = IN_CLASSA_NET;
+ shift = IN_CLASSA_NSHIFT;
+ } else if (IN_CLASSB(addr)) {
+ mask = IN_CLASSB_NET;
+ shift = IN_CLASSB_NSHIFT;
+ } else if (IN_CLASSC(addr)) {
+ mask = IN_CLASSC_NET;
+ shift = IN_CLASSC_NSHIFT;
+ } else if (IN_CLASSD(addr)) {
+ mask = IN_CLASSD_NET;
+ shift = IN_CLASSD_NSHIFT;
+ } else {
+ msg_fatal("%s: unknown address class: %s",
+ myname, inet_ntoa(SOCK_ADDR_IN_ADDR(sa)));
+ }
+ break;
+
+ /*
+ * Subnet mask. This is less unsafe, but still bad if
+ * you're connected to a large subnet.
+ */
+ case MASK_STYLE_SUBNET:
+ for (junk = mask, shift = MAI_V4ADDR_BITS; junk != 0;
+ shift--, junk <<= 1)
+ /* void */ ;
+ break;
+
+ /*
+ * Host only. Do not relay authorize other hosts.
+ */
+ case MASK_STYLE_HOST:
+ mask = ~0;
+ shift = 0;
+ break;
+
+ default:
+ msg_panic("unknown mynetworks mask style: %s",
+ var_mynetworks_style);
}
- break;
-
- /*
- * Subnet mask. This is safe, but breaks backwards
- * compatibility when used as default setting.
- */
- case MASK_STYLE_SUBNET:
- for (junk = mask, shift = BITS_PER_ADDR; junk != 0; shift--, (junk <<= 1))
- /* void */ ;
- break;
-
- /*
- * Host only. Do not relay authorize other hosts.
- */
- case MASK_STYLE_HOST:
- mask = ~0;
- shift = 0;
- break;
-
- default:
- msg_panic("unknown mynetworks mask style: %s",
- var_mynetworks_style);
+ net.s_addr = htonl(addr & mask);
+ vstring_sprintf_append(result, "%s/%d ",
+ inet_ntoa(net), MAI_V4ADDR_BITS - shift);
+ net_mask_count++;
+ continue;
+ }
+#ifdef HAS_IPV6
+ else if (SOCK_ADDR_FAMILY(sa) == AF_INET6) {
+ MAI_HOSTADDR_STR hostaddr;
+ unsigned char *ac;
+ unsigned char *end;
+ unsigned char ch;
+ struct sockaddr_in6 net6;
+
+ switch (mask_style) {
+
+ /*
+ * There are no classes for IPv6. We default to subnets
+ * instead.
+ */
+ case MASK_STYLE_CLASS:
+
+ /* FALLTHROUGH */
+
+ /*
+ * Subnet mask.
+ */
+ case MASK_STYLE_SUBNET:
+ ac = (unsigned char *) &SOCK_ADDR_IN6_ADDR(ma);
+ end = ac + sizeof(SOCK_ADDR_IN6_ADDR(ma));
+ shift = MAI_V6ADDR_BITS;
+ while (ac < end) {
+ if ((ch = *ac++) == (unsigned char) -1) {
+ shift -= CHAR_BIT;
+ continue;
+ } else {
+ while (ch != 0)
+ shift--, ch <<= 1;
+ break;
+ }
+ }
+ break;
+
+ /*
+ * Host only. Do not relay authorize other hosts.
+ */
+ case MASK_STYLE_HOST:
+ shift = 0;
+ break;
+
+ default:
+ msg_panic("unknown mynetworks mask style: %s",
+ var_mynetworks_style);
+ }
+ /* FIX 200501: IPv6 patch did not clear host bits. */
+ net6 = *SOCK_ADDR_IN6_PTR(sa);
+ mask_addr((unsigned char *) &net6.sin6_addr,
+ sizeof(net6.sin6_addr),
+ MAI_V6ADDR_BITS - shift);
+ SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(&net6), SOCK_ADDR_LEN(&net6),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ vstring_sprintf_append(result, "[%s]/%d ",
+ hostaddr.buf, MAI_V6ADDR_BITS - shift);
+ net_mask_count++;
+ continue;
+ }
+#endif
+ else {
+ msg_warn("%s: skipping unknown address family %d",
+ myname, SOCK_ADDR_FAMILY(sa));
+ continue;
}
- net.s_addr = htonl(addr & mask);
- vstring_sprintf_append(result, "%s/%d ",
- inet_ntoa(net), BITS_PER_ADDR - shift);
+ }
+
+ /*
+ * FIX 200501 IPv6 patch produced repeated results. Some systems
+ * report the same interface multiple times, notably multi-homed
+ * systems with IPv6 link-local or site-local addresses. A
+ * straight-forward sort+uniq produces ugly results, though. Instead
+ * we preserve the original order and use a duplicate filter to
+ * suppress repeated information.
+ */
+ if (net_mask_count > 1) {
+ argv = argv_split(vstring_str(result), " ");
+ VSTRING_RESET(result);
+ dup_filter = been_here_init(net_mask_count, BH_FLAG_NONE);
+ for (cpp = argv->argv; cpp < argv->argv + argv->argc; cpp++)
+ if (!been_here_fixed(dup_filter, *cpp))
+ vstring_sprintf_append(result, "%s ", *cpp);
+ argv_free(argv);
+ been_here_free(dup_filter);
}
if (msg_verbose)
msg_info("%s: %s", myname, vstring_str(result));
}
#ifdef TEST
+#include <inet_proto.h>
char *var_inet_interfaces;
char *var_mynetworks_style;
int main(int argc, char **argv)
{
- if (argc != 3)
- msg_fatal("usage: %s mask_style interface_list", argv[0]);
+ INET_PROTO_INFO *proto_info;
+
+ if (argc != 4)
+ msg_fatal("usage: %s protocols mask_style interface_list (e.g. \"all subnet all\")",
+ argv[0]);
msg_verbose = 10;
- var_inet_interfaces = argv[2];
- var_mynetworks_style = argv[1];
+ proto_info = inet_proto_init(argv[0], argv[1]);
+ var_mynetworks_style = argv[2];
+ var_inet_interfaces = argv[3];
mynetworks();
}
--- /dev/null
+./namadr_list 168.100.189.0/28 dummy 168.100.189.2
+./namadr_list 168.100.189.0/28 dummy 168.100.189.16
+./namadr_list 168.100.189.0/98 dummy 168.100.189.16
+./namadr_list 168.100.589.0/28 dummy 168.100.189.16
+./namadr_list 168.100.189.0/28 dummy 168.100.989.16
+./namadr_list 2001:240:5c7:0:2d0:b7ff:fe88:2ca7 dummy 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+./namadr_list '[2001:240:5c7:0:2d0:b7ff:fe88:2ca7]' dummy 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+./namadr_list '[2001:240:5c7:0:2d0:b7ff:fe88:2ca7]' dummy 2001:240:5c7:0:2d0:b7ff:fe88:2ca8
+./namadr_list '[2001:240:5c7:0:2d0:b7ff:fe88:2ca7]/64' dummy 2001:240:5c7:0:2d0:b7ff:fe88:2ca8
+./namadr_list '[2001:240:5c7::]/64' dummy 2001:240:5c7:0:2d0:b7ff:fe88:2ca8
+./namadr_list '[2001:240:5c7::]/64' dummy 2001:24:5c7:0:2d0:b7ff:fe88:2ca8
+./namadr_list '[2001:24:5c7:0:2d0:b7ff:fe88:2ca8]' dummy 2001:24:5c7:0:2d0:b7ff:fe88:2ca8
+./namadr_list '[2001:24:5c7:0:2d0:b7ff:fe88:2ca8]' dummy 2001:24:5c7:0:2d0:b7ff:fe88:2ca7
+./namadr_list 168.100.189.2 dummy 168.100.189.2
+./namadr_list 168.100.189.2 dummy 168.100.189.3
+./namadr_list '[168.100.189.2]' dummy 168.100.189.2
+./namadr_list '[168.100.189.2]' dummy 168.100.189.3
--- /dev/null
+dummy/168.100.189.2: YES
+dummy/168.100.189.16: NO
+./namadr_list: fatal: bad net/mask pattern: "168.100.189.0/98"
+./namadr_list: fatal: bad net/mask pattern: "168.100.589.0/28"
+dummy/168.100.989.16: NO
+./namadr_list: fatal: unsupported dictionary type: 2001
+dummy/2001:240:5c7:0:2d0:b7ff:fe88:2ca7: YES
+dummy/2001:240:5c7:0:2d0:b7ff:fe88:2ca8: NO
+./namadr_list: fatal: non-null host address bits in "2001:240:5c7:0:2d0:b7ff:fe88:2ca7/64", perhaps you should use "2001:240:5c7::/64" instead
+dummy/2001:240:5c7:0:2d0:b7ff:fe88:2ca8: YES
+dummy/2001:24:5c7:0:2d0:b7ff:fe88:2ca8: NO
+dummy/2001:24:5c7:0:2d0:b7ff:fe88:2ca8: YES
+dummy/2001:24:5c7:0:2d0:b7ff:fe88:2ca7: NO
+dummy/168.100.189.2: YES
+dummy/168.100.189.3: NO
+dummy/168.100.189.2: YES
+dummy/168.100.189.3: NO
/* System library. */
#include <sys_defs.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
#include <inet_addr_local.h>
#include <inet_addr_host.h>
#include <stringops.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
+#include <inet_proto.h>
/* Global library. */
char *bufp;
int nvirtual;
int nlocal;
+ MAI_HOSTADDR_STR hostaddr;
+ struct sockaddr_storage *sa;
+ struct sockaddr_storage *ma;
inet_addr_list_init(addr_list);
inet_addr_list_init(mask_list);
* If we are listening on all interfaces (default), ask the system what
* the interfaces are.
*/
- if (strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) == 0) {
- if (inet_addr_local(addr_list, mask_list) == 0)
+ if (strcmp(var_inet_interfaces, INET_INTERFACES_ALL) == 0) {
+ if (inet_addr_local(addr_list, mask_list,
+ inet_proto_info()->ai_family_list) == 0)
msg_fatal("could not find any active network interfaces");
-#if 0
- if (addr_list->used == 1)
- msg_warn("found only one active network interface: %s",
- inet_ntoa(addr_list->addrs[0]));
-#endif
+ }
+
+ /*
+ * Select all loopback interfaces from the system's available interface
+ * list.
+ */
+ else if (strcmp(var_inet_interfaces, INET_INTERFACES_LOCAL) == 0) {
+ inet_addr_list_init(&local_addrs);
+ inet_addr_list_init(&local_masks);
+ if (inet_addr_local(&local_addrs, &local_masks,
+ inet_proto_info()->ai_family_list) == 0)
+ msg_fatal("could not find any active network interfaces");
+ for (sa = local_addrs.addrs, ma = local_masks.addrs;
+ sa < local_addrs.addrs + local_addrs.used; sa++, ma++) {
+ if (sock_addr_in_loopback(SOCK_ADDR_PTR(sa))) {
+ inet_addr_list_append(addr_list, SOCK_ADDR_PTR(sa));
+ inet_addr_list_append(mask_list, SOCK_ADDR_PTR(ma));
+ }
+ }
+ inet_addr_list_free(&local_addrs);
+ inet_addr_list_free(&local_masks);
}
/*
*/
inet_addr_list_uniq(addr_list);
+ /*
+ * Find out the netmask for each virtual interface, by looking it up
+ * among all the local interfaces.
+ */
inet_addr_list_init(&local_addrs);
inet_addr_list_init(&local_masks);
- if (inet_addr_local(&local_addrs, &local_masks) == 0)
+ if (inet_addr_local(&local_addrs, &local_masks,
+ inet_proto_info()->ai_family_list) == 0)
msg_fatal("could not find any active network interfaces");
for (nvirtual = 0; nvirtual < addr_list->used; nvirtual++) {
for (nlocal = 0; /* see below */ ; nlocal++) {
- if (nlocal >= local_addrs.used)
+ if (nlocal >= local_addrs.used) {
+ SOCKADDR_TO_HOSTADDR(
+ SOCK_ADDR_PTR(addr_list->addrs + nvirtual),
+ SOCK_ADDR_LEN(addr_list->addrs + nvirtual),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
msg_fatal("parameter %s: no local interface found for %s",
- VAR_INET_INTERFACES,
- inet_ntoa(addr_list->addrs[nvirtual]));
- if (addr_list->addrs[nvirtual].s_addr
- == local_addrs.addrs[nlocal].s_addr) {
- inet_addr_list_append(mask_list, &local_masks.addrs[nlocal]);
+ VAR_INET_INTERFACES, hostaddr.buf);
+ }
+ if (SOCK_ADDR_EQ_ADDR(addr_list->addrs + nvirtual,
+ local_addrs.addrs + nlocal)) {
+ inet_addr_list_append(mask_list,
+ SOCK_ADDR_PTR(local_masks.addrs + nlocal));
break;
}
}
/* own_inet_addr - is this my own internet address */
-int own_inet_addr(struct in_addr * addr)
+int own_inet_addr(struct sockaddr * addr)
{
int i;
own_inet_addr_init(&addr_list, &mask_list);
for (i = 0; i < addr_list.used; i++)
- if (addr->s_addr == addr_list.addrs[i].s_addr)
+ if (SOCK_ADDR_EQ_ADDR(addr, addr_list.addrs + i))
return (1);
return (0);
}
/* proxy_inet_addr - is this my proxy internet address */
-int proxy_inet_addr(struct in_addr * addr)
+int proxy_inet_addr(struct sockaddr * addr)
{
int i;
proxy_inet_addr_init(&proxy_list);
for (i = 0; i < proxy_list.used; i++)
- if (addr->s_addr == proxy_list.addrs[i].s_addr)
+ if (SOCK_ADDR_EQ_ADDR(addr, proxy_list.addrs + i))
return (1);
return (0);
}
/* .nf
/*
- * System library.
+ * Utility library.
*/
-#include <netinet/in.h>
+#include <inet_addr_list.h>
/*
* External interface.
*/
-extern int own_inet_addr(struct in_addr *);
+extern int own_inet_addr(struct sockaddr *);
extern struct INET_ADDR_LIST *own_inet_addr_list(void);
extern struct INET_ADDR_LIST *own_inet_mask_list(void);
-extern int proxy_inet_addr(struct in_addr *);
+extern int proxy_inet_addr(struct sockaddr *);
extern struct INET_ADDR_LIST *proxy_inet_addr_list(void);
/* LICENSE
/* resolve_local() determines if the named domain resolves to the
/* local mail system, either by case-insensitive exact match
/* against the domains, files or tables listed in $mydestination,
-/* or by any of the network addresses listed in $inet_interfaces
-/* or in $proxy_interfaces.
+/* or by a match of an [address-literal] against of the network
+/* addresses listed in $inet_interfaces or in $proxy_interfaces.
/*
/* resolve_local_init() performs initialization. If this routine is
/* not called explicitly ahead of time, it will be called on the fly.
/* System library. */
#include <sys_defs.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <string.h>
-
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <string_list.h>
+#include <myaddrinfo.h>
+#include <valid_mailhost_addr.h>
/* Global library. */
#include <mail_params.h>
#include <own_inet_addr.h>
#include <resolve_local.h>
-#include <match_parent_style.h>
/* Application-specific */
{
char *saved_addr = mystrdup(addr);
char *dest;
- struct in_addr ipaddr;
+ const char *bare_dest;
+ struct addrinfo *res0 = 0;
int len;
-#define RETURN(x) { myfree(saved_addr); return(x); }
+#define RETURN(x) \
+ do { \
+ myfree(saved_addr); \
+ if (res0) \
+ freeaddrinfo(res0); \
+ return(x); \
+ } while (0)
if (resolve_local_list == 0)
resolve_local_init();
/*
* Strip one trailing dot but not dot-dot.
- *
+ *
* XXX This should not be distributed all over the code. Problem is,
- * addresses can enter the system via multiple paths: networks, local
+ * addresses can enter the system via multiple paths: networks, local
* forward/alias/include files, even as the result of address rewriting.
*/
len = strlen(saved_addr);
/*
* Compare the destination against the list of interface addresses that
* we are supposed to listen on.
+ *
+ * The destination may be an IPv6 address literal that was buried somewhere
+ * inside a deeply recursively nested address. This information comes
+ * from an untrusted source, and Wietse is not confident that everyone's
+ * getaddrinfo() etc. implementation is sufficiently robust. The syntax
+ * is complex enough with null field compression and with IPv4-in-IPv6
+ * addresses that errors are likely.
+ *
+ * The solution below is ad-hoc. We neutralize the string as soon as we
+ * realize that its contents could be harmful. We neutralize the string
+ * here, instead of neutralizing it in every resolve_local() caller.
+ * That's because resolve_local knows how the address is going to be
+ * parsed and converted into binary form.
+ *
+ * There are several more structural solutions to this.
+ *
+ * - One solution is to disallow address literals. This is not as bad as it
+ * seems: I have never seen actual legitimate use of address literals.
+ *
+ * - Another solution is to label each string with a trustworthiness label
+ * and to expect that all Postfix infrastructure will exercise additional
+ * caution when given a string with untrusted content. This is not likely
+ * to happen.
+ *
+ * FIX 200501 IPv6 patch did not require "IPv6:" prefix in numerical
+ * addresses.
*/
dest = saved_addr;
if (*dest == '[' && dest[len - 1] == ']') {
dest++;
dest[len -= 2] = 0;
- if ((ipaddr.s_addr = inet_addr(dest)) != INADDR_NONE
- && (own_inet_addr(&ipaddr) || proxy_inet_addr(&ipaddr)))
- RETURN(1);
+ if ((bare_dest = valid_mailhost_addr(dest, DO_GRIPE)) != 0
+ && hostaddr_to_sockaddr(bare_dest, (char *) 0, 0, &res0) == 0) {
+ if (own_inet_addr(res0->ai_addr) || proxy_inet_addr(res0->ai_addr))
+ RETURN(1);
+ }
}
/*
int smtp_fgetc(VSTREAM *stream)
{
- int err;
int ch;
/*
--- /dev/null
+/*++
+/* NAME
+/* valid_mailhost_addr 3
+/* SUMMARY
+/* mailhost address syntax validation
+/* SYNOPSIS
+/* #include <valid_mailhost_addr.h>
+/*
+/* const char *valid_mailhost_addr(name, gripe)
+/* const char *name;
+/* int gripe;
+/*
+/* int valid_mailhost_literal(addr, gripe)
+/* const char *addr;
+/* int gripe;
+/* DESCRIPTION
+/* valid_mailhost_addr() requires that the input is a valid
+/* RFC 2821 string representation of an IPv4 or IPv6 network
+/* address. A valid IPv4 address is in dotted quad decimal
+/* form. A valid IPv6 address includes the "IPV6:" prefix as
+/* required by RFC 2821, and is in valid hexadecimal form or
+/* in valid IPv4-in-IPv6 form. The result value is the bare
+/* address in the input argument (i.e. text after "IPV6:"
+/* prefix, if any) in case of success, a null pointer in case
+/* of failure.
+/*
+/* valid_mailhost_literal() requires an address enclosed in
+/* []. The result is non-zero in case of success, zero in
+/* case of failure.
+/*
+/* These routines operate silently unless the gripe parameter
+/* specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
+/* provide suitable constants.
+/*
+/* The IPV6_COL macro defines the "IPv6:" prefix.
+/* DIAGNOSTICS
+/* Warnings are logged with msg_warn().
+/* SEE ALSO
+/* valid_hostname(3)
+/* RFC 952, RFC 1123, RFC 1035, RFC 2821
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <myaddrinfo.h>
+
+/* Global library. */
+
+#include <valid_mailhost_addr.h>
+
+/* Application-specific. */
+
+#define IPV6_COL_LEN (sizeof(IPV6_COL) - 1)
+#define HAS_IPV6_COL(str) (strncasecmp((str), IPV6_COL, IPV6_COL_LEN) == 0)
+#define SKIP_IPV6_COL(str) (HAS_IPV6_COL(str) ? (str) + IPV6_COL_LEN : (str))
+
+/* valid_mailhost_addr - validate RFC 2821 numerical address form */
+
+const char *valid_mailhost_addr(const char *addr, int gripe)
+{
+ const char *bare_addr;
+
+ bare_addr = SKIP_IPV6_COL(addr);
+ return ((bare_addr != addr ? valid_ipv6_hostaddr : valid_ipv4_hostaddr)
+ (bare_addr, gripe) ? bare_addr : 0);
+}
+
+/* valid_mailhost_literal - validate [RFC 2821 numerical address] form */
+
+int valid_mailhost_literal(const char *addr, int gripe)
+{
+ const char *myname = "valid_mailhost_literal";
+ MAI_HOSTADDR_STR hostaddr;
+ const char *last;
+ size_t address_bytes;
+
+ if (*addr != '[') {
+ if (gripe)
+ msg_warn("%s: '[' expected at start: %.100s", myname, addr);
+ return (0);
+ }
+ if ((last = strchr(addr, ']')) == 0) {
+ if (gripe)
+ msg_warn("%s: ']' expected at end: %.100s", myname, addr);
+ return (0);
+ }
+ if (last[1]) {
+ if (gripe)
+ msg_warn("%s: unexpected text after ']': %.100s", myname, addr);
+ return (0);
+ }
+ if ((address_bytes = last - addr - 1) >= sizeof(hostaddr.buf)) {
+ if (gripe)
+ msg_warn("%s: too much text: %.100s", myname, addr);
+ return (0);
+ }
+ strncpy(hostaddr.buf, addr + 1, address_bytes);
+ hostaddr.buf[address_bytes] = 0;
+ return (valid_mailhost_addr(hostaddr.buf, gripe) != 0);
+}
+
+#ifdef TEST
+
+ /*
+ * Test program - reads hostnames from stdin, reports invalid hostnames to
+ * stderr.
+ */
+#include <stdlib.h>
+
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <msg_vstream.h>
+
+int main(int unused_argc, char **argv)
+{
+ VSTRING *buffer = vstring_alloc(1);
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+ msg_verbose = 1;
+
+ while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
+ msg_info("testing: \"%s\"", vstring_str(buffer));
+ if (vstring_str(buffer)[0] == '[')
+ valid_mailhost_literal(vstring_str(buffer), DO_GRIPE);
+ else
+ valid_mailhost_addr(vstring_str(buffer), DO_GRIPE);
+ }
+ exit(0);
+}
+
+#endif
--- /dev/null
+#ifndef _VALID_MAILHOST_ADDR_H_INCLUDED_
+#define _VALID_MAILHOST_ADDR_H_INCLUDED_
+
+/*++
+/* NAME
+/* valid_mailhost_addr 3h
+/* SUMMARY
+/* mailhost address syntax validation
+/* SYNOPSIS
+/* #include <valid_mailhost_addr.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <valid_hostname.h>
+
+ /*
+ * External interface
+ */
+#define IPV6_COL "IPv6:" /* RFC 2821 */
+
+extern const char *valid_mailhost_addr(const char *, int);
+extern int valid_mailhost_literal(const char *, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* wildcard_inet_addr 3
+/* SUMMARY
+/* expand wild-card address
+/* SYNOPSIS
+/* #include <wildcard_inet_addr.h>
+/*
+/* INET_ADDR_LIST *wildcard_inet_addr(void)
+/* DESCRIPTION
+/* wildcard_inet_addr() determines all wild-card addresses
+/* for all supported address families.
+/* DIAGNOSTICS
+/* Fatal errors: out of memory.
+/* SEE ALSO
+/* inet_addr_list(3) address list management
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Dean C. Strik
+/* Department ICT
+/* Eindhoven University of Technology
+/* P.O. Box 513
+/* 5600 MB Eindhoven, Netherlands
+/* E-mail: <dean@ipnet6.org>
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <inet_addr_list.h>
+#include <inet_addr_host.h>
+
+/* Global library. */
+
+#include <wildcard_inet_addr.h>
+
+/* Application-specific. */
+
+static INET_ADDR_LIST wild_addr_list;
+
+static void wildcard_inet_addr_init(INET_ADDR_LIST *addr_list)
+{
+ inet_addr_list_init(addr_list);
+ if (inet_addr_host(addr_list, "") == 0)
+ msg_fatal("could not get list of wildcard addresses");
+}
+
+/* wildcard_inet_addr_list - return list of addresses */
+
+INET_ADDR_LIST *wildcard_inet_addr_list(void)
+{
+ if (wild_addr_list.used == 0)
+ wildcard_inet_addr_init(&wild_addr_list);
+
+ return (&wild_addr_list);
+}
--- /dev/null
+#ifndef _WILDCARD_INET_ADDR_H_INCLUDED_
+#define _WILDCARD_INET_ADDR_H_INCLUDED_
+
+/*++
+/* NAME
+/* wildcard_inet_addr 3h
+/* SUMMARY
+/* grab the list of wildcard IP addresses.
+/* SYNOPSIS
+/* #include <wildcard_inet_addr.h>
+/* DESCRIPTION
+/* .nf
+/*--*/
+
+ /*
+ * Utility library.
+ */
+#include <inet_addr_list.h>
+
+ /*
+ * External interface.
+ */
+extern struct INET_ADDR_LIST *wildcard_inet_addr_list(void);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* foo
+/* AUTHOR(S)
+/* Jun-ichiro itojun Hagino
+/*--*/
+
+#endif
return (len);
}
-main(int unused_argc, char **unused_argv)
+int main(int unused_argc, char **unused_argv)
{
VSTRING *unquoted = vstring_alloc(BUFLEN);
VSTRING *quoted = vstring_alloc(100);
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
lmtp_addr.o: ../../include/vbuf.h
lmtp_addr.o: ../../include/mymalloc.h
lmtp_addr.o: ../../include/inet_addr_list.h
+lmtp_addr.o: ../../include/myaddrinfo.h
lmtp_addr.o: ../../include/stringops.h
+lmtp_addr.o: ../../include/sock_addr.h
+lmtp_addr.o: ../../include/inet_proto.h
lmtp_addr.o: ../../include/mail_params.h
lmtp_addr.o: ../../include/own_inet_addr.h
lmtp_addr.o: ../../include/dns.h
lmtp_connect.o: ../../include/stringops.h
lmtp_connect.o: ../../include/host_port.h
lmtp_connect.o: ../../include/sane_connect.h
+lmtp_connect.o: ../../include/inet_addr_list.h
+lmtp_connect.o: ../../include/myaddrinfo.h
+lmtp_connect.o: ../../include/sock_addr.h
lmtp_connect.o: ../../include/mail_params.h
lmtp_connect.o: ../../include/mail_proto.h
lmtp_connect.o: ../../include/attr.h
+lmtp_connect.o: ../../include/own_inet_addr.h
lmtp_connect.o: ../../include/dns.h
lmtp_connect.o: lmtp.h
lmtp_connect.o: ../../include/argv.h
#include <string.h>
#include <unistd.h>
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <inet_addr_list.h>
#include <stringops.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
+#include <inet_proto.h>
/* Global library. */
static void lmtp_print_addr(char *what, DNS_RR *addr_list)
{
DNS_RR *addr;
- struct in_addr in_addr;
+ MAI_HOSTADDR_STR hostaddr;
msg_info("begin %s address list", what);
for (addr = addr_list; addr; addr = addr->next) {
- if (addr->data_len > sizeof(addr)) {
- msg_warn("skipping address length %d", addr->data_len);
+ if (dns_rr_to_pa(addr, &hostaddr) == 0) {
+ msg_warn("skipping record type %s: %m", dns_strtype(addr->type));
} else {
- memcpy((char *) &in_addr, addr->data, sizeof(in_addr));
msg_info("pref %4d host %s/%s",
addr->pref, addr->name,
- inet_ntoa(in_addr));
+ hostaddr.buf);
}
}
msg_info("end %s address list", what);
static DNS_RR *lmtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
{
char *myname = "lmtp_addr_one";
- struct in_addr inaddr;
- DNS_FIXED fixed;
DNS_RR *addr = 0;
DNS_RR *rr;
- struct hostent *hp;
+ int aierr;
+ struct addrinfo *res0;
+ struct addrinfo *res;
+ INET_PROTO_INFO *proto_info = inet_proto_info();
+ int found;
if (msg_verbose)
msg_info("%s: host %s", myname, host);
/*
* Interpret a numerical name as an address.
*/
- if (ISDIGIT(host[0]) && (inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
- memset((char *) &fixed, 0, sizeof(fixed));
- return (dns_rr_append(addr_list,
- dns_rr_create(host, &fixed, pref,
- (char *) &inaddr, sizeof(inaddr))));
+ if (hostaddr_to_sockaddr(host, (char *) 0, 0, &res0) == 0
+ && strchr((char *) proto_info->sa_family_list, res0->ai_family) != 0) {
+ if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0)
+ msg_fatal("host %s: conversion error for address family %d: %m",
+ host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
+ addr_list = dns_rr_append(addr_list, addr);
+ freeaddrinfo(res0);
+ return (addr_list);
}
/*
- * Use gethostbyname() when DNS is disabled.
+ * Use native name service when DNS is disabled.
*/
+#define RETRY_AI_ERROR(e) \
+ ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
+
if (var_disable_dns) {
- memset((char *) &fixed, 0, sizeof(fixed));
- if ((hp = gethostbyname(host)) == 0) {
- vstring_sprintf(why, "%s: host not found", host);
- lmtp_errno = LMTP_FAIL;
- } else if (hp->h_addrtype != AF_INET) {
- vstring_sprintf(why, "%s: host not found", host);
- msg_warn("%s: unknown address family %d for %s",
- myname, hp->h_addrtype, host);
- lmtp_errno = LMTP_FAIL;
+ if ((aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0)) != 0) {
+ vstring_sprintf(why, "%s: %s", host, MAI_STRERROR(aierr));
+ lmtp_errno = (RETRY_AI_ERROR(aierr) ? LMTP_RETRY : LMTP_FAIL);
} else {
- while (hp->h_addr_list[0]) {
- addr_list = dns_rr_append(addr_list,
- dns_rr_create(host, &fixed, pref,
- hp->h_addr_list[0],
- sizeof(inaddr)));
- hp->h_addr_list++;
+ for (found = 0, res = res0; res != 0; res = res->ai_next) {
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, host);
+ continue;
+ }
+ found++;
+ if ((addr = dns_sa_to_rr(host, pref, res->ai_addr)) == 0)
+ msg_fatal("host %s: conversion error for address family %d: %m",
+ host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
+ addr_list = dns_rr_append(addr_list, addr);
+ }
+ freeaddrinfo(res0);
+ if (found == 0) {
+ vstring_sprintf(why, "%s: host not found", host);
+ lmtp_errno = LMTP_FAIL;
}
+ return (addr_list);
}
- return (addr_list);
}
/*
* Append the addresses for this host to the address list.
*/
- switch (dns_lookup(host, T_A, RES_DEFNAMES, &addr, (VSTRING *) 0, why)) {
+ switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0, why,
+ DNS_REQ_FLAG_ALL, proto_info->dns_atype_list)) {
case DNS_OK:
for (rr = addr; rr; rr = rr->next)
rr->pref = pref;
#include <stringops.h>
#include <host_port.h>
#include <sane_connect.h>
+#include <inet_addr_list.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
/* Global library. */
#include <mail_params.h>
#include <mail_proto.h>
+#include <own_inet_addr.h>
/* DNS library. */
#include <dns.h>
-
+
/* Application-specific. */
#include "lmtp.h"
const char *destination, VSTRING *why)
{
char *myname = "lmtp_connect_addr";
- struct sockaddr_in sin;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = SOCK_ADDR_PTR(&ss);
+ SOCKADDR_SIZE salen = sizeof(ss);
+ MAI_HOSTADDR_STR hostaddr;
int sock;
/*
* Sanity checks.
*/
- if (addr->data_len > sizeof(sin.sin_addr)) {
- msg_warn("%s: skip address with length %d", myname, addr->data_len);
+ if (dns_rr_to_sa(addr, port, sa, &salen) != 0) {
+ msg_warn("%s: skip address type %s: %m",
+ myname, dns_strtype(addr->type));
lmtp_errno = LMTP_RETRY;
return (0);
}
/*
* Initialize.
*/
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
-
- if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
+ if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
msg_fatal("%s: socket: %m", myname);
/*
* Connect to the LMTP server.
*/
- sin.sin_port = port;
- memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr));
-
+ SOCKADDR_TO_HOSTADDR(sa, salen, &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
if (msg_verbose)
msg_info("%s: trying: %s[%s] port %d...",
- myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
+ myname, addr->name, hostaddr.buf, ntohs(port));
- return (lmtp_connect_sock(sock, (struct sockaddr *) & sin, sizeof(sin),
- addr->name, inet_ntoa(sin.sin_addr),
- destination, why));
+ return (lmtp_connect_sock(sock, sa, salen,
+ addr->name, hostaddr.buf, destination, why));
}
/* lmtp_connect_sock - connect a socket over some transport */
* Parse the host/port information. We're working with a copy of the
* destination argument so the parsing can be destructive.
*/
- if ((err = host_port(buf, hostp, &service, def_service)) != 0)
+ if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
msg_fatal("%s in LMTP server description: %s", err, destination);
/*
* aren't going to have lmtp defined as a service, use a default value
* instead of just blowing up.
*/
- if (alldig(service) && (port = atoi(service)) != 0)
+ if (alldig(service)) {
+ if ((port = atoi(service)) >= 65536)
+ msg_fatal("bad numeric port in destination: %s", destination);
*portp = htons(port);
- else if ((sp = getservbyname(service, protocol)) != 0)
+ } else if ((sp = getservbyname(service, protocol)) != 0)
*portp = sp->s_port;
else
*portp = htons(var_lmtp_tcp_port);
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
resolve.o: ../../include/vstream.h
resolve.o: ../../include/iostuff.h
resolve.o: ../../include/attr.h
-resolve.o: ../../include/rewrite_clnt.h
resolve.o: ../../include/resolve_clnt.h
+resolve.o: ../../include/rewrite_clnt.h
resolve.o: ../../include/tok822.h
resolve.o: ../../include/mail_params.h
resolve.o: ../../include/defer.h
all: $(PROG) $(LIB)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
$(PROG): $(OBJS) $(LIBS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
master.o: ../../include/mail_task.h
master.o: ../../include/mail_conf.h
master.o: ../../include/open_lock.h
+master.o: ../../include/inet_proto.h
master.o: master.h
master_avail.o: master_avail.c
master_avail.o: ../../include/sys_defs.h
master_ent.o: ../../include/stringops.h
master_ent.o: ../../include/readlline.h
master_ent.o: ../../include/inet_addr_list.h
-master_ent.o: ../../include/inet_util.h
+master_ent.o: ../../include/myaddrinfo.h
+master_ent.o: ../../include/host_port.h
master_ent.o: ../../include/inet_addr_host.h
master_ent.o: ../../include/mail_proto.h
master_ent.o: ../../include/iostuff.h
master_ent.o: ../../include/attr.h
master_ent.o: ../../include/mail_params.h
master_ent.o: ../../include/own_inet_addr.h
+master_ent.o: ../../include/wildcard_inet_addr.h
master_ent.o: master_proto.h
master_ent.o: master.h
master_flow.o: master_flow.c
master_listen.o: ../../include/vstring.h
master_listen.o: ../../include/vbuf.h
master_listen.o: ../../include/inet_addr_list.h
+master_listen.o: ../../include/myaddrinfo.h
master_listen.o: ../../include/set_eugid.h
master_listen.o: ../../include/set_ugid.h
+master_listen.o: ../../include/sock_addr.h
master_listen.o: ../../include/mail_params.h
master_listen.o: master.h
master_proto.o: master_proto.c
master_spawn.o: ../../include/binhash.h
master_spawn.o: ../../include/mymalloc.h
master_spawn.o: ../../include/events.h
+master_spawn.o: ../../include/vstring.h
+master_spawn.o: ../../include/vbuf.h
master_spawn.o: ../../include/argv.h
master_spawn.o: master_proto.h
master_spawn.o: master.h
/* RESOURCE AND RATE CONTROLS
/* .ad
/* .fi
-/* .IP "\fBdaemon_timeout (18000s)\fR"
-/* How much time a Postfix daemon process may take to handle a
-/* request before it is terminated by a built-in watchdog timer.
/* .IP "\fBdefault_process_limit (100)\fR"
/* The default maximal number of Postfix child processes that provide
/* a given service.
/* .IP "\fBinet_interfaces (all)\fR"
/* The network interface addresses that this mail system receives mail
/* on.
+/* .IP "\fBinet_protocols (ipv4)\fR"
+/* The Internet protocols Postfix will attempt to use when making
+/* or accepting connections.
/* .IP "\fBimport_environment (see 'postconf -d' output)\fR"
/* The list of environment parameters that a Postfix process will
/* import from a non-Postfix parent process.
#include <mail_task.h>
#include <mail_conf.h>
#include <open_lock.h>
+#include <inet_proto.h>
/* Application-specific. */
exit(0);
}
+/* usage - show hint and terminate */
+
+static NORETURN usage(const char *me)
+{
+ msg_fatal("usage: %s [-c config_dir] [-e exit_time] [-D (debug)] [-t (test)] [-v]", me);
+}
+
/* main - main program */
int main(int argc, char **argv)
msg_verbose++;
break;
default:
- msg_fatal("usage: %s [-c config_dir] [-e exit_time] [-D (debug)] [-t (test)] [-v]", argv[0]);
+ usage(argv[0]);
/* NOTREACHED */
}
}
+ /*
+ * This program takes no other arguments.
+ */
+ if (argc > optind)
+ usage(argv[0]);
+
/*
* Final initializations. Unfortunately, we must read the global Postfix
* configuration file after doing command-line processing, so that we get
*/
master_vars_init();
+ /*
+ * In case of multi-protocol support. This needs to be done because
+ * master does not invoke mail_params_init() (it was written before that
+ * code existed).
+ */
+ (void) inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols);
+
/*
* Environment import filter, to enforce consistent behavior whether
* Postfix is started by hand, or at system boot time.
#include <stringops.h>
#include <readlline.h>
#include <inet_addr_list.h>
-#include <inet_util.h>
+#include <host_port.h>
#include <inet_addr_host.h>
/* Global library. */
#include <mail_proto.h>
#include <mail_params.h>
#include <own_inet_addr.h>
+#include <wildcard_inet_addr.h>
/* Local stuff. */
int n;
char *bufp;
char *atmp;
+ const char *parse_err;
static char *saved_interfaces = 0;
if (master_fp == 0)
VAR_INET_INTERFACES);
}
serv->type = MASTER_SERV_TYPE_INET;
- atmp = inet_parse(name, &host, &port);
+ atmp = mystrdup(name);
+ if ((parse_err = host_port(atmp, &host, "", &port, (char *) 0)) != 0)
+ msg_fatal("%s: line %d: %s in \"%s\"",
+ VSTREAM_PATH(master_fp), master_line,
+ parse_err, name);
if (*host) {
serv->flags |= MASTER_FLAG_INETHOST;/* host:port */
MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *)
inet_addr_list_init(MASTER_INET_ADDRLIST(serv));
if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0)
msg_fatal("%s: line %d: bad hostname or network address: %s",
- VSTREAM_PATH(master_fp), master_line, host);
+ VSTREAM_PATH(master_fp), master_line, name);
inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
- } else if (strcasecmp(saved_interfaces, DEF_INET_INTERFACES) == 0) {
- MASTER_INET_ADDRLIST(serv) = 0; /* wild-card */
- serv->listen_fd_count = 1;
} else {
- MASTER_INET_ADDRLIST(serv) = own_inet_addr_list(); /* virtual */
+ MASTER_INET_ADDRLIST(serv) =
+ strcasecmp(saved_interfaces, INET_INTERFACES_ALL) ?
+ own_inet_addr_list() : /* virtual */
+ wildcard_inet_addr_list(); /* wild-card */
inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
}
#include <set_eugid.h>
#include <set_ugid.h>
#include <iostuff.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
/* Global library. */
char *myname = "master_listen_init";
char *end_point;
int n;
+ MAI_HOSTADDR_STR hostaddr;
+ struct sockaddr *sa;
/*
* Find out what transport we should use, then create one or more
/*
* INET-domain listener endpoints can be wildcarded (the default) or
* bound to specific interface addresses.
+ *
+ * With dual-stack IPv4/6 systems it does not matter, we have to specify
+ * the addresses anyway, either explicit or wild-card.
*/
case MASTER_SERV_TYPE_INET:
- if (MASTER_INET_ADDRLIST(serv) == 0) { /* wild-card */
- serv->listen_fd[0] =
- inet_listen(MASTER_INET_PORT(serv),
- serv->max_proc > var_proc_limit ?
- serv->max_proc : var_proc_limit, NON_BLOCKING);
- close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
- } else { /* virtual or host:port */
- for (n = 0; n < serv->listen_fd_count; n++) {
- end_point = concatenate(inet_ntoa(MASTER_INET_ADDRLIST(serv)->addrs[n]),
- ":", MASTER_INET_PORT(serv), (char *) 0);
- serv->listen_fd[n]
- = inet_listen(end_point, serv->max_proc > var_proc_limit ?
- serv->max_proc : var_proc_limit, NON_BLOCKING);
- close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC);
- myfree(end_point);
- }
+ for (n = 0; n < serv->listen_fd_count; n++) {
+ sa = SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv)->addrs + n);
+ SOCKADDR_TO_HOSTADDR(sa, SOCK_ADDR_LEN(sa), &hostaddr,
+ (MAI_SERVPORT_STR *) 0, 0);
+ end_point = concatenate(hostaddr.buf,
+ ":", MASTER_INET_PORT(serv), (char *) 0);
+ serv->listen_fd[n]
+ = inet_listen(end_point, serv->max_proc > var_proc_limit ?
+ serv->max_proc : var_proc_limit, NON_BLOCKING);
+ close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC);
+ myfree(end_point);
}
break;
default:
/*
* Tunable parameters.
*/
+char *var_inet_protocols;
int var_proc_limit;
int var_throttle_time;
void master_vars_init(void)
{
char *path;
+ static CONFIG_STR_TABLE str_table[] = {
+ VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 1, 0,
+ 0,
+ };
static CONFIG_INT_TABLE int_table[] = {
VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0,
0,
VAR_THROTTLE_TIME, DEF_THROTTLE_TIME, &var_throttle_time, 1, 0,
0,
};
+ static char *saved_inet_protocols;
+ if (var_inet_protocols && !saved_inet_protocols)
+ saved_inet_protocols = mystrdup(var_inet_protocols);
mail_conf_read();
+ get_mail_conf_str_table(str_table);
get_mail_conf_int_table(int_table);
get_mail_conf_time_table(time_table);
path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
fset_master_ent(path);
myfree(path);
+
+ if (saved_inet_protocols && strcmp(var_inet_protocols, saved_inet_protocols)) {
+ msg_warn("ignoring %s change", VAR_INET_PROTOCOLS);
+ msg_warn("to change %s, stop and start Postfix", VAR_INET_PROTOCOLS);
+ }
}
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
update: ../../bin/$(PROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
./$(PROG) -d) |egrep -v '^(myhostname|mydomain|mynetworks) ' >$@
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
postconf.o: ../../include/split_at.h
postconf.o: ../../include/vstring_vstream.h
postconf.o: ../../include/myflock.h
+postconf.o: ../../include/inet_proto.h
postconf.o: ../../include/mynetworks.h
postconf.o: ../../include/mail_conf.h
postconf.o: ../../include/mail_dict.h
#include <split_at.h>
#include <vstring_vstream.h>
#include <myflock.h>
+#include <inet_proto.h>
/* Global library. */
static const char *check_mynetworks(void)
{
+ INET_PROTO_INFO *proto_info;
const char *junk;
if (var_inet_interfaces == 0) {
junk = DEF_MYNETWORKS_STYLE;
var_mynetworks_style = mystrdup(junk);
}
+ if (var_inet_protocols == 0) {
+ if ((mode & SHOW_DEFS)
+ || !(junk = mail_conf_lookup_eval(VAR_INET_PROTOCOLS)))
+ junk = DEF_INET_PROTOCOLS;
+ var_inet_protocols = mystrdup(junk);
+ proto_info = inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols);
+ }
return (mynetworks());
}
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
update: ../../bin/$(PROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
postqueue.o: ../../include/smtp_stream.h
postqueue.o: ../../include/vstring.h
postqueue.o: ../../include/user_acl.h
+postqueue.o: ../../include/valid_mailhost_addr.h
/* .RE
/* .IP "\fB-s \fIsite\fR"
/* Schedule immediate delivery of all mail that is queued for the named
-/* \fIsite\fR. The site must be eligible for the "fast flush" service.
+/* \fIsite\fR. A numerical site must be specified as a valid RFC 2821
+/* address literal enclosed in [], just like in email addresses.
+/* The site must be eligible for the "fast flush" service.
/* See \fBflush\fR(8) for more information about the "fast flush"
/* service.
/*
#include <flush_clnt.h>
#include <smtp_stream.h>
#include <user_acl.h>
+#include <valid_mailhost_addr.h>
/* Application-specific. */
*/
if (site_to_flush != 0) {
bad_site = 0;
- if (*site_to_flush == '['
- && *(last = site_to_flush + strlen(site_to_flush) - 1) == ']') {
- *last = 0;
- bad_site = !valid_hostaddr(site_to_flush + 1, DONT_GRIPE);
- *last = ']';
+ if (*site_to_flush == '[') {
+ bad_site = !valid_mailhost_literal(site_to_flush, DONT_GRIPE);
} else {
- bad_site = (!valid_hostname(site_to_flush, DONT_GRIPE)
- && !valid_hostaddr(site_to_flush, DONT_GRIPE));
+ bad_site = !valid_hostname(site_to_flush, DONT_GRIPE);
}
if (bad_site)
msg_fatal_status(EX_USAGE,
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
qmqpd_peer.o: ../../include/sys_defs.h
qmqpd_peer.o: ../../include/msg.h
qmqpd_peer.o: ../../include/mymalloc.h
-qmqpd_peer.o: ../../include/valid_hostname.h
qmqpd_peer.o: ../../include/stringops.h
qmqpd_peer.o: ../../include/vstring.h
qmqpd_peer.o: ../../include/vbuf.h
-qmqpd_peer.o: qmqpd.h
+qmqpd_peer.o: ../../include/myaddrinfo.h
+qmqpd_peer.o: ../../include/sock_addr.h
+qmqpd_peer.o: ../../include/inet_proto.h
+qmqpd_peer.o: ../../include/mail_proto.h
qmqpd_peer.o: ../../include/vstream.h
+qmqpd_peer.o: ../../include/iostuff.h
+qmqpd_peer.o: ../../include/attr.h
+qmqpd_peer.o: ../../include/valid_mailhost_addr.h
+qmqpd_peer.o: ../../include/valid_hostname.h
+qmqpd_peer.o: qmqpd.h
qmqpd_peer.o: ../../include/mail_stream.h
qmqpd_state.o: qmqpd_state.c
qmqpd_state.o: ../../include/sys_defs.h
/* it is queued.
/* .IP "\fBreceive_override_options (empty)\fR"
/* Enable or disable recipient validation, built-in content
-/* filtering, or address rewriting.
+/* filtering, or address mapping.
/* RESOURCE AND RATE CONTROLS
/* .ad
/* .fi
MAIL_ATTR_CLIENT_NAME, state->name);
if (IS_AVAIL_CLIENT_ADDR(state->addr))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
- MAIL_ATTR_CLIENT_ADDR, state->addr);
+ MAIL_ATTR_CLIENT_ADDR, state->rfc_addr);
if (IS_AVAIL_CLIENT_NAMADDR(state->namaddr))
rec_fprintf(state->cleanup, REC_TYPE_ATTR, "%s=%s",
MAIL_ATTR_ORIGIN, state->namaddr);
*/
rec_fputs(state->cleanup, REC_TYPE_MESG, "");
rec_fprintf(state->cleanup, REC_TYPE_NORM, "Received: from %s (%s [%s])",
- state->name, state->name, state->addr);
+ state->name, state->name, state->rfc_addr);
if (state->rcpt_count == 1 && state->recipient) {
rec_fprintf(state->cleanup, REC_TYPE_NORM,
"\tby %s (%s) with %s id %s",
char *name; /* client name */
char *addr; /* client IP address */
char *namaddr; /* name[addr] */
+ char *rfc_addr; /* RFC 2821 client IP address */
char *queue_id; /* queue file ID */
VSTREAM *cleanup; /* cleanup server */
MAIL_STREAM *dest; /* cleanup server */
/* .IP namaddr
/* String of the form: "name[addr]".
/* .PP
-/* qmqpd_peer_reset() releases memory allocate by qmqpd_peer_init().
+/* qmqpd_peer_reset() releases memory allocated by qmqpd_peer_init().
/* LICENSE
/* .ad
/* .fi
#include <netdb.h>
#include <string.h>
- /*
- * Older systems don't have h_errno. Even modern systems don't have
- * hstrerror().
- */
-#ifdef NO_HERRNO
-
-static int h_errno = TRY_AGAIN;
-
-#define HSTRERROR(err) "Host not found"
-
-#else
-
-#define HSTRERROR(err) (\
- err == TRY_AGAIN ? "Host not found, try again" : \
- err == HOST_NOT_FOUND ? "Host not found" : \
- err == NO_DATA ? "Host name has no address" : \
- err == NO_RECOVERY ? "Name server failure" : \
- strerror(errno) \
- )
-#endif
-
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
-#include <valid_hostname.h>
#include <stringops.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
+#include <inet_proto.h>
/* Global library. */
+#include <mail_proto.h>
+#include <valid_mailhost_addr.h>
/* Application-specific. */
void qmqpd_peer_init(QMQPD_STATE *state)
{
- struct sockaddr_in sin;
- SOCKADDR_SIZE len = sizeof(sin);
- struct hostent *hp;
- int i;
+ char *myname = "qmqpd_peer_init";
+ struct sockaddr_storage ss;
+ struct sockaddr *sa;
+ SOCKADDR_SIZE sa_len;
+ INET_PROTO_INFO *proto_info = inet_proto_info();
+
+ sa = (struct sockaddr *) & ss;
+ sa_len = sizeof(ss);
/*
* Look up the peer address information.
*/
- if (getpeername(vstream_fileno(state->client),
- (struct sockaddr *) & sin, &len) >= 0) {
+ if (getpeername(vstream_fileno(state->client), sa, &sa_len) >= 0) {
errno = 0;
}
* If peer went away, give up.
*/
if (errno == ECONNRESET || errno == ECONNABORTED) {
- state->name = mystrdup(CLIENT_ATTR_UNKNOWN);
- state->addr = mystrdup(CLIENT_ATTR_UNKNOWN);
+ state->name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
+ state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
}
/*
- * Look up and "verify" the client hostname.
+ * Convert the client address to printable address and hostname.
*/
- else if (errno == 0 && sin.sin_family == AF_INET) {
- state->addr = mystrdup(inet_ntoa(sin.sin_addr));
- hp = gethostbyaddr((char *) &(sin.sin_addr),
- sizeof(sin.sin_addr), AF_INET);
- if (hp == 0) {
- state->name = mystrdup(CLIENT_ATTR_UNKNOWN);
- } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) {
- state->name = mystrdup(CLIENT_ATTR_UNKNOWN);
- } else {
- state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */
+ else if (errno == 0
+ && strchr((char *) proto_info->sa_family_list, sa->sa_family)) {
+ MAI_HOSTNAME_STR client_name;
+ MAI_HOSTADDR_STR client_addr;
+ int aierr;
+ char *colonp;
+
+ /*
+ * Convert the client address to printable form.
+ */
+ if ((aierr = sockaddr_to_hostaddr(sa, sa_len, &client_addr,
+ (MAI_SERVPORT_STR *) 0, 0)) != 0)
+ msg_fatal("%s: cannot convert client address to string: %s",
+ myname, MAI_STRERROR(aierr));
+
+ /*
+ * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on,
+ * but only if IPv4 support is enabled (why would anyone want to turn
+ * it off)? With IPv4 support enabled we have no need for the IPv6
+ * form in logging, hostname verification and access checks.
+ */
+#ifdef HAS_IPV6
+ if (sa->sa_family == AF_INET6) {
+ if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0
+ && IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa))
+ && (colonp = strrchr(client_addr.buf, ':')) != 0) {
+ struct addrinfo *res0;
+
+ if (msg_verbose > 1)
+ msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
+ myname, client_addr.buf, colonp + 1);
+
+ state->addr = mystrdup(colonp + 1);
+ state->rfc_addr = mystrdup(colonp + 1);
+ aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0);
+ if (aierr)
+ msg_fatal("%s: cannot convert %s from string to binary: %s",
+ myname, state->addr, MAI_STRERROR(aierr));
+ sa_len = res0->ai_addrlen;
+ memcpy((char *) sa, res0->ai_addr, sa_len);
+ freeaddrinfo(res0);
+ }
/*
- * Reject the hostname if it does not list the peer address.
+ * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
+ * a prefix of 'IPv6:'. We do this consistently for all IPv6
+ * addresses that that appear in headers or envelopes. The fact
+ * that valid_mailhost_addr() enforces the form helps of course.
+ * We use the form without IPV6: prefix when doing access
+ * control, or when accessing the connection cache.
*/
+ else {
+ state->addr = mystrdup(client_addr.buf);
+ state->rfc_addr =
+ concatenate(IPV6_COL, client_addr.buf, (char *) 0);
+ }
+ }
+
+ /*
+ * An IPv4 address is in dotted quad decimal form.
+ */
+ else
+#endif
+ {
+ state->addr = mystrdup(client_addr.buf);
+ state->rfc_addr = mystrdup(client_addr.buf);
+ }
+
+ /*
+ * Look up and sanity check the client hostname.
+ *
+ * It is unsafe to allow numeric hostnames, especially because there
+ * exists pressure to turn off the name->addr double check. In that
+ * case an attacker could trivally bypass access restrictions.
+ *
+ * sockaddr_to_hostname() already rejects malformed or numeric names.
+ */
#define REJECT_PEER_NAME(state) { \
myfree(state->name); \
- state->name = mystrdup(CLIENT_ATTR_UNKNOWN); \
+ state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
}
- hp = gethostbyname(state->name); /* clobbers hp->name!! */
- if (hp == 0) {
+ if ((aierr = sockaddr_to_hostname(sa, sa_len, &client_name,
+ (MAI_SERVNAME_STR *) 0, 0)) != 0) {
+ state->name = mystrdup(CLIENT_NAME_UNKNOWN);
+ } else {
+ struct addrinfo *res0;
+ struct addrinfo *res;
+
+ state->name = mystrdup(client_name.buf);
+
+ /*
+ * Reject the hostname if it does not list the peer address.
+ */
+ aierr = hostname_to_sockaddr(state->name, (char *) 0, 0, &res0);
+ if (aierr) {
msg_warn("%s: hostname %s verification failed: %s",
- state->addr, state->name, HSTRERROR(h_errno));
- REJECT_PEER_NAME(state);
- } else if (hp->h_length != sizeof(sin.sin_addr)) {
- msg_warn("%s: hostname %s verification failed: bad address size %d",
- state->addr, state->name, hp->h_length);
+ state->addr, state->name, MAI_STRERROR(aierr));
REJECT_PEER_NAME(state);
} else {
- for (i = 0; /* void */ ; i++) {
- if (hp->h_addr_list[i] == 0) {
+ for (res = res0; /* void */ ; res = res->ai_next) {
+ if (res == 0) {
msg_warn("%s: address not listed for hostname %s",
state->addr, state->name);
REJECT_PEER_NAME(state);
break;
}
- if (memcmp(hp->h_addr_list[i],
- (char *) &sin.sin_addr,
- sizeof(sin.sin_addr)) == 0)
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, state->name);
+ continue;
+ }
+ if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
break; /* keep peer name */
}
+ freeaddrinfo(res0);
}
}
}
else {
state->name = mystrdup("localhost");
state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */
+ state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
}
/*
myfree(state->name);
myfree(state->addr);
myfree(state->namaddr);
+ myfree(state->rfc_addr);
}
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
/* Non-default alias database. Specify \fIpathname\fR or
/* \fItype\fR:\fIpathname\fR. See \fBpostalias\fR(1) for
/* details.
+/* .IP "\fB-O \fIoption=value\fR (ignored)"
+/* Backwards compatibility.
/* .IP "\fB-o7\fR (ignored)"
/* .IP "\fB-o8\fR (ignored)"
/* To send 8-bit or binary content, use an appropriate MIME encapsulation
optind++;
continue;
}
- if ((c = GETOPT(argc, argv, "A:B:C:F:GIL:N:R:UV:X:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
+ if ((c = GETOPT(argc, argv, "A:B:C:F:GIL:N:O:R:UV:X:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
break;
switch (c) {
default:
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
smtp_addr.o: ../../include/vbuf.h
smtp_addr.o: ../../include/mymalloc.h
smtp_addr.o: ../../include/inet_addr_list.h
+smtp_addr.o: ../../include/myaddrinfo.h
smtp_addr.o: ../../include/stringops.h
-smtp_addr.o: ../../include/myrand.h
+smtp_addr.o: ../../include/inet_proto.h
smtp_addr.o: ../../include/mail_params.h
smtp_addr.o: ../../include/own_inet_addr.h
smtp_addr.o: ../../include/dns.h
+smtp_addr.o: ../../include/sock_addr.h
smtp_addr.o: smtp.h
smtp_addr.o: ../../include/vstream.h
smtp_addr.o: ../../include/argv.h
smtp_connect.o: ../../include/split_at.h
smtp_connect.o: ../../include/mymalloc.h
smtp_connect.o: ../../include/inet_addr_list.h
+smtp_connect.o: ../../include/myaddrinfo.h
smtp_connect.o: ../../include/iostuff.h
smtp_connect.o: ../../include/timed_connect.h
smtp_connect.o: ../../include/stringops.h
smtp_connect.o: ../../include/host_port.h
smtp_connect.o: ../../include/sane_connect.h
+smtp_connect.o: ../../include/sock_addr.h
smtp_connect.o: ../../include/mail_params.h
smtp_connect.o: ../../include/own_inet_addr.h
smtp_connect.o: ../../include/deliver_pass.h
smtp_reuse.o: ../../include/dict.h
smtp_reuse.o: smtp_reuse.h
smtp_reuse.o: ../../include/dns.h
+smtp_reuse.o: ../../include/sock_addr.h
+smtp_reuse.o: ../../include/myaddrinfo.h
smtp_sasl_glue.o: smtp_sasl_glue.c
smtp_sasl_glue.o: ../../include/sys_defs.h
smtp_sasl_glue.o: ../../include/msg.h
smtp_unalias.o: ../../include/vbuf.h
smtp_unalias.o: ../../include/msg.h
smtp_unalias.o: ../../include/dns.h
+smtp_unalias.o: ../../include/sock_addr.h
+smtp_unalias.o: ../../include/myaddrinfo.h
smtp_unalias.o: smtp.h
smtp_unalias.o: ../../include/vstream.h
smtp_unalias.o: ../../include/argv.h
/* Optional list of relay hosts for SMTP destinations that can't be
/* found or that are unreachable.
/* .IP "\fBinet_interfaces (all)\fR"
-/* The network interface addresses that this mail system receives mail
-/* on.
+/* The network interface addresses that this mail system receives
+/* mail on.
+/* .IP "\fBinet_protocols (ipv4)\fR"
+/* The Internet protocols Postfix will attempt to use when making
+/* or accepting connections.
/* .IP "\fBipc_timeout (3600s)\fR"
/* The time limit for sending or receiving information over an internal
/* communication channel.
/* on by way of a proxy or network address translation unit.
/* .IP "\fBsmtp_bind_address (empty)\fR"
/* An optional numerical network address that the SMTP client should
-/* bind to when making a connection.
+/* bind to when making an IPv4 connection.
+/* .IP "\fBsmtp_bind_address6 (empty)\fR"
+/* An optional numerical network address that the SMTP client should
+/* bind to when making an IPv6 connection.
/* .IP "\fBsmtp_helo_name ($myhostname)\fR"
/* The hostname to send in the SMTP EHLO or HELO command.
/* .IP "\fBsmtp_host_lookup (dns)\fR"
bool var_smtp_sasl_enable;
char *var_smtp_sasl_mechs;
char *var_smtp_bind_addr;
+char *var_smtp_bind_addr6;
bool var_smtp_rand_addr;
int var_smtp_pix_thresh;
int var_smtp_pix_delay;
0,
};
- /*
- * Turn on per-peer debugging.
- */
- debug_peer_init();
-
/*
* Select hostname lookup mechanisms.
*/
static void pre_init(char *unused_name, char **unused_argv)
{
+ /*
+ * Turn on per-peer debugging.
+ */
+ debug_peer_init();
+
/*
* SASL initialization.
*/
VAR_SMTP_SASL_OPTS, DEF_SMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
VAR_SMTP_SASL_MECHS, DEF_SMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
+ VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0,
VAR_SMTP_CACHE_DEST, DEF_SMTP_CACHE_DEST, &var_smtp_cache_dest, 0, 0,
/*
/* All routines either return a DNS_RR pointer, or return a null
/* pointer and set the \fIsmtp_errno\fR global variable accordingly:
-/* .IP SMTP_RETRY
+/* .IP SMTP_ERR_RETRY
/* The request failed due to a soft error, and should be retried later.
-/* .IP SMTP_FAIL
+/* .IP SMTP_ERR_FAIL
/* The request attempt failed due to a hard error.
-/* .IP SMTP_LOOP
+/* .IP SMTP_ERR_LOOP
/* The local machine is the best mail exchanger.
/* .PP
/* In addition, a textual description of the problem is made available
#include <unistd.h>
#include <errno.h>
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
- /*
- * Older systems don't have h_errno. Even modern systems don't have
- * hstrerror().
- */
-#ifdef NO_HERRNO
-
-static int h_errno = TRY_AGAIN;
-
-#define HSTRERROR(err) "Host not found"
-
-#else
-
-#define HSTRERROR(err) (\
- err == TRY_AGAIN ? "Host not found, try again" : \
- err == HOST_NOT_FOUND ? "Host not found" : \
- err == NO_DATA ? "Host name has no address" : \
- err == NO_RECOVERY ? "Name server failure" : \
- strerror(errno) \
- )
-#endif
-
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <inet_addr_list.h>
#include <stringops.h>
-#include <myrand.h>
+#include <myaddrinfo.h>
+#include <inet_proto.h>
/* Global library. */
static void smtp_print_addr(char *what, DNS_RR *addr_list)
{
DNS_RR *addr;
- struct in_addr in_addr;
+ MAI_HOSTADDR_STR hostaddr;
msg_info("begin %s address list", what);
for (addr = addr_list; addr; addr = addr->next) {
- if (addr->data_len > sizeof(addr)) {
- msg_warn("skipping address length %d", addr->data_len);
+ if (dns_rr_to_pa(addr, &hostaddr) == 0) {
+ msg_warn("skipping record type %s: %m", dns_strtype(addr->type));
} else {
- memcpy((char *) &in_addr, addr->data, sizeof(in_addr));
msg_info("pref %4d host %s/%s",
addr->pref, addr->name,
- inet_ntoa(in_addr));
+ hostaddr.buf);
}
}
msg_info("end %s address list", what);
static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
{
char *myname = "smtp_addr_one";
- struct in_addr inaddr;
- DNS_FIXED fixed;
DNS_RR *addr = 0;
DNS_RR *rr;
- struct hostent *hp;
+ int aierr;
+ struct addrinfo *res0;
+ struct addrinfo *res;
+ INET_PROTO_INFO *proto_info = inet_proto_info();
+ int found;
if (msg_verbose)
msg_info("%s: host %s", myname, host);
/*
* Interpret a numerical name as an address.
*/
- if (ISDIGIT(host[0]) && (inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
- memset((char *) &fixed, 0, sizeof(fixed));
- return (dns_rr_append(addr_list,
- dns_rr_create(host, &fixed, pref,
- (char *) &inaddr, sizeof(inaddr))));
+ if (hostaddr_to_sockaddr(host, (char *) 0, 0, &res0) == 0
+ && strchr((char *) proto_info->sa_family_list, res0->ai_family) != 0) {
+ if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0)
+ msg_fatal("host %s: conversion error for address family %d: %m",
+ host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
+ addr_list = dns_rr_append(addr_list, addr);
+ freeaddrinfo(res0);
+ return (addr_list);
}
/*
* Use DNS lookup, but keep the option open to use native name service.
*/
if (smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS) {
- switch (dns_lookup(host, T_A, RES_DEFNAMES, &addr, (VSTRING *) 0, why)) {
+ switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0, why,
+ DNS_REQ_FLAG_ALL, proto_info->dns_atype_list)) {
case DNS_OK:
for (rr = addr; rr; rr = rr->next)
rr->pref = pref;
case DNS_NOTFOUND:
if (smtp_errno != SMTP_ERR_RETRY)
smtp_errno = SMTP_ERR_FAIL;
- /* maybe gethostbyname() will succeed */
+ /* maybe native naming service will succeed */
break;
}
}
/*
* Use the native name service which also looks in /etc/hosts.
*/
+#define RETRY_AI_ERROR(e) \
+ ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
+
if (smtp_host_lookup_mask & SMTP_HOST_FLAG_NATIVE) {
- memset((char *) &fixed, 0, sizeof(fixed));
- if ((hp = gethostbyname(host)) == 0) {
- vstring_sprintf(why, "%s: %s", host, HSTRERROR(h_errno));
+ if ((aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0)) != 0) {
+ vstring_sprintf(why, "%s: %s", host, MAI_STRERROR(aierr));
if (smtp_errno != SMTP_ERR_RETRY)
smtp_errno =
- (h_errno == TRY_AGAIN ? SMTP_ERR_RETRY : SMTP_ERR_FAIL);
- } else if (hp->h_addrtype != AF_INET) {
- vstring_sprintf(why, "%s: host not found", host);
- msg_warn("%s: unknown address family %d for %s",
- myname, hp->h_addrtype, host);
- if (smtp_errno != SMTP_ERR_RETRY)
- smtp_errno = SMTP_ERR_FAIL;
+ (RETRY_AI_ERROR(aierr) ? SMTP_ERR_RETRY : SMTP_ERR_FAIL);
} else {
- while (hp->h_addr_list[0]) {
- addr_list = dns_rr_append(addr_list,
- dns_rr_create(host, &fixed, pref,
- hp->h_addr_list[0],
- sizeof(inaddr)));
- hp->h_addr_list++;
+ for (found = 0, res = res0; res != 0; res = res->ai_next) {
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, host);
+ continue;
+ }
+ found++;
+ if ((addr = dns_sa_to_rr(host, pref, res->ai_addr)) == 0)
+ msg_fatal("host %s: conversion error for address family %d: %m",
+ host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
+ addr_list = dns_rr_append(addr_list, addr);
+ }
+ freeaddrinfo(res0);
+ if (found == 0) {
+ vstring_sprintf(why, "%s: host not found", host);
+ smtp_errno = SMTP_ERR_FAIL;
}
+ return (addr_list);
}
- return (addr_list);
}
/*
DNS_RR *addr;
int i;
-#define INADDRP(x) ((struct in_addr *) (x))
-
self = own_inet_addr_list();
proxy = proxy_inet_addr_list();
* Find out if this mail system is listening on this address.
*/
for (i = 0; i < self->used; i++)
- if (INADDRP(addr->data)->s_addr == self->addrs[i].s_addr) {
+ if (DNS_RR_EQ_SA(addr, (struct sockaddr *) (self->addrs + i))) {
if (msg_verbose)
msg_info("%s: found self at pref %d", myname, addr->pref);
return (addr);
* address.
*/
for (i = 0; i < proxy->used; i++)
- if (INADDRP(addr->data)->s_addr == proxy->addrs[i].s_addr) {
+ if (DNS_RR_EQ_SA(addr, (struct sockaddr *) (proxy->addrs + i))) {
if (msg_verbose)
msg_info("%s: found proxy at pref %d", myname, addr->pref);
return (addr);
static int smtp_compare_pref(DNS_RR *a, DNS_RR *b)
{
- return (a->pref - b->pref);
+ if (a->pref != b->pref)
+ return (a->pref - b->pref);
+#ifdef HAS_IPV6
+ if (a->type == b->type) /* 200412 */
+ return 0;
+ if (a->type == T_AAAA)
+ return (-1);
+ if (b->type == T_AAAA)
+ return (+1);
+#endif
+ return 0;
}
/* smtp_domain_addr - mail exchanger address lookup */
smtp_errno = SMTP_ERR_LOOP;
return (0);
}
- if (addr_list && addr_list->next && var_smtp_rand_addr)
- addr_list = dns_rr_shuffle(addr_list);
+ if (addr_list && addr_list->next) {
+ if (var_smtp_rand_addr)
+ addr_list = dns_rr_shuffle(addr_list);
+ /* The following changes the order of equal-preference hosts. */
+ if (inet_proto_info()->ai_family_list[1] != 0)
+ addr_list = dns_rr_sort(addr_list, smtp_compare_pref);
+ }
if (msg_verbose)
smtp_print_addr(host, addr_list);
return (addr_list);
/* System library. */
#include <sys_defs.h>
+#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <ctype.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
#ifndef IPPORT_SMTP
#define IPPORT_SMTP 25
#endif
#include <stringops.h>
#include <host_port.h>
#include <sane_connect.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
/* Global library. */
int sess_flags)
{
char *myname = "smtp_connect_addr";
- struct sockaddr_in sin;
+ struct sockaddr_storage ss; /* remote */
+ struct sockaddr *sa = (struct sockaddr *) & ss;
+ SOCKADDR_SIZE salen = sizeof(ss);
+ MAI_HOSTADDR_STR hostaddr;
int sock;
- INET_ADDR_LIST *addr_list;
int conn_stat;
int saved_errno;
VSTREAM *stream;
int ch;
- unsigned long inaddr;
+ char *bind_addr;
+ char *bind_var;
smtp_errno = SMTP_ERR_NONE; /* Paranoia */
/*
* Sanity checks.
*/
- if (addr->data_len > sizeof(sin.sin_addr)) {
- msg_warn("%s: skip address with length %d", myname, addr->data_len);
+ if (dns_rr_to_sa(addr, port, sa, &salen) != 0) {
+ msg_warn("%s: skip address type %s: %m",
+ myname, dns_strtype(addr->type));
smtp_errno = SMTP_ERR_RETRY;
return (0);
}
/*
* Initialize.
*/
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
-
- if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
+ if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
msg_fatal("%s: socket: %m", myname);
/*
* Allow the sysadmin to specify the source address, for example, as "-o
* smtp_bind_address=x.x.x.x" in the master.cf file.
*/
- if (*var_smtp_bind_addr) {
- sin.sin_addr.s_addr = inet_addr(var_smtp_bind_addr);
- if (sin.sin_addr.s_addr == INADDR_NONE)
- msg_fatal("%s: bad %s parameter: %s",
- myname, VAR_SMTP_BIND_ADDR, var_smtp_bind_addr);
- if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
- msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
- if (msg_verbose)
- msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
+#ifdef HAS_IPV6
+ if (sa->sa_family == AF_INET6) {
+ bind_addr = var_smtp_bind_addr6;
+ bind_var = VAR_SMTP_BIND_ADDR6;
+ } else
+#endif
+ if (sa->sa_family == AF_INET) {
+ bind_addr = var_smtp_bind_addr;
+ bind_var = VAR_SMTP_BIND_ADDR;
+ } else
+ bind_var = bind_addr = "";
+ if (*bind_addr) {
+ int aierr;
+ struct addrinfo *res0;
+
+ if ((aierr = hostaddr_to_sockaddr(bind_addr, (char *) 0, 0, &res0)) != 0)
+ msg_fatal("%s: bad %s parameter: %s: %s",
+ myname, bind_var, bind_addr, MAI_STRERROR(aierr));
+ if (bind(sock, res0->ai_addr, res0->ai_addrlen) < 0)
+ msg_warn("%s: bind %s: %m", myname, bind_addr);
+ else if (msg_verbose)
+ msg_info("%s: bind %s", myname, bind_addr);
+ freeaddrinfo(res0);
}
/*
* When running as a virtual host, bind to the virtual interface so that
* the mail appears to come from the "right" machine address.
+ *
+ * XXX The IPv6 patch expands the null host (as client endpoint) and uses
+ * the result as the loopback address list.
*/
- else if ((addr_list = own_inet_addr_list())->used == 1) {
- memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr));
- inaddr = ntohl(sin.sin_addr.s_addr);
- if (!IN_CLASSA(inaddr)
- || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
- if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
- msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
- if (msg_verbose)
- msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
+ else {
+ int count = 0;
+ struct sockaddr *own_addr = 0;
+ INET_ADDR_LIST *addr_list = own_inet_addr_list();
+ struct sockaddr_storage *s;
+
+ for (s = addr_list->addrs; s < addr_list->addrs + addr_list->used; s++) {
+ if (SOCK_ADDR_FAMILY(s) == sa->sa_family) {
+ if (count++ > 0)
+ break;
+ own_addr = SOCK_ADDR_PTR(s);
+ }
+ }
+ if (count == 1 && !sock_addr_in_loopback(own_addr)) {
+ if (bind(sock, own_addr, SOCK_ADDR_LEN(own_addr)) < 0) {
+ SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ msg_warn("%s: bind %s: %m", myname, hostaddr.buf);
+ } else if (msg_verbose) {
+ SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ msg_info("%s: bind %s", myname, hostaddr.buf);
+ }
}
}
/*
* Connect to the SMTP server.
*/
- sin.sin_port = port;
- memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr));
-
+ SOCKADDR_TO_HOSTADDR(sa, salen, &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
if (msg_verbose)
msg_info("%s: trying: %s[%s] port %d...",
- myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
+ myname, addr->name, hostaddr.buf, ntohs(port));
if (var_smtp_conn_tmout > 0) {
non_blocking(sock, NON_BLOCKING);
- conn_stat = timed_connect(sock, (struct sockaddr *) & sin,
- sizeof(sin), var_smtp_conn_tmout);
+ conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout);
saved_errno = errno;
non_blocking(sock, BLOCKING);
errno = saved_errno;
} else {
- conn_stat = sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin));
+ conn_stat = sane_connect(sock, sa, salen);
}
if (conn_stat < 0) {
vstring_sprintf(why, "connect to %s[%s]: %m",
- addr->name, inet_ntoa(sin.sin_addr));
+ addr->name, hostaddr.buf);
smtp_errno = SMTP_ERR_RETRY;
close(sock);
return (0);
*/
if (read_wait(sock, var_smtp_helo_tmout) < 0) {
vstring_sprintf(why, "connect to %s[%s]: read timeout",
- addr->name, inet_ntoa(sin.sin_addr));
+ addr->name, hostaddr.buf);
smtp_errno = SMTP_ERR_RETRY;
close(sock);
return (0);
stream = vstream_fdopen(sock, O_RDWR);
if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
vstring_sprintf(why, "connect to %s[%s]: server dropped connection without sending the initial SMTP greeting",
- addr->name, inet_ntoa(sin.sin_addr));
+ addr->name, hostaddr.buf);
smtp_errno = SMTP_ERR_RETRY;
vstream_fclose(stream);
return (0);
}
vstream_ungetc(stream, ch);
return (smtp_session_alloc(stream, dest, addr->name,
- inet_ntoa(sin.sin_addr), port, sess_flags));
+ hostaddr.buf, port, sess_flags));
}
/* smtp_parse_destination - parse destination */
* Parse the host/port information. We're working with a copy of the
* destination argument so the parsing can be destructive.
*/
- if ((err = host_port(buf, hostp, &service, def_service)) != 0)
+ if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
msg_fatal("%s in SMTP server description: %s", err, destination);
/*
* Convert service to port number, network byte order.
*/
- if (alldig(service) && (port = atoi(service)) != 0) {
+ if (alldig(service)) {
+ if ((port = atoi(service)) >= 65536)
+ msg_fatal("bad network port in destination: %s", destination);
*portp = htons(port);
} else {
if ((sp = getservbyname(service, protocol)) == 0)
static void smtp_scrub_addr_list(HTABLE *cached_addr, DNS_RR **addr_list)
{
+ MAI_HOSTADDR_STR hostaddr;
DNS_RR *addr;
DNS_RR *next;
-#define INADDRP(x) ((struct in_addr *) (x))
-
+ /*
+ * XXX Extend the DNS_RR structure with fields for the printable address
+ * and/or binary sockaddr representations, so that we can avoid repeated
+ * binary->string transformations for the same address.
+ */
for (addr = *addr_list; addr; addr = next) {
next = addr->next;
- if (addr->type == T_A) {
- if (addr->data_len > sizeof(struct in_addr))
- continue;
- if (htable_locate(cached_addr, inet_ntoa(*INADDRP(addr->data))))
- *addr_list = dns_rr_remove(*addr_list, addr);
+ if (dns_rr_to_pa(addr, &hostaddr) == 0) {
+ msg_warn("cannot convert type %s resource record to socket address",
+ dns_strtype(addr->type));
+ continue;
}
+ if (htable_locate(cached_addr, hostaddr.buf))
+ *addr_list = dns_rr_remove(*addr_list, addr);
}
}
static void smtp_update_addr_list(DNS_RR **addr_list, const char *server_addr,
int session_count)
{
- struct in_addr server_in_addr;
DNS_RR *addr;
DNS_RR *next;
+ int aierr;
+ struct addrinfo *res0;
if (*addr_list == 0)
return;
*
* XXX smtp_reuse_session() breaks if we remove two or more adjacent list
* elements but do not truncate the list to zero length.
+ *
+ * XXX Extend the SMTP_SESSION structure with sockaddr information so that
+ * we can avoid repeated string->binary transformations for the same
+ * address.
*/
- server_in_addr.s_addr = inet_addr(server_addr);
- for (addr = *addr_list; addr; addr = next) {
- next = addr->next;
- if (addr->type == T_A) { /* NOT: switch */
- if (addr->data_len > sizeof(server_in_addr))
- continue;
- if (INADDRP(addr->data)->s_addr == server_in_addr.s_addr) {
+ if ((aierr = hostaddr_to_sockaddr(server_addr, (char *) 0, 0, &res0)) != 0) {
+ msg_warn("hostaddr_to_sockaddr %s: %s",
+ server_addr, MAI_STRERROR(aierr));
+ } else {
+ for (addr = *addr_list; addr; addr = next) {
+ next = addr->next;
+ if (DNS_RR_EQ_SA(addr, (struct sockaddr *) res0->ai_addr)) {
*addr_list = dns_rr_remove(*addr_list, addr);
break;
}
}
+ freeaddrinfo(res0);
}
}
SMTP_SESSION *smtp_reuse_addr(SMTP_STATE *state, DNS_RR *addr, unsigned port)
{
+ MAI_HOSTADDR_STR hostaddr;
SMTP_SESSION *session;
int fd;
-#define INADDRP(x) ((struct in_addr *) (x))
-
/*
* Look up the session by its IP address. This means that we have no
* destination-to-address binding properties.
* Note: if the label needs to be made more specific (with e.g., SASL login
* information), just append the text with vstring_sprintf_append().
*/
- if (addr->data_len > sizeof(struct in_addr))
+ if (dns_rr_to_pa(addr, &hostaddr) == 0)
return (0);
vstring_sprintf(state->endp_label, SMTP_SCACHE_LABEL(NO_MX_LOOKUP),
- state->service, inet_ntoa(*INADDRP(addr->data)),
- ntohs(port));
+ state->service, hostaddr.buf, ntohs(port));
if ((fd = scache_find_endp(smtp_scache, STR(state->endp_label),
state->endp_prop)) < 0)
return (0);
* Allright, bundle up what we have sofar.
*/
session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR),
- dest, host, addr, port, SMTP_SESS_FLAG_NONE);
+ dest, host, addr, port, SMTP_SESS_FLAG_NONE);
session->features = (features | SMTP_FEATURE_FROM_CACHE);
session->reuse_count = reuse_count - 1;
session->sndbufsize = sndbufsize;
*/
if ((result = htable_find(cache, name)) == 0) {
fqdn = vstring_alloc(10);
- if (dns_lookup_types(name, smtp_unalias_flags, (DNS_RR **) 0,
- fqdn, (VSTRING *) 0, T_MX, T_A, 0) != DNS_OK)
+ if (dns_lookup_l(name, smtp_unalias_flags, (DNS_RR **) 0, fqdn,
+ (VSTRING *) 0, DNS_REQ_FLAG_ANY, T_MX, T_A,
+#ifdef HAS_IPV6
+ T_AAAA,
+#endif
+ 0) != DNS_OK)
vstring_strcpy(fqdn, name);
htable_enter(cache, name, result = vstring_export(fqdn));
}
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
smtpd.o: ../../include/attr_clnt.h
smtpd.o: ../../include/ehlo_mask.h
smtpd.o: ../../include/maps.h
+smtpd.o: ../../include/valid_mailhost_addr.h
smtpd.o: ../../include/mail_server.h
smtpd.o: smtpd_token.h
smtpd.o: smtpd.h
smtpd_check.o: ../../include/mac_parse.h
smtpd_check.o: ../../include/attr_clnt.h
smtpd_check.o: ../../include/attr.h
+smtpd_check.o: ../../include/myaddrinfo.h
+smtpd_check.o: ../../include/inet_proto.h
smtpd_check.o: ../../include/dns.h
+smtpd_check.o: ../../include/sock_addr.h
smtpd_check.o: ../../include/string_list.h
smtpd_check.o: ../../include/match_list.h
smtpd_check.o: ../../include/match_ops.h
smtpd_check.o: ../../include/name_mask.h
smtpd_check.o: ../../include/resolve_local.h
smtpd_check.o: ../../include/own_inet_addr.h
+smtpd_check.o: ../../include/inet_addr_list.h
smtpd_check.o: ../../include/mail_conf.h
smtpd_check.o: ../../include/maps.h
smtpd_check.o: ../../include/mail_addr_find.h
smtpd_check.o: ../../include/recipient_list.h
smtpd_check.o: ../../include/input_transp.h
smtpd_check.o: ../../include/is_header.h
+smtpd_check.o: ../../include/valid_mailhost_addr.h
smtpd_check.o: smtpd.h
smtpd_check.o: ../../include/mail_stream.h
smtpd_check.o: smtpd_sasl_glue.h
smtpd_peer.o: ../../include/sys_defs.h
smtpd_peer.o: ../../include/msg.h
smtpd_peer.o: ../../include/mymalloc.h
-smtpd_peer.o: ../../include/valid_hostname.h
smtpd_peer.o: ../../include/stringops.h
smtpd_peer.o: ../../include/vstring.h
smtpd_peer.o: ../../include/vbuf.h
+smtpd_peer.o: ../../include/myaddrinfo.h
+smtpd_peer.o: ../../include/sock_addr.h
+smtpd_peer.o: ../../include/inet_proto.h
smtpd_peer.o: ../../include/mail_proto.h
smtpd_peer.o: ../../include/vstream.h
smtpd_peer.o: ../../include/iostuff.h
smtpd_peer.o: ../../include/attr.h
+smtpd_peer.o: ../../include/valid_mailhost_addr.h
+smtpd_peer.o: ../../include/valid_hostname.h
smtpd_peer.o: smtpd.h
smtpd_peer.o: ../../include/argv.h
smtpd_peer.o: ../../include/mail_stream.h
/* The list of domains that are delivered via the $local_transport
/* mail delivery transport.
/* .IP "\fBinet_interfaces (all)\fR"
-/* The network interface addresses that this mail system receives mail
-/* on.
+/* The network interface addresses that this mail system receives
+/* mail on.
/* .IP "\fBproxy_interfaces (empty)\fR"
/* The network interface addresses that this mail system receives mail
/* on by way of a proxy or network address translation unit.
+/* .IP "\fBinet_protocols (ipv4)\fR"
+/* The Internet protocols Postfix will attempt to use when making
+/* or accepting connections.
/* .IP "\fBlocal_recipient_maps (proxy:unix:passwd.byname $alias_maps)\fR"
/* Lookup tables with all names or addresses of local recipients:
/* a recipient address is local when its domain matches $mydestination,
#include <flush_clnt.h>
#include <ehlo_mask.h> /* ehlo filter */
#include <maps.h> /* ehlo filter */
+#include <valid_mailhost_addr.h>
/* Single-threaded server skeleton. */
/*
* This filter is applied after printable().
*/
-#define NEUTER_CHARACTERS " <>()\\\";:@"
+#define NEUTER_CHARACTERS " <>()\\\";@"
/*
* Reasons for losing the client.
out_fprintf(out_stream, REC_TYPE_NORM,
"Received: from %s (%s [%s])",
state->helo_name ? state->helo_name : state->name,
- state->name, state->addr);
+ state->name, state->rfc_addr);
if (state->rcpt_count == 1 && state->recipient) {
out_fprintf(out_stream, REC_TYPE_NORM,
state->cleanup ? "\tby %s (%s) with %s id %s" :
smtpd_chat_reply(state, "500 Syntax: ETRN domain");
return (-1);
}
- if (!ISALNUM(argv[1].strval[0]))
- argv[1].strval++;
- if (!valid_hostname(argv[1].strval, DONT_GRIPE)) {
+ if (argv[1].strval[0] == '@' || argv[1].strval[0] == '#')
+ argv[1].strval++;
+
+ /*
+ * As an extension to RFC 1985 we also allow an RFC 2821 address literal
+ * enclosed in [].
+ */
+ if (!valid_hostname(argv[1].strval, DONT_GRIPE)
+ && !valid_mailhost_literal(argv[1].strval, DONT_GRIPE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Error: invalid parameter syntax");
return (-1);
{
SMTPD_TOKEN *argp;
char *attr_value;
+ const char *bare_value;
char *attr_name;
int update_namaddr = 0;
int peer_code;
if (peer_code != SMTPD_PEER_CODE_OK) {
attr_value = CLIENT_NAME_UNKNOWN;
} else {
- if (!valid_hostname(attr_value, DONT_GRIPE)
- || valid_hostaddr(attr_value, DONT_GRIPE)) {
+ if (!valid_hostname(attr_value, DONT_GRIPE)) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad %s syntax: %s",
XCLIENT_NAME, attr_value);
else if (STREQ(attr_name, XCLIENT_ADDR)) {
if (STREQ(attr_value, XCLIENT_UNAVAILABLE)) {
attr_value = CLIENT_ADDR_UNKNOWN;
+ bare_value = attr_value;
} else {
- if (!valid_hostaddr(attr_value, DONT_GRIPE)) {
+ if ((bare_value = valid_mailhost_addr(attr_value, DONT_GRIPE)) == 0) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Bad %s syntax: %s",
XCLIENT_ADDR, attr_value);
return (-1);
}
}
- UPDATE_STR(state->addr, attr_value);
+ UPDATE_STR(state->addr, bare_value);
+ UPDATE_STR(state->rfc_addr, attr_value);
update_namaddr = 1;
}
{
SMTPD_TOKEN *argp;
char *attr_value;
+ const char *bare_value;
char *attr_name;
int updated = 0;
static NAME_CODE xforward_flags[] = {
attr_value = CLIENT_NAME_UNKNOWN;
} else {
neuter(attr_value, NEUTER_CHARACTERS, '?');
+ if (!valid_hostname(attr_value, DONT_GRIPE)) {
+ state->error_mask |= MAIL_ERROR_PROTOCOL;
+ smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+ XFORWARD_NAME, attr_value);
+ return (-1);
+ }
}
UPDATE_STR(state->xforward.name, attr_value);
break;
case SMTPD_STATE_XFORWARD_ADDR:
if (STREQ(attr_value, XFORWARD_UNAVAILABLE)) {
attr_value = CLIENT_ADDR_UNKNOWN;
+ bare_value = attr_value;
} else {
neuter(attr_value, NEUTER_CHARACTERS, '?');
+ if ((bare_value = valid_mailhost_addr(attr_value, DONT_GRIPE)) == 0) {
+ state->error_mask |= MAIL_ERROR_PROTOCOL;
+ smtpd_chat_reply(state, "501 Bad %s syntax: %s",
+ XFORWARD_ADDR, attr_value);
+ return (-1);
+ }
}
- UPDATE_STR(state->xforward.addr, attr_value);
+ UPDATE_STR(state->xforward.addr, bare_value);
+ UPDATE_STR(state->xforward.rfc_addr, attr_value);
break;
/*
* recipient checks, address mapping, header_body_checks?.
*/
smtpd_input_transp_mask =
- input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
+ input_transp_mask(VAR_INPUT_TRANSP, var_input_transp);
/*
* Sanity checks. The queue_minfree value should be at least as large as
char *name; /* name for access control */
char *addr; /* address for access control */
char *namaddr; /* name[address] */
+ char *rfc_addr; /* address for RFC 2821 */
char *protocol; /* email protocol */
char *helo_name; /* helo/ehlo parameter */
char *ident; /* message identifier */
char *name; /* client hostname */
char *addr; /* client host address string */
char *namaddr; /* combined name and address */
+ char *rfc_addr; /* address for RFC 2821 */
int peer_code; /* 2=ok, 4=soft, 5=hard */
int error_count; /* reset after DOT */
int error_mask; /* client errors */
(((s)->xforward.flags & SMTPD_STATE_XFORWARD_CLIENT_MASK) ? \
(s)->xforward.a : (s)->a)
-#define FORWARD_ADDR(s) FORWARD_CLIENT_ATTR((s), addr)
+#define FORWARD_ADDR(s) FORWARD_CLIENT_ATTR((s), rfc_addr)
#define FORWARD_NAME(s) FORWARD_CLIENT_ATTR((s), name)
#define FORWARD_NAMADDR(s) FORWARD_CLIENT_ATTR((s), namaddr)
#define FORWARD_PROTO(s) FORWARD_CLIENT_ATTR((s), protocol)
--- /dev/null
+#
+# Initialize.
+#
+#! ../bin/postmap smtpd_check_access
+#msg_verbose 1
+smtpd_delay_reject 0
+mynetworks 127.0.0.0/8,168.100.189.0/28
+#
+# MX backup
+#
+mydestination wzv.porcupine.org,localhost.porcupine.org
+inet_interfaces 168.100.189.7,127.0.0.1
+recipient_restrictions permit_mx_backup,reject
+rcpt wietse@wzv.porcupine.org
+rcpt wietse@fist.porcupine.org
+rcpt wietse@porcupine.org
+permit_mx_backup_networks 168.100.189.5
+rcpt wietse@fist.porcupine.org
+permit_mx_backup_networks 168.100.189.4
+rcpt wietse@fist.porcupine.org
--- /dev/null
+>>> #
+>>> # Initialize.
+>>> #
+>>> #! ../bin/postmap smtpd_check_access
+>>> #msg_verbose 1
+>>> smtpd_delay_reject 0
+OK
+>>> mynetworks 127.0.0.0/8,168.100.189.0/28
+OK
+>>> #
+>>> # MX backup
+>>> #
+>>> mydestination wzv.porcupine.org,localhost.porcupine.org
+OK
+>>> inet_interfaces 168.100.189.7,127.0.0.1
+OK
+>>> recipient_restrictions permit_mx_backup,reject
+OK
+>>> rcpt wietse@wzv.porcupine.org
+OK
+>>> rcpt wietse@fist.porcupine.org
+OK
+>>> rcpt wietse@porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from localhost[127.0.0.1]: 554 <wietse@porcupine.org>: Recipient address rejected: Access denied; to=<wietse@porcupine.org> proto=SMTP
+554 <wietse@porcupine.org>: Recipient address rejected: Access denied
+>>> permit_mx_backup_networks 168.100.189.5
+OK
+>>> rcpt wietse@fist.porcupine.org
+./smtpd_check: <queue id>: reject: RCPT from localhost[127.0.0.1]: 554 <wietse@fist.porcupine.org>: Recipient address rejected: Access denied; to=<wietse@fist.porcupine.org> proto=SMTP
+554 <wietse@fist.porcupine.org>: Recipient address rejected: Access denied
+>>> permit_mx_backup_networks 168.100.189.4
+OK
+>>> rcpt wietse@fist.porcupine.org
+OK
#include <setjmp.h>
#include <stdlib.h>
#include <unistd.h>
+#include <errno.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
/* Utility library. */
#include <msg.h>
#include <ctable.h>
#include <mac_expand.h>
#include <attr_clnt.h>
+#include <myaddrinfo.h>
+#include <inet_proto.h>
/* DNS library. */
#include <string_list.h>
#include <namadr_list.h>
#include <domain_list.h>
+#include <string_list.h>
#include <mail_params.h>
#include <rewrite_clnt.h>
#include <resolve_clnt.h>
#include <input_transp.h>
#include <is_header.h>
#include <rewrite_clnt.h>
+#include <valid_mailhost_addr.h>
/* Application-specific. */
defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2))
#define DEFER_IF_REJECT3(state, class, fmt, a1, a2, a3) \
defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3))
+#define DEFER_IF_REJECT4(state, class, fmt, a1, a2, a3, a4) \
+ defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3), (a4))
#define DEFER_IF_PERMIT2(state, class, fmt, a1, a2) do { \
if ((state)->warn_if_reject == 0) \
defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2)); \
msg_info("%s: %s", myname, addr);
if (addr[0] == '[' && (len = strlen(addr)) > 2 && addr[len - 1] == ']') {
- test_addr = mystrndup(&addr[1], len - 2);
+ test_addr = mystrndup(addr + 1, len - 2);
} else
test_addr = addr;
/*
* Validate the address.
*/
- if (!valid_hostaddr(test_addr, DONT_GRIPE))
+ if (!valid_mailhost_addr(test_addr, DONT_GRIPE))
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: invalid ip address",
var_bad_name_code, reply_name, reply_class);
/*
* Validate the hostname.
*/
- if (!valid_hostname(test_name, DONT_GRIPE))
+ if (!valid_hostname(test_name, DONT_GRIPE)
+ && !valid_hostaddr(test_name, DONT_GRIPE)) /* XXX back compat */
stat = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Invalid name",
var_bad_name_code, reply_name, reply_class);
#define RR_ADDR_TYPES T_A
#endif
- dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
- (VSTRING *) 0, RR_ADDR_TYPES, T_MX, 0);
+ dns_status = dns_lookup_l(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
+ (VSTRING *) 0, DNS_REQ_FLAG_ANY,
+ RR_ADDR_TYPES, T_MX, 0);
if (dns_status == DNS_NOTFOUND)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Host not found",
if (msg_verbose)
msg_info("%s: %s", myname, name);
- dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
- (VSTRING *) 0, RR_ADDR_TYPES, T_MX, 0);
+ dns_status = dns_lookup_l(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
+ (VSTRING *) 0, DNS_REQ_FLAG_ANY,
+ RR_ADDR_TYPES, T_MX, 0);
if (dns_status == DNS_NOTFOUND)
return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Domain not found",
const char *reply_name, const char *reply_class)
{
char *myname = "all_auth_mx_addr";
- struct in_addr addr;
+ MAI_HOSTADDR_STR hostaddr;
DNS_RR *rr;
DNS_RR *addr_list;
int dns_status;
/*
* Verify that all host addresses are within permit_mx_backup_networks.
*/
- dns_status = dns_lookup(host, T_A, 0, &addr_list, (VSTRING *) 0, (VSTRING *) 0);
+ dns_status = dns_lookup_v(host, 0, &addr_list, (VSTRING *) 0, (VSTRING *) 0,
+ DNS_REQ_FLAG_ALL, inet_proto_info()->dns_atype_list);
if (dns_status != DNS_OK) {
DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
"450 <%s>: %s rejected: Unable to look up host %s as mail exchanger",
return (NOPE);
}
for (rr = addr_list; rr != 0; rr = rr->next) {
- if (rr->data_len > sizeof(addr)) {
- msg_warn("%s: skipping address length %d for host %s",
- state->queue_id, rr->data_len, host);
+ if (dns_rr_to_pa(rr, &hostaddr) == 0) {
+ msg_warn("%s: skipping record type %s for host %s: %m",
+ myname, dns_strtype(rr->type), host);
continue;
}
- memcpy((char *) &addr, rr->data, sizeof(addr));
if (msg_verbose)
- msg_info("%s: checking: %s", myname, inet_ntoa(addr));
+ msg_info("%s: checking: %s", myname, hostaddr.buf);
- if (!namadr_list_match(perm_mx_networks, host, inet_ntoa(addr))) {
+ if (!namadr_list_match(perm_mx_networks, host, hostaddr.buf)) {
/*
* Reject: at least one IP address is not listed in
*/
if (msg_verbose)
msg_info("%s: address %s for %s does not match %s",
- myname, inet_ntoa(addr), host, VAR_PERM_MX_NETWORKS);
+ myname, hostaddr.buf, host, VAR_PERM_MX_NETWORKS);
dns_rr_free(addr_list);
return (NOPE);
}
const char *reply_name, const char *reply_class)
{
char *myname = "has_my_addr";
- struct in_addr addr;
- char **cpp;
- struct hostent *hp;
+ struct addrinfo *res;
+ struct addrinfo *res0;
+ int aierr;
+ MAI_HOSTADDR_STR hostaddr;
+ INET_PROTO_INFO *proto_info = inet_proto_info();
if (msg_verbose)
msg_info("%s: host %s", myname, host);
#define YUP 1
#define NOPE 0
- if ((hp = gethostbyname(host)) == 0) {
- DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY,
- "450 <%s>: %s rejected: Unable to look up mail exchanger host %s",
- reply_name, reply_class, host);
- return (NOPE);
- }
- if (hp->h_addrtype != AF_INET || hp->h_length != sizeof(addr)) {
- msg_warn("address type %d length %d for %s",
- hp->h_addrtype, hp->h_length, host);
+ aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0);
+ if (aierr) {
+ DEFER_IF_REJECT4(state, MAIL_ERROR_POLICY,
+ "450 <%s>: %s rejected: Unable to look up mail exchanger host %s: %s",
+ reply_name, reply_class, host, MAI_STRERROR(aierr));
return (NOPE);
}
- for (cpp = hp->h_addr_list; *cpp; cpp++) {
- memcpy((char *) &addr, *cpp, sizeof(addr));
- if (msg_verbose)
- msg_info("%s: addr %s", myname, inet_ntoa(addr));
- if (own_inet_addr(&addr))
- return (YUP);
- if (proxy_inet_addr(&addr))
- return (YUP);
+#define HAS_MY_ADDR_RETURN(x) { freeaddrinfo(res0); return (x); }
+
+ for (res = res0; res != 0; res = res->ai_next) {
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ if (msg_verbose)
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, host);
+ continue;
+ }
+ if (msg_verbose) {
+ SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ msg_info("%s: addr %s", myname, hostaddr.buf);
+ }
+ if (own_inet_addr(res->ai_addr))
+ HAS_MY_ADDR_RETURN(YUP);
+ if (proxy_inet_addr(res->ai_addr))
+ HAS_MY_ADDR_RETURN(YUP);
}
if (msg_verbose)
msg_info("%s: host %s: no match", myname, host);
- return (NOPE);
+ HAS_MY_ADDR_RETURN(NOPE);
}
/* i_am_mx - is this machine listed as MX relay */
static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list,
const char *reply_name, const char *reply_class)
{
- const char *myname = "permit_mx_backup";
+ const char *myname = "i_am_mx";
DNS_RR *mx;
/*
static int permit_mx_primary(SMTPD_STATE *state, DNS_RR *mx_list,
const char *reply_name, const char *reply_class)
{
+ const char *myname = "permit_mx_primary";
DNS_RR *mx;
unsigned int best_pref;
+ if (msg_verbose)
+ msg_info("%s", myname);
+
/*
* Find the preference of the primary MX hosts.
*/
char *addr;
const char *value;
DICT *dict;
+ int delim;
if (msg_verbose)
msg_info("%s: %s", myname, address);
#define CHK_ADDR_RETURN(x,y) { *found = y; return(x); }
addr = STR(vstring_strcpy(error_text, address));
+#ifdef HAS_IPV6
+ if (strchr(addr, ':') != 0)
+ delim = ':';
+ else
+#endif
+ delim = '.';
if ((dict = dict_handle(table)) == 0)
msg_panic("%s: dictionary not found: %s", myname, table);
msg_fatal("%s: table lookup problem", table);
}
flags = PARTIAL;
- } while (split_at_right(addr, '.'));
+ } while (split_at_right(addr, delim));
CHK_ADDR_RETURN(SMTPD_CHECK_DUNNO, MISSED);
}
DNS_RR *server_list;
DNS_RR *server;
int found = 0;
- struct in_addr addr;
- struct hostent *hp;
- char *addr_string;
+ MAI_HOSTADDR_STR addr_string;
+ int aierr;
+ struct addrinfo *res0;
+ struct addrinfo *res;
int status;
- char **cpp;
- static DNS_FIXED fixed;
+ INET_PROTO_INFO *proto_info;
/*
* Sanity check.
(VSTRING *) 0, (VSTRING *) 0);
if (dns_status == DNS_NOTFOUND && h_errno == NO_DATA) {
if (type == T_MX) {
- server_list = dns_rr_create(domain, &fixed, 0,
+ server_list = dns_rr_create(domain, type, C_IN, 0, 0,
domain, strlen(domain) + 1);
dns_status = DNS_OK;
} else if (type == T_NS) {
/*
* Check the hostnames first, then the addresses.
*/
+ proto_info = inet_proto_info();
for (server = server_list; server != 0; server = server->next) {
if (msg_verbose)
msg_info("%s: %s hostname check: %s",
FULL, &found, reply_name, reply_class,
def_acl)) != 0 || found)
CHECK_SERVER_RETURN(status);
- SET_H_ERRNO(0);
- if ((hp = gethostbyname((char *) server->data)) == 0) {
+ if ((aierr = hostname_to_sockaddr((char *) server->data,
+ (char *) 0, 0, &res0)) != 0) {
msg_warn("Unable to look up %s host %s for %s %s: %s",
dns_strtype(type), (char *) server->data,
- reply_class, reply_name, dns_strerror(h_errno));
+ reply_class, reply_name, MAI_STRERROR(aierr));
continue;
}
- if (hp->h_addrtype != AF_INET || hp->h_length != sizeof(addr)) {
- if (msg_verbose)
- msg_warn("address type %d length %d for %s",
- hp->h_addrtype, hp->h_length, (char *) server->data);
- continue; /* XXX */
- }
+ /* Now we must also free the addrinfo result. */
if (msg_verbose)
msg_info("%s: %s host address check: %s",
myname, dns_strtype(type), (char *) server->data);
- for (cpp = hp->h_addr_list; *cpp; cpp++) {
- memcpy((char *) &addr, *cpp, sizeof(addr));
- addr_string = mystrdup(inet_ntoa(addr));
- status = check_addr_access(state, table, addr_string, FULL,
+ for (res = res0; res != 0; res = res->ai_next) {
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ if (msg_verbose)
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, server->data);
+ continue;
+ }
+ SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
+ &addr_string, (MAI_SERVPORT_STR *) 0, 0);
+ status = check_addr_access(state, table, addr_string.buf, FULL,
&found, reply_name, reply_class,
def_acl);
- myfree(addr_string);
- if (status != 0 || found)
+ if (status != 0 || found) {
+ freeaddrinfo(res0); /* 200412 */
CHECK_SERVER_RETURN(status);
+ }
}
+ freeaddrinfo(res0); /* 200412 */
}
CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO);
}
static void *rbl_pagein(const char *query, void *unused_context)
{
+ const char *myname = "rbl_pagein";
DNS_RR *txt_list;
VSTRING *why;
int dns_status;
SMTPD_RBL_STATE *rbl;
DNS_RR *addr_list;
- struct in_addr addr;
+ MAI_HOSTADDR_STR hostaddr;
DNS_RR *rr;
DNS_RR *next;
VSTRING *buf;
* Do the query. If the DNS lookup produces no definitive reply, give the
* requestor the benefit of the doubt. We can't block all email simply
* because an RBL server is unavailable.
+ *
+ * Don't do this for AAAA records. Yet.
*/
why = vstring_alloc(10);
dns_status = dns_lookup(query, T_A, 0, &addr_list, (VSTRING *) 0, why);
rbl->txt = 0;
rbl->a = argv_alloc(1);
for (rr = addr_list; rr != 0; rr = rr->next) {
- memcpy((char *) &addr.s_addr, addr_list->data, sizeof(addr.s_addr));
- argv_add(rbl->a, inet_ntoa(addr), ARGV_END);
+ if (dns_rr_to_pa(rr, &hostaddr) == 0)
+ msg_warn("%s: skipping record type %s for query %s: %m",
+ myname, dns_strtype(rr->type), query);
+ else
+ argv_add(rbl->a, hostaddr.buf, ARGV_END);
}
dns_rr_free(addr_list);
return ((void *) rbl);
msg_info("%s: %s %s", myname, reply_class, addr);
/*
- * IPv4 only for now
+ * IPv4 / IPv6-mapped IPv4 (if supported) only for now
*/
-#ifdef INET6
- if (inet_pton(AF_INET, addr, &a) != 1)
+ if (valid_ipv6_hostaddr(addr, DONT_GRIPE))
return SMTPD_CHECK_DUNNO;
-#endif
/*
* Reverse the client IPV4 address, tack on the RBL domain name and query
msg_warn("restriction %s is deprecated. Use %s instead",
PERMIT_NAKED_IP_ADDR, PERMIT_MYNETWORKS);
if (state->helo_name) {
- if (state->helo_name[strspn(state->helo_name, "0123456789.")] == 0
+ if (state->helo_name[strspn(state->helo_name, "0123456789.:")] == 0
&& (status = reject_invalid_hostaddr(state, state->helo_name,
state->helo_name, SMTPD_NAME_HELO)) == 0)
status = SMTPD_CHECK_OK;
char *var_rcpt_checks = "";
char *var_etrn_checks = "";
char *var_data_checks = "";
+char *var_eod_checks = "";
char *var_relay_domains = "";
char *var_mynetworks = "";
char *var_notify_classes = "";
char *var_myorigin;
char *var_mydest;
char *var_inet_interfaces;
+char *var_proxy_interfaces;
char *var_rcpt_delim;
char *var_rest_classes;
char *var_alias_maps;
VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin,
VAR_MYDEST, DEF_MYDEST, &var_mydest,
VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces,
+ VAR_PROXY_INTERFACES, DEF_PROXY_INTERFACES, &var_proxy_interfaces,
VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim,
VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes,
VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps,
char *bp;
char *resp;
char *addr;
+ INET_PROTO_INFO *proto_info;
/*
* Initialization. Use dummies for client information.
smtpd_state_init(&state, VSTREAM_IN, "smtpd");
state.queue_id = "<queue id>";
+ proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
+
/*
* Main loop: update config parameters or test the client, helo, sender
* and recipient restrictions.
resp = 0;
break;
}
- if (strcasecmp(args->argv[0], "local_recipient_maps") == 0) {
+ if (strcasecmp(args->argv[0], VAR_LOCAL_RCPT_MAPS) == 0) {
UPDATE_STRING(var_local_rcpt_maps, args->argv[1]);
UPDATE_MAPS(local_rcpt_maps, VAR_LOCAL_RCPT_MAPS,
var_local_rcpt_maps, DICT_FLAG_LOCK);
resp = 0;
break;
}
- if (strcasecmp(args->argv[0], "relay_recipient_maps") == 0) {
+ if (strcasecmp(args->argv[0], VAR_RELAY_RCPT_MAPS) == 0) {
UPDATE_STRING(var_relay_rcpt_maps, args->argv[1]);
UPDATE_MAPS(relay_rcpt_maps, VAR_RELAY_RCPT_MAPS,
var_relay_rcpt_maps, DICT_FLAG_LOCK);
resp = 0;
break;
}
- if (strcasecmp(args->argv[0], "canonical_maps") == 0) {
+ if (strcasecmp(args->argv[0], VAR_CANONICAL_MAPS) == 0) {
UPDATE_STRING(var_canonical_maps, args->argv[1]);
UPDATE_MAPS(canonical_maps, VAR_CANONICAL_MAPS,
var_canonical_maps, DICT_FLAG_LOCK);
resp = 0;
break;
}
- if (strcasecmp(args->argv[0], "rbl_reply_maps") == 0) {
+ if (strcasecmp(args->argv[0], VAR_RBL_REPLY_MAPS) == 0) {
UPDATE_STRING(var_rbl_reply_maps, args->argv[1]);
UPDATE_MAPS(rbl_reply_maps, VAR_RBL_REPLY_MAPS,
var_rbl_reply_maps, DICT_FLAG_LOCK);
resp = 0;
break;
}
- if (strcasecmp(args->argv[0], "mynetworks") == 0) {
+ if (strcasecmp(args->argv[0], VAR_MYNETWORKS) == 0) {
+ /* NOT: UPDATE_STRING */
namadr_list_free(mynetworks);
mynetworks =
namadr_list_init(match_parent_style(VAR_MYNETWORKS),
resp = 0;
break;
}
- if (strcasecmp(args->argv[0], "relay_domains") == 0) {
+ if (strcasecmp(args->argv[0], VAR_RELAY_DOMAINS) == 0) {
+ /* NOT: UPDATE_STRING */
domain_list_free(relay_domains);
relay_domains =
domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
resp = 0;
break;
}
+ if (strcasecmp(args->argv[0], VAR_PERM_MX_NETWORKS) == 0) {
+ UPDATE_STRING(var_perm_mx_networks, args->argv[1]);
+ domain_list_free(perm_mx_networks);
+ perm_mx_networks =
+ namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
+ args->argv[1]);
+ resp = 0;
+ break;
+ }
if (strcasecmp(args->argv[0], "restriction_class") == 0) {
rest_class(args->argv[1]);
resp = 0;
helo friend.bad.domain
helo_restrictions reject_invalid_hostname,reject_unknown_hostname
helo 123.123.123.123
+helo [123.123.123.123]
+helo [::]
+helo [ipv6:::]
+helo [ipv6::::]
helo_restrictions permit_naked_ip_address,reject_invalid_hostname,reject_unknown_hostname
helo 123.123.123.123
#
>>> helo 123.123.123.123
./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 450 <123.123.123.123>: Helo command rejected: Host not found; proto=SMTP helo=<123.123.123.123>
450 <123.123.123.123>: Helo command rejected: Host not found
+>>> helo [123.123.123.123]
+OK
+>>> helo [::]
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 501 <[::]>: Helo command rejected: invalid ip address; proto=SMTP helo=<[::]>
+501 <[::]>: Helo command rejected: invalid ip address
+>>> helo [ipv6:::]
+OK
+>>> helo [ipv6::::]
+./smtpd_check: <queue id>: reject: HELO from foo[123.123.123.123]: 501 <[ipv6::::]>: Helo command rejected: invalid ip address; proto=SMTP helo=<[ipv6::::]>
+501 <[ipv6::::]>: Helo command rejected: invalid ip address
>>> helo_restrictions permit_naked_ip_address,reject_invalid_hostname,reject_unknown_hostname
OK
>>> helo 123.123.123.123
#include <netdb.h>
#include <string.h>
- /*
- * Older systems don't have h_errno. Even modern systems don't have
- * hstrerror().
- */
-#ifdef NO_HERRNO
-
-static int h_errno = TRY_AGAIN;
-
-#define HSTRERROR(err) "Host not found"
-
-#else
-
-#define HSTRERROR(err) (\
- err == TRY_AGAIN ? "Host not found, try again" : \
- err == HOST_NOT_FOUND ? "Host not found" : \
- err == NO_DATA ? "Host name has no address" : \
- err == NO_RECOVERY ? "Name server failure" : \
- strerror(errno) \
- )
-#endif
-
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
-#include <valid_hostname.h>
#include <stringops.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
+#include <inet_proto.h>
/* Global library. */
#include <mail_proto.h>
+#include <valid_mailhost_addr.h>
/* Application-specific. */
void smtpd_peer_init(SMTPD_STATE *state)
{
- struct sockaddr_in sin;
- SOCKADDR_SIZE len = sizeof(sin);
- struct hostent *hp;
- int i;
+ char *myname = "smtpd_peer_init";
+ struct sockaddr_storage ss;
+ SOCKADDR_SIZE sa_len;
+ struct sockaddr *sa;
+ INET_PROTO_INFO *proto_info = inet_proto_info();
- /*
- * Avoid suprious complaints from Purify on Solaris.
- */
- memset((char *) &sin, 0, len);
+ sa = (struct sockaddr *) & ss;
+ sa_len = sizeof(ss);
/*
* Look up the peer address information.
*/
- if (getpeername(vstream_fileno(state->client),
- (struct sockaddr *) & sin, &len) >= 0) {
+ if (getpeername(vstream_fileno(state->client), sa, &sa_len) >= 0) {
errno = 0;
}
if (errno == ECONNRESET || errno == ECONNABORTED) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
+ state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->peer_code = SMTPD_PEER_CODE_PERM;
}
/*
- * Look up and "verify" the client hostname.
+ * Convert the client address to printable address and hostname.
*/
- else if (errno == 0 && sin.sin_family == AF_INET) {
- state->addr = mystrdup(inet_ntoa(sin.sin_addr));
- hp = gethostbyaddr((char *) &(sin.sin_addr),
- sizeof(sin.sin_addr), AF_INET);
- if (hp == 0) {
- state->name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->peer_code = (h_errno == TRY_AGAIN ?
- SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
- } else if (valid_hostaddr(hp->h_name, DONT_GRIPE)) {
- msg_warn("numeric result %s in address->name lookup for %s",
- hp->h_name, state->addr);
- state->name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->peer_code = SMTPD_PEER_CODE_PERM;
- } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) {
- state->name = mystrdup(CLIENT_NAME_UNKNOWN);
- state->peer_code = SMTPD_PEER_CODE_PERM;
- } else {
- state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */
- state->peer_code = SMTPD_PEER_CODE_OK;
+ else if (errno == 0
+ && strchr((char *) proto_info->sa_family_list, sa->sa_family)) {
+ MAI_HOSTNAME_STR client_name;
+ MAI_HOSTADDR_STR client_addr;
+ int aierr;
+ char *colonp;
+
+ /*
+ * Convert the client address to printable form.
+ */
+ if ((aierr = sockaddr_to_hostaddr(sa, sa_len, &client_addr,
+ (MAI_SERVPORT_STR *) 0, 0)) != 0)
+ msg_fatal("%s: cannot convert client address to string: %s",
+ myname, MAI_STRERROR(aierr));
+
+ /*
+ * We convert IPv4-in-IPv6 address to 'true' IPv4 address early on,
+ * but only if IPv4 support is enabled (why would anyone want to turn
+ * it off)? With IPv4 support enabled we have no need for the IPv6
+ * form in logging, hostname verification and access checks.
+ */
+#ifdef HAS_IPV6
+ if (sa->sa_family == AF_INET6) {
+ if (strchr((char *) proto_info->sa_family_list, AF_INET) != 0
+ && IN6_IS_ADDR_V4MAPPED(&SOCK_ADDR_IN6_ADDR(sa))
+ && (colonp = strrchr(client_addr.buf, ':')) != 0) {
+ struct addrinfo *res0;
+
+ if (msg_verbose > 1)
+ msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"",
+ myname, client_addr.buf, colonp + 1);
+
+ state->addr = mystrdup(colonp + 1);
+ state->rfc_addr = mystrdup(colonp + 1);
+ aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0);
+ if (aierr)
+ msg_fatal("%s: cannot convert %s from string to binary: %s",
+ myname, state->addr, MAI_STRERROR(aierr));
+ sa_len = res0->ai_addrlen;
+ memcpy((char *) sa, res0->ai_addr, sa_len);
+ freeaddrinfo(res0); /* 200412 */
+ }
/*
- * Reject the hostname if it does not list the peer address.
+ * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
+ * a prefix of 'IPv6:'. We do this consistently for all IPv6
+ * addresses that that appear in headers or envelopes. The fact
+ * that valid_mailhost_addr() enforces the form helps of course.
+ * We use the form without IPV6: prefix when doing access
+ * control, or when accessing the connection cache.
*/
+ else {
+ state->addr = mystrdup(client_addr.buf);
+ state->rfc_addr =
+ concatenate(IPV6_COL, client_addr.buf, (char *) 0);
+ }
+ }
+
+ /*
+ * An IPv4 address is in dotted quad decimal form.
+ */
+ else
+#endif
+ {
+ state->addr = mystrdup(client_addr.buf);
+ state->rfc_addr = mystrdup(client_addr.buf);
+ }
+
+ /*
+ * Look up and sanity check the client hostname.
+ *
+ * It is unsafe to allow numeric hostnames, especially because there
+ * exists pressure to turn off the name->addr double check. In that
+ * case an attacker could trivally bypass access restrictions.
+ *
+ * sockaddr_to_hostname() already rejects malformed or numeric names.
+ */
+#define TEMP_AI_ERROR(e) \
+ ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
+
#define REJECT_PEER_NAME(state, code) { \
myfree(state->name); \
state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
state->peer_code = code; \
}
- hp = gethostbyname(state->name); /* clobbers hp->name!! */
- if (hp == 0) {
+ if ((aierr = sockaddr_to_hostname(sa, sa_len, &client_name,
+ (MAI_SERVNAME_STR *) 0, 0)) != 0) {
+ state->name = mystrdup(CLIENT_NAME_UNKNOWN);
+ state->peer_code = (TEMP_AI_ERROR(aierr) ?
+ SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
+ } else {
+ struct addrinfo *res0;
+ struct addrinfo *res;
+
+ state->name = mystrdup(client_name.buf);
+ state->peer_code = SMTPD_PEER_CODE_OK;
+
+ /*
+ * Reject the hostname if it does not list the peer address.
+ */
+ aierr = hostname_to_sockaddr(state->name, (char *) 0, 0, &res0);
+ if (aierr) {
msg_warn("%s: hostname %s verification failed: %s",
- state->addr, state->name, HSTRERROR(h_errno));
- REJECT_PEER_NAME(state, (h_errno == TRY_AGAIN ?
+ state->addr, state->name, MAI_STRERROR(aierr));
+ REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM));
- } else if (hp->h_length != sizeof(sin.sin_addr)) {
- msg_warn("%s: hostname %s verification failed: bad address size %d",
- state->addr, state->name, hp->h_length);
- REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM);
} else {
- for (i = 0; /* void */ ; i++) {
- if (hp->h_addr_list[i] == 0) {
+ for (res = res0; /* void */ ; res = res->ai_next) {
+ if (res == 0) {
msg_warn("%s: address not listed for hostname %s",
state->addr, state->name);
REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM);
break;
}
- if (memcmp(hp->h_addr_list[i],
- (char *) &sin.sin_addr,
- sizeof(sin.sin_addr)) == 0)
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, state->name);
+ continue;
+ }
+ if (sock_addr_cmp_addr(res->ai_addr, sa) == 0)
break; /* keep peer name */
}
+ freeaddrinfo(res0);
}
}
}
else {
state->name = mystrdup("localhost");
state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */
+ state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
state->peer_code = SMTPD_PEER_CODE_OK;
}
myfree(state->name);
myfree(state->addr);
myfree(state->namaddr);
+ myfree(state->rfc_addr);
}
state->xforward.name = mystrdup(CLIENT_NAME_UNKNOWN);
state->xforward.addr = mystrdup(CLIENT_ADDR_UNKNOWN);
state->xforward.namaddr = mystrdup(CLIENT_NAMADDR_UNKNOWN);
+ state->xforward.rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
/* Leave helo at zero. */
state->xforward.protocol = mystrdup(CLIENT_PROTO_UNKNOWN);
/* Leave ident at zero. */
FREE_AND_WIPE(state->xforward.name);
FREE_AND_WIPE(state->xforward.addr);
FREE_AND_WIPE(state->xforward.namaddr);
+ FREE_AND_WIPE(state->xforward.rfc_addr);
FREE_AND_WIPE(state->xforward.protocol);
FREE_AND_WIPE(state->xforward.helo_name);
FREE_AND_WIPE(state->xforward.ident);
all: $(PROG)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
smtp-sink: smtp-sink.o $(LIBS)
$(CC) $(CFLAGS) -o $@ smtp-sink.o $(LIBS) $(SYSLIBS)
qmqp-sink.o: ../../include/mymalloc.h
qmqp-sink.o: ../../include/msg_vstream.h
qmqp-sink.o: ../../include/netstring.h
+qmqp-sink.o: ../../include/inet_proto.h
qmqp-sink.o: ../../include/qmqp_proto.h
qmqp-source.o: qmqp-source.c
qmqp-source.o: ../../include/sys_defs.h
qmqp-source.o: ../../include/iostuff.h
qmqp-source.o: ../../include/mymalloc.h
qmqp-source.o: ../../include/events.h
-qmqp-source.o: ../../include/find_inet.h
qmqp-source.o: ../../include/netstring.h
qmqp-source.o: ../../include/sane_connect.h
+qmqp-source.o: ../../include/host_port.h
+qmqp-source.o: ../../include/myaddrinfo.h
+qmqp-source.o: ../../include/inet_proto.h
qmqp-source.o: ../../include/mail_date.h
qmqp-source.o: ../../include/qmqp_proto.h
smtp-sink.o: smtp-sink.c
smtp-sink.o: ../../include/msg_vstream.h
smtp-sink.o: ../../include/stringops.h
smtp-sink.o: ../../include/sane_accept.h
+smtp-sink.o: ../../include/inet_proto.h
smtp-sink.o: ../../include/smtp_stream.h
smtp-source.o: smtp-source.c
smtp-source.o: ../../include/sys_defs.h
smtp-source.o: ../../include/iostuff.h
smtp-source.o: ../../include/mymalloc.h
smtp-source.o: ../../include/events.h
-smtp-source.o: ../../include/find_inet.h
smtp-source.o: ../../include/sane_connect.h
+smtp-source.o: ../../include/host_port.h
+smtp-source.o: ../../include/myaddrinfo.h
+smtp-source.o: ../../include/inet_proto.h
smtp-source.o: ../../include/smtp_stream.h
smtp-source.o: ../../include/mail_date.h
/* multi-threaded QMQP test server
/* SYNOPSIS
/* .fi
-/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
+/* \fBqmqp-sink\fR [\fB-46cv\fR] [\fB-x \fItime\fR]
/* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR
/*
-/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
+/* \fBqmqp-sink\fR [\fB-46cv\fR] [\fB-x \fItime\fR]
/* \fBunix:\fR\fIpathname\fR \fIbacklog\fR
/* DESCRIPTION
/* \fBqmqp-sink\fR listens on the named host (or address) and port.
/* It receives messages from the network and throws them away.
/* The purpose is to measure QMQP client performance, not protocol
/* compliance.
-/* Connections can be accepted on IPV4 endpoints or UNIX-domain sockets.
-/* IPV4 is the default.
+/* Connections can be accepted on IPv4 or IPv6 endpoints, or on
+/* UNIX-domain sockets.
+/* IPv4 and IPv6 are the default.
/* This program is the complement of the \fBqmqp-source\fR(1) program.
+/* .IP \fB-4\fR
+/* Support IPv4 only. This option has no effect when
+/* Postfix is built without IPv6 support.
+/* .IP \fB-6\fR
+/* Support IPv6 only. This option is not available when
+/* Postfix is built without IPv6 support.
/* .IP \fB-c\fR
/* Display a running counter that is updated whenever a delivery
/* is completed.
#include <iostuff.h>
#include <msg_vstream.h>
#include <netstring.h>
+#include <inet_proto.h>
/* Global library. */
int backlog;
int ch;
int ttl;
+ const char *protocols = INET_PROTO_NAME_ALL;
+ INET_PROTO_INFO *proto_info;
/*
* Initialize diagnostics.
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "cvx:")) > 0) {
+ while ((ch = GETOPT(argc, argv, "46cvx:")) > 0) {
switch (ch) {
+ case '4':
+ protocols = INET_PROTO_NAME_IPV4;
+ break;
+ case '6':
+ protocols = INET_PROTO_NAME_IPV6;
+ break;
case 'c':
count++;
break;
/*
* Initialize.
*/
+ proto_info = inet_proto_init("protocols", protocols);
buffer = vstring_alloc(1024);
if (strncmp(argv[optind], "unix:", 5) == 0) {
sock = unix_listen(argv[optind] + 5, backlog, BLOCKING);
/* \fBqmqp-source\fR connects to the named host and TCP port (default 628)
/* and sends one or more messages to it, either sequentially
/* or in parallel. The program speaks the QMQP protocol.
-/* Connections can be made to UNIX-domain and IPV4 servers.
-/* IPV4 is the default.
+/* Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
+/* IPv4 and IPv6 are the default.
/*
/* Options:
+/* .IP \fB-4\fR
+/* Connect to the server with IPv4. This option has no effect when
+/* Postfix is built without IPv6 support.
+/* .IP \fB-6\fR
+/* Connect to the server with IPv6. This option is not available when
+/* Postfix is built without IPv6 support.
/* .IP \fB-c\fR
/* Display a running counter that is incremented each time
/* a delivery completes.
#include <connect.h>
#include <mymalloc.h>
#include <events.h>
-#include <find_inet.h>
#include <iostuff.h>
#include <netstring.h>
#include <sane_connect.h>
+#include <host_port.h>
+#include <myaddrinfo.h>
+#include <inet_proto.h>
/* Global library. */
static const char *var_myhostname;
static int session_count;
static int message_count = 1;
-static struct sockaddr_in sin;
+static struct sockaddr_storage ss;
#undef sun
static struct sockaddr_un sun;
int ch;
int n;
int i;
+ char *buf;
+ const char *parse_err;
+ struct addrinfo *res;
+ int aierr;
+ const char *protocols = INET_PROTO_NAME_ALL;
+ INET_PROTO_INFO *proto_info;
signal(SIGPIPE, SIG_IGN);
msg_vstream_init(argv[0], VSTREAM_ERR);
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "cC:f:l:m:r:R:s:t:vw:")) > 0) {
+ while ((ch = GETOPT(argc, argv, "46cC:f:l:m:r:R:s:t:vw:")) > 0) {
switch (ch) {
+ case '4':
+ protocols = INET_PROTO_NAME_IPV4;
+ break;
+ case '6':
+ protocols = INET_PROTO_NAME_IPV6;
+ break;
case 'c':
count++;
break;
/*
* Translate endpoint address to internal form.
*/
+ proto_info = inet_proto_init("protocols", protocols);
if (strncmp(argv[optind], "unix:", 5) == 0) {
path = argv[optind] + 5;
path_len = strlen(path);
} else {
if (strncmp(argv[optind], "inet:", 5) == 0)
argv[optind] += 5;
- if ((port = split_at(host = argv[optind], ':')) == 0 || *port == 0)
- port = "628";
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = find_inet_addr(host);
- sin.sin_port = find_inet_port(port, "tcp");
- sa = (struct sockaddr *) & sin;
- sa_length = sizeof(sin);
+ buf = mystrdup(argv[optind]);
+ if ((parse_err = host_port(buf, &host, (char *) 0, &port, "628")) != 0)
+ msg_fatal("%s: %s", argv[optind], parse_err);
+ if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
+ msg_fatal("%s: %s", argv[optind], MAI_STRERROR(aierr));
+ myfree(buf);
+ sa = (struct sockaddr *) & ss;
+ memcpy((char *) sa, res->ai_addr, res->ai_addrlen);
+ sa_length = res->ai_addrlen;
+#ifdef HAS_SA_LEN
+ sa->sa_len = sa_length;
+#endif
+ freeaddrinfo(res);
}
/*
/* The purpose is to measure client performance, not protocol
/* compliance.
/*
-/* Connections can be accepted on IPV4 endpoints or UNIX-domain sockets.
-/* IPV4 is the default.
+/* Connections can be accepted on IPv4 or IPv6 endpoints, or on
+/* UNIX-domain sockets.
+/* IPv4 and IPv6 are the default.
/* This program is the complement of the \fBsmtp-source\fR(1) program.
/*
/* Arguments:
+/* .IP \fB-4\fR
+/* Support IPv4 only. This option has no effect when
+/* Postfix is built without IPv6 support.
+/* .IP \fB-6\fR
+/* Support IPv6 only. This option is not available when
+/* Postfix is built without IPv6 support.
/* .IP \fB-a\fR
/* Do not announce SASL authentication support.
/* .IP \fB-c\fR
#include <msg_vstream.h>
#include <stringops.h>
#include <sane_accept.h>
+#include <inet_proto.h>
/* Global library. */
smtp_flush(state->stream);
return (0);
}
- if (cmdp->flags & FLAG_DISCONNECT)
+ if (cmdp->flags & FLAG_DISCONNECT)
return (-1);
if (cmdp->flags & FLAG_HARD_ERR) {
smtp_printf(state->stream, "500 Error: command failed");
int sock;
int backlog;
int ch;
+ const char *protocols = INET_PROTO_NAME_ALL;
+ INET_PROTO_INFO *proto_info;
/*
* Initialize diagnostics.
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "acCef:Fh:Ln:pPq:r:s:vw:8")) > 0) {
+ while ((ch = GETOPT(argc, argv, "46acCef:Fh:Ln:pPq:r:s:vw:8")) > 0) {
switch (ch) {
+ case '4':
+ protocols = INET_PROTO_NAME_IPV4;
+ break;
+ case '6':
+ protocols = INET_PROTO_NAME_IPV6;
+ break;
case 'a':
disable_saslauth = 1;
break;
set_cmds_flags(enable_lmtp ? "lhlo" :
disable_esmtp ? "helo" :
"helo, ehlo", FLAG_ENABLE);
+ proto_info = inet_proto_init("protocols", protocols);
if (strncmp(argv[optind], "unix:", 5) == 0) {
sock = unix_listen(argv[optind] + 5, backlog, BLOCKING);
} else {
/* (default: port 25)
/* and sends one or more messages to it, either sequentially
/* or in parallel. The program speaks either SMTP (default) or
-/* LMTP. Connections can be made to UNIX-domain and IPV4 servers.
-/* IPV4 is the default.
+/* LMTP.
+/* Connections can be made to UNIX-domain and IPv4 or IPv6 servers.
+/* IPv4 and IPv6 are the default.
/*
/* Arguments:
+/* .IP \fB-4\fR
+/* Connect to the server with IPv4. This option has no effect when
+/* Postfix is built without IPv6 support.
+/* .IP \fB-6\fR
+/* Connect to the server with IPv6. This option is not available when
+/* Postfix is built without IPv6 support.
/* .IP \fB-c\fR
/* Display a running counter that is incremented each time
/* an SMTP DATA command completes.
#include <connect.h>
#include <mymalloc.h>
#include <events.h>
-#include <find_inet.h>
#include <iostuff.h>
#include <sane_connect.h>
+#include <host_port.h>
+#include <myaddrinfo.h>
+#include <inet_proto.h>
/* Global library. */
static const char *var_myhostname;
static int session_count;
static int message_count = 1;
-static struct sockaddr_in sin;
+static struct sockaddr_storage ss;
#undef sun
static struct sockaddr_un sun;
int sessions = 1;
int ch;
int i;
+ char *buf;
+ const char *parse_err;
+ struct addrinfo *res;
+ int aierr;
+ const char *protocols = INET_PROTO_NAME_ALL;
+ INET_PROTO_INFO *proto_info;
signal(SIGPIPE, SIG_IGN);
msg_vstream_init(argv[0], VSTREAM_ERR);
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "cC:df:l:Lm:Nor:R:s:S:t:vw:")) > 0) {
+ while ((ch = GETOPT(argc, argv, "46cC:df:l:Lm:Nor:R:s:S:t:vw:")) > 0) {
switch (ch) {
+ case '4':
+ protocols = INET_PROTO_NAME_IPV4;
+ break;
+ case '6':
+ protocols = INET_PROTO_NAME_IPV6;
+ break;
case 'c':
count++;
break;
/*
* Translate endpoint address to internal form.
*/
+ proto_info = inet_proto_init("protocols", protocols);
if (strncmp(argv[optind], "unix:", 5) == 0) {
path = argv[optind] + 5;
path_len = strlen(path);
} else {
if (strncmp(argv[optind], "inet:", 5) == 0)
argv[optind] += 5;
- if ((port = split_at(host = argv[optind], ':')) == 0 || *port == 0)
- port = "smtp";
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = find_inet_addr(host);
- sin.sin_port = find_inet_port(port, "tcp");
- sa = (struct sockaddr *) & sin;
- sa_length = sizeof(sin);
+ buf = mystrdup(argv[optind]);
+ if ((parse_err = host_port(buf, &host, (char *) 0, &port, "smtp")) != 0)
+ msg_fatal("%s: %s", argv[optind], parse_err);
+ if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
+ msg_fatal("%s: %s", argv[optind], MAI_STRERROR(aierr));
+ myfree(buf);
+ sa = (struct sockaddr *) & ss;
+ memcpy((char *) sa, res->ai_addr, res->ai_addrlen);
+ sa_length = res->ai_addrlen;
+#ifdef HAS_SA_LEN
+ sa->sa_len = sa_length;
+#endif
+ freeaddrinfo(res);
}
/*
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
trivial-rewrite.o: ../../include/attr.h
trivial-rewrite.o: ../../include/resolve_local.h
trivial-rewrite.o: ../../include/mail_conf.h
-trivial-rewrite.o: ../../include/rewrite_clnt.h
trivial-rewrite.o: ../../include/resolve_clnt.h
+trivial-rewrite.o: ../../include/rewrite_clnt.h
trivial-rewrite.o: ../../include/tok822.h
trivial-rewrite.o: ../../include/mail_addr.h
trivial-rewrite.o: ../../include/mail_server.h
* XXX This may produce incorrect results if we cracked open a quoted
* local-part with routing operators; see discussion above at the top of
* the big loop.
+ *
+ * XXX We explicitly disallow domain names in bare network address form. A
+ * network address destination should be formatted according to RFC 2821:
+ * it should be enclosed in [], and an IPv6 address should have an IPv6:
+ * prefix.
*/
tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
rcpt_domain = strrchr(STR(nextrcpt), '@') + 1;
- if (*rcpt_domain == '[' ? !valid_hostliteral(rcpt_domain, DONT_GRIPE) :
- (!valid_hostname(rcpt_domain, DONT_GRIPE)
- || valid_hostaddr(rcpt_domain, DONT_GRIPE)))
+ if (*rcpt_domain == '[' ? !valid_mailhost_literal(rcpt_domain, DONT_GRIPE) :
+ !valid_hostname(rcpt_domain, DONT_GRIPE))
*flags |= RESOLVE_FLAG_ERROR;
tok822_free_tree(tree);
tree = 0;
fifo_trigger.c file_limit.c find_inet.c fsspace.c fullname.c \
get_domainname.c get_hostname.c hex_quote.c host_port.c htable.c \
inet_addr_host.c inet_addr_list.c inet_addr_local.c inet_connect.c \
- inet_listen.c inet_trigger.c inet_util.c line_wrap.c \
+ inet_listen.c inet_trigger.c line_wrap.c \
lowercase.c lstat_as.c mac_expand.c mac_parse.c make_dirs.c \
match_list.c match_ops.c msg.c msg_output.c msg_syslog.c \
msg_vstream.c mvect.c myflock.c mymalloc.c myrand.c mystrtok.c \
write_buf.c write_wait.c auto_clnt.c attr_clnt.c attr_scan_plain.c \
attr_print_plain.c sane_connect.c neuter.c name_code.c \
uppercase.c unix_recv_fd.c stream_recv_fd.c unix_send_fd.c \
- stream_send_fd.c dict_sdbm.c hex_code.c dummy_read.c dummy_write.c
+ stream_send_fd.c dict_sdbm.c hex_code.c dummy_read.c dummy_write.c \
+ myaddrinfo.c sock_addr.c inet_proto.c cidr_match.c mask_addr.c
OBJS = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \
chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \
fifo_trigger.o file_limit.o find_inet.o fsspace.o fullname.o \
get_domainname.o get_hostname.o hex_quote.o host_port.o htable.o \
inet_addr_host.o inet_addr_list.o inet_addr_local.o inet_connect.o \
- inet_listen.o inet_trigger.o inet_util.o line_wrap.o \
+ inet_listen.o inet_trigger.o line_wrap.o \
lowercase.o lstat_as.o mac_expand.o mac_parse.o make_dirs.o \
match_list.o match_ops.o msg.o msg_output.o msg_syslog.o \
msg_vstream.o mvect.o myflock.o mymalloc.o myrand.o mystrtok.o \
write_buf.o write_wait.o auto_clnt.o attr_clnt.o attr_scan_plain.o \
attr_print_plain.o sane_connect.o $(STRCASE) neuter.o name_code.o \
uppercase.o unix_recv_fd.o stream_recv_fd.o unix_send_fd.o \
- stream_send_fd.o dict_sdbm.o hex_code.o dummy_read.o dummy_write.o
+ stream_send_fd.o dict_sdbm.o hex_code.o dummy_read.o dummy_write.o \
+ myaddrinfo.o sock_addr.o inet_proto.o cidr_match.o mask_addr.o
HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
connect.h ctable.h dict.h dict_db.h dict_cdb.h dict_dbm.h dict_env.h \
dict_cidr.h dict_ht.h dict_ni.h dict_nis.h \
dict_static.h dict_tcp.h dict_unix.h dir_forest.h events.h \
exec_command.h find_inet.h fsspace.h fullname.h get_domainname.h \
get_hostname.h hex_quote.h host_port.h htable.h inet_addr_host.h \
- inet_addr_list.h inet_addr_local.h inet_util.h iostuff.h \
+ inet_addr_list.h inet_addr_local.h iostuff.h \
line_wrap.h listen.h lstat_as.h mac_expand.h mac_parse.h \
make_dirs.h match_list.h match_ops.h msg.h msg_output.h \
msg_syslog.h msg_vstream.h mvect.h myflock.h mymalloc.h myrand.h \
timed_wait.h trigger.h username.h valid_hostname.h vbuf.h \
vbuf_print.h vstream.h vstring.h vstring_vstream.h watchdog.h \
auto_clnt.h attr_clnt.h sane_connect.h name_code.h dict_sdbm.h \
- hex_code.h
+ hex_code.h myaddrinfo.h sock_addr.h inet_proto.h cidr_match.h \
+ mask_addr.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c
DEFS = -I. -D$(SYSTYPE)
watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \
attr_scan0 host_port attr_scan_plain attr_print_plain htable \
- unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code
+ unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
+ myaddrinfo myaddrinfo4 inet_proto
LIB_DIR = ../../lib
INC_DIR = ../../include
all: $(LIB)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+myaddrinfo: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
+myaddrinfo4: $(LIB)
+ mv myaddrinfo.o junk
+ $(CC) $(CFLAGS) -DTEST -DEMULATE_IPV4_ADDRINFO -o $@ myaddrinfo.c $(LIB) $(SYSLIBS)
+ mv junk myaddrinfo.o
+
+inet_proto: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \
- dict_cidr_test attr_scan_plain_test htable_test hex_code_test
+ dict_cidr_test attr_scan_plain_test htable_test hex_code_test \
+ myaddrinfo_test
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
hex_code_test: hex_code
./hex_code
+myaddrinfo_test: myaddrinfo myaddrinfo.ref myaddrinfo.ref2
+ ./myaddrinfo all belly.porcupine.org 168.100.189.2 >myaddrinfo.tmp 2>&1
+ diff myaddrinfo.ref myaddrinfo.tmp
+ rm -f myaddrinfo.tmp
+ ./myaddrinfo all null.porcupine.org 10.0.0.0 >myaddrinfo.tmp 2>&1
+ diff myaddrinfo.ref2 myaddrinfo.tmp
+ rm -f myaddrinfo.tmp
+
+myaddrinfo4_test: myaddrinfo4 myaddrinfo4.ref myaddrinfo4.ref2
+ ./myaddrinfo4 all belly.porcupine.org 168.100.189.2 >myaddrinfo4.tmp 2>&1
+ diff myaddrinfo4.ref myaddrinfo4.tmp
+ ./myaddrinfo4 all null.porcupine.org 10.0.0.0 >myaddrinfo4.tmp 2>&1
+ diff myaddrinfo4.ref2 myaddrinfo4.tmp
+ rm -f myaddrinfo4.tmp
+
# do not edit below this line - it is generated by 'make depend'
alldig.o: alldig.c
alldig.o: sys_defs.h
chroot_uid.o: sys_defs.h
chroot_uid.o: msg.h
chroot_uid.o: chroot_uid.h
+cidr_match.o: cidr_match.c
+cidr_match.o: sys_defs.h
+cidr_match.o: msg.h
+cidr_match.o: vstring.h
+cidr_match.o: vbuf.h
+cidr_match.o: stringops.h
+cidr_match.o: split_at.h
+cidr_match.o: myaddrinfo.h
+cidr_match.o: mask_addr.h
+cidr_match.o: cidr_match.h
clean_env.o: clean_env.c
clean_env.o: sys_defs.h
clean_env.o: msg.h
dict_cidr.o: readlline.h
dict_cidr.o: dict.h
dict_cidr.o: argv.h
+dict_cidr.o: myaddrinfo.h
+dict_cidr.o: cidr_match.h
dict_cidr.o: dict_cidr.h
-dict_cidr.o: split_at.h
dict_db.o: dict_db.c
dict_db.o: sys_defs.h
dict_db.o: msg.h
htable.o: htable.h
inet_addr_host.o: inet_addr_host.c
inet_addr_host.o: sys_defs.h
+inet_addr_host.o: mymalloc.h
inet_addr_host.o: inet_addr_list.h
+inet_addr_host.o: myaddrinfo.h
inet_addr_host.o: inet_addr_host.h
+inet_addr_host.o: sock_addr.h
+inet_addr_host.o: inet_proto.h
+inet_addr_host.o: msg.h
inet_addr_list.o: inet_addr_list.c
inet_addr_list.o: sys_defs.h
inet_addr_list.o: msg.h
inet_addr_list.o: mymalloc.h
+inet_addr_list.o: myaddrinfo.h
+inet_addr_list.o: sock_addr.h
inet_addr_list.o: inet_addr_list.h
inet_addr_local.o: inet_addr_local.c
inet_addr_local.o: sys_defs.h
inet_addr_local.o: vstring.h
inet_addr_local.o: vbuf.h
inet_addr_local.o: inet_addr_list.h
+inet_addr_local.o: myaddrinfo.h
inet_addr_local.o: inet_addr_local.h
+inet_addr_local.o: sock_addr.h
+inet_addr_local.o: mask_addr.h
+inet_addr_local.o: hex_code.h
inet_connect.o: inet_connect.c
inet_connect.o: sys_defs.h
inet_connect.o: mymalloc.h
inet_connect.o: msg.h
-inet_connect.o: find_inet.h
-inet_connect.o: inet_util.h
inet_connect.o: iostuff.h
+inet_connect.o: host_port.h
inet_connect.o: sane_connect.h
inet_connect.o: connect.h
inet_connect.o: timed_connect.h
+inet_connect.o: myaddrinfo.h
+inet_connect.o: sock_addr.h
+inet_connect.o: inet_proto.h
inet_listen.o: inet_listen.c
inet_listen.o: sys_defs.h
inet_listen.o: mymalloc.h
inet_listen.o: msg.h
-inet_listen.o: find_inet.h
-inet_listen.o: inet_util.h
+inet_listen.o: host_port.h
inet_listen.o: iostuff.h
inet_listen.o: listen.h
inet_listen.o: sane_accept.h
+inet_listen.o: myaddrinfo.h
+inet_listen.o: sock_addr.h
+inet_listen.o: inet_proto.h
+inet_proto.o: inet_proto.c
+inet_proto.o: sys_defs.h
+inet_proto.o: mymalloc.h
+inet_proto.o: msg.h
+inet_proto.o: myaddrinfo.h
+inet_proto.o: name_mask.h
+inet_proto.o: inet_proto.h
inet_trigger.o: inet_trigger.c
inet_trigger.o: sys_defs.h
inet_trigger.o: msg.h
inet_trigger.o: mymalloc.h
inet_trigger.o: events.h
inet_trigger.o: trigger.h
-inet_util.o: inet_util.c
-inet_util.o: sys_defs.h
-inet_util.o: mymalloc.h
-inet_util.o: split_at.h
-inet_util.o: inet_util.h
line_wrap.o: line_wrap.c
line_wrap.o: sys_defs.h
line_wrap.o: line_wrap.h
make_dirs.o: vstring.h
make_dirs.o: vbuf.h
make_dirs.o: make_dirs.h
+mask_addr.o: mask_addr.c
+mask_addr.o: sys_defs.h
+mask_addr.o: msg.h
+mask_addr.o: mask_addr.h
match_list.o: match_list.c
match_list.o: sys_defs.h
match_list.o: msg.h
match_ops.o: match_ops.h
match_ops.o: stringops.h
match_ops.o: vstring.h
+match_ops.o: cidr_match.h
+match_ops.o: myaddrinfo.h
msg.o: msg.c
msg.o: sys_defs.h
msg.o: msg.h
mvect.o: sys_defs.h
mvect.o: mymalloc.h
mvect.o: mvect.h
+myaddrinfo.o: myaddrinfo.c
+myaddrinfo.o: sys_defs.h
+myaddrinfo.o: mymalloc.h
+myaddrinfo.o: valid_hostname.h
+myaddrinfo.o: sock_addr.h
+myaddrinfo.o: stringops.h
+myaddrinfo.o: vstring.h
+myaddrinfo.o: vbuf.h
+myaddrinfo.o: msg.h
+myaddrinfo.o: inet_proto.h
+myaddrinfo.o: myaddrinfo.h
myflock.o: myflock.c
myflock.o: sys_defs.h
myflock.o: msg.h
skipblanks.o: stringops.h
skipblanks.o: vstring.h
skipblanks.o: vbuf.h
+sock_addr.o: sock_addr.c
+sock_addr.o: sys_defs.h
+sock_addr.o: msg.h
+sock_addr.o: sock_addr.h
spawn_command.o: spawn_command.c
spawn_command.o: sys_defs.h
spawn_command.o: msg.h
stream_trigger.o: trigger.h
sys_compat.o: sys_compat.c
sys_compat.o: sys_defs.h
+sys_compat.o: iostuff.h
timed_connect.o: timed_connect.c
timed_connect.o: sys_defs.h
timed_connect.o: msg.h
/* string array utilities
/* SYNOPSIS
/* #include "argv.h"
- DESCRIPTION
- .nf
+/* DESCRIPTION
+/* .nf
/*
* External interface.
--- /dev/null
+/*++
+/* NAME
+/* cidr_match 3
+/* SUMMARY
+/* CIDR-style pattern matching
+/* SYNOPSIS
+/* #include <cidr_match.h>
+/*
+/* VSTRING *cidr_match_parse(info, pattern, why)
+/* CIDR_MATCH *info;
+/* char *pattern;
+/* VSTRING *why;
+/*
+/* int cidr_match_execute(info, address)
+/* CIDR_MATCH *info;
+/* const char *address;
+/* DESCRIPTION
+/* This module parses address or address/length patterns and
+/* provides simple address matching. The implementation is
+/* such that parsing and execution can be done without dynamic
+/* memory allocation. The purpose is to minimize overhead when
+/* called by functions that parse and execute on the fly, such
+/* as match_hostaddr().
+/*
+/* cidr_match_parse() parses an address or address/mask
+/* expression and stores the result into the info argument.
+/* The result is non-zero in case of problems: either the
+/* value of the why argument, or a newly allocated VSTRING
+/* (the caller should give the latter to vstring_free()).
+/* The pattern argument is destroyed.
+/*
+/* cidr_match_execute() matches the specified address against
+/* a list of parsed expressions, and returns the matching
+/* expression's data structure.
+/* SEE ALSO
+/* dict_cidr(3) CIDR-style lookup table
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <stringops.h>
+#include <split_at.h>
+#include <myaddrinfo.h>
+#include <mask_addr.h>
+#include <cidr_match.h>
+
+/* Application-specific. */
+
+ /*
+ * This is how we figure out the address family, address bit count and
+ * address byte count for a CIDR_MATCH entry.
+ */
+#ifdef HAS_IPV6
+#define CIDR_MATCH_ADDR_FAMILY(a) (strchr((a), ':') ? AF_INET6 : AF_INET)
+#define CIDR_MATCH_ADDR_BIT_COUNT(f) \
+ ((f) == AF_INET6 ? MAI_V6ADDR_BITS : \
+ (f) == AF_INET ? MAI_V4ADDR_BITS : \
+ (msg_panic("%s: bad address family %d", myname, (f)), 0))
+#define CIDR_MATCH_ADDR_BYTE_COUNT(f) \
+ ((f) == AF_INET6 ? MAI_V6ADDR_BYTES : \
+ (f) == AF_INET ? MAI_V4ADDR_BYTES : \
+ (msg_panic("%s: bad address family %d", myname, (f)), 0))
+#else
+#define CIDR_MATCH_ADDR_FAMILY(a) (AF_INET)
+#define CIDR_MATCH_ADDR_BIT_COUNT(f) \
+ ((f) == AF_INET ? MAI_V4ADDR_BITS : \
+ (msg_panic("%s: bad address family %d", myname, (f)), 0))
+#define CIDR_MATCH_ADDR_BYTE_COUNT(f) \
+ ((f) == AF_INET ? MAI_V4ADDR_BYTES : \
+ (msg_panic("%s: bad address family %d", myname, (f)), 0))
+#endif
+
+/* cidr_match_execute - match address against compiled CIDR pattern list */
+
+CIDR_MATCH *cidr_match_execute(CIDR_MATCH *list, const char *addr)
+{
+ unsigned char addr_bytes[CIDR_MATCH_ABYTES];
+ unsigned addr_family;
+ unsigned char *mp;
+ unsigned char *np;
+ unsigned char *ap;
+ CIDR_MATCH *entry;
+
+ addr_family = CIDR_MATCH_ADDR_FAMILY(addr);
+ if (inet_pton(addr_family, addr, addr_bytes) != 1)
+ return (0);
+
+ for (entry = list; entry; entry = entry->next) {
+ if (entry->addr_family == addr_family) {
+ /* Unoptimized case: netmask with some or all bits zero. */
+ if (entry->mask_shift < entry->addr_bit_count) {
+ for (np = entry->net_bytes, mp = entry->mask_bytes,
+ ap = addr_bytes; /* void */ ; np++, mp++, ap++) {
+ if (ap >= addr_bytes + entry->addr_byte_count)
+ return (entry);
+ if ((*ap & *mp) != *np)
+ break;
+ }
+ }
+ /* Optimized case: all 1 netmask (i.e. no netmask specified). */
+ else {
+ for (np = entry->net_bytes,
+ ap = addr_bytes; /* void */ ; np++, ap++) {
+ if (ap >= addr_bytes + entry->addr_byte_count)
+ return (entry);
+ if (*ap != *np)
+ break;
+ }
+ }
+ }
+ }
+ return (0);
+}
+
+/* cidr_match_parse - parse CIDR pattern */
+
+VSTRING *cidr_match_parse(CIDR_MATCH *ip, char *pattern, VSTRING *why)
+{
+ const char *myname = "cidr_match_parse";
+ char *mask_search;
+ char *mask;
+ MAI_HOSTADDR_STR hostaddr;
+ unsigned char *np;
+ unsigned char *mp;
+
+ /*
+ * Strip [] from [addr/len] or [addr]/len, destroying the pattern. CIDR
+ * maps don't need [] to eliminate syntax ambiguity, but matchlists need
+ * it. While stripping [], figure out where we should start looking for
+ * /mask information.
+ */
+ if (*pattern == '[') {
+ pattern++;
+ if ((mask_search = split_at(pattern, ']')) == 0) {
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+ "missing ']' character after \"[%s\"", pattern);
+ return (why);
+ } else if (*mask_search != '/') {
+ if (*mask_search != 0) {
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+ "garbage after \"[%s]\"", pattern);
+ return (why);
+ }
+ mask_search = pattern;
+ }
+ } else
+ mask_search = pattern;
+
+ /*
+ * Parse the pattern into network and mask, destroying the pattern.
+ */
+ if ((mask = split_at(mask_search, '/')) != 0) {
+ ip->addr_family = CIDR_MATCH_ADDR_FAMILY(pattern);
+ ip->addr_bit_count = CIDR_MATCH_ADDR_BIT_COUNT(ip->addr_family);
+ ip->addr_byte_count = CIDR_MATCH_ADDR_BYTE_COUNT(ip->addr_family);
+ if (!alldig(mask)
+ || (ip->mask_shift = atoi(mask)) > ip->addr_bit_count
+ || inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) {
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+ "bad net/mask pattern: \"%s/%s\"", pattern, mask);
+ return (why);
+ }
+ if (ip->mask_shift > 0) {
+ /* Allow for bytes > 8. */
+ memset(ip->mask_bytes, (unsigned char) -1, ip->addr_byte_count);
+ mask_addr(ip->mask_bytes, ip->addr_byte_count, ip->mask_shift);
+ } else
+ memset(ip->mask_bytes, 0, ip->addr_byte_count);
+
+ /*
+ * Sanity check: all host address bits must be zero.
+ */
+ for (np = ip->net_bytes, mp = ip->mask_bytes;
+ np < ip->net_bytes + ip->addr_byte_count; np++, mp++) {
+ if (*np & ~(*mp)) {
+ mask_addr(ip->net_bytes, ip->addr_byte_count, ip->mask_shift);
+ if (inet_ntop(ip->addr_family, ip->net_bytes, hostaddr.buf,
+ sizeof(hostaddr.buf)) == 0)
+ msg_fatal("inet_ntop: %m");
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+ "non-null host address bits in \"%s/%s\", "
+ "perhaps you should use \"%s/%d\" instead",
+ pattern, mask, hostaddr.buf, ip->mask_shift);
+ return (why);
+ }
+ }
+ }
+
+ /*
+ * No /mask specified. Treat a bare network address as /allbits.
+ */
+ else {
+ ip->addr_family = CIDR_MATCH_ADDR_FAMILY(pattern);
+ ip->addr_bit_count = CIDR_MATCH_ADDR_BIT_COUNT(ip->addr_family);
+ ip->addr_byte_count = CIDR_MATCH_ADDR_BYTE_COUNT(ip->addr_family);
+ if (inet_pton(ip->addr_family, pattern, ip->net_bytes) != 1) {
+ vstring_sprintf(why ? why : (why = vstring_alloc(20)),
+ "bad address pattern: \"%s\"", pattern);
+ return (why);
+ }
+ ip->mask_shift = ip->addr_bit_count;
+ /* Allow for bytes > 8. */
+ memset(ip->mask_bytes, (unsigned char) -1, ip->addr_byte_count);
+ }
+
+ /*
+ * Wrap up the result.
+ */
+ ip->next = 0;
+
+ return (0);
+}
--- /dev/null
+#ifndef _CIDR_MATCH_H_INCLUDED_
+#define _CIDR_MATCH_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_cidr 3h
+/* SUMMARY
+/* CIDR-style pattern matching
+/* SYNOPSIS
+/* #include <cidr_match.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <limits.h> /* CHAR_BIT */
+
+ /*
+ * Utility library.
+ */
+#include <myaddrinfo.h> /* MAI_V6ADDR_BYTES etc. */
+#include <vstring.h>
+
+ /*
+ * External interface.
+ *
+ * Address length is protocol dependent. Find out how large our address byte
+ * strings should be.
+ */
+#ifdef HAS_IPV6
+# define CIDR_MATCH_ABYTES MAI_V6ADDR_BYTES
+#else
+# define CIDR_MATCH_ABYTES MAI_V4ADDR_BYTES
+#endif
+
+ /*
+ * Each parsed CIDR pattern can be member of a linked list.
+ */
+typedef struct CIDR_MATCH {
+ unsigned char net_bytes[CIDR_MATCH_ABYTES]; /* network portion */
+ unsigned char mask_bytes[CIDR_MATCH_ABYTES]; /* network mask */
+ unsigned char addr_family; /* AF_XXX */
+ unsigned char addr_byte_count; /* typically, 4 or 16 */
+ unsigned char addr_bit_count; /* optimization */
+ unsigned char mask_shift; /* optimization */
+ struct CIDR_MATCH *next; /* next entry */
+} CIDR_MATCH;
+
+extern VSTRING *cidr_match_parse(CIDR_MATCH *, char *, VSTRING *);
+extern CIDR_MATCH *cidr_match_execute(CIDR_MATCH *, const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
/* dict_default_sequence - trap unimplemented operation */
-static int dict_default_sequence(DICT *dict, int function,
+static int dict_default_sequence(DICT *dict, int unused_function,
const char **unused_key, const char **unused_value)
{
msg_fatal("%s table %s: sequence operation is not supported",
#include <unistd.h>
#include <string.h>
#include <ctype.h>
+#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
/* Utility library. */
#include <mymalloc.h>
#include <stringops.h>
#include <readlline.h>
#include <dict.h>
+#include <myaddrinfo.h>
+#include <cidr_match.h>
#include <dict_cidr.h>
-#include <split_at.h>
/* Application-specific. */
/*
* Each rule in a CIDR table is parsed and stored in a linked list.
- * Obviously all this is IPV4 specific and needs to be redone for IPV6.
*/
typedef struct DICT_CIDR_ENTRY {
- unsigned long net_bits; /* network portion of address */
- unsigned long mask_bits; /* network mask */
+ CIDR_MATCH cidr_info; /* must be first */
char *value; /* lookup result */
- struct DICT_CIDR_ENTRY *next; /* next entry */
} DICT_CIDR_ENTRY;
typedef struct {
DICT_CIDR_ENTRY *head; /* first entry */
} DICT_CIDR;
-#define BITS_PER_ADDR 32
-
/* dict_cidr_lookup - CIDR table lookup */
static const char *dict_cidr_lookup(DICT *dict, const char *key)
{
DICT_CIDR *dict_cidr = (DICT_CIDR *) dict;
DICT_CIDR_ENTRY *entry;
- unsigned long addr;
if (msg_verbose)
- msg_info("dict_cidr_lookup: %s: %s", dict_cidr->dict.name, key);
-
- if ((addr = inet_addr(key)) == INADDR_NONE)
- return (0);
-
- for (entry = dict_cidr->head; entry; entry = entry->next)
- if ((addr & entry->mask_bits) == entry->net_bits)
- return (entry->value);
+ msg_info("dict_cidr_lookup: %s: %s", dict->name, key);
+ if ((entry = (DICT_CIDR_ENTRY *)
+ cidr_match_execute(&(dict_cidr->head->cidr_info), key)) != 0)
+ return (entry->value);
return (0);
}
DICT_CIDR_ENTRY *next;
for (entry = dict_cidr->head; entry; entry = next) {
- next = entry->next;
+ next = (DICT_CIDR_ENTRY *) entry->cidr_info.next;
myfree(entry->value);
myfree((char *) entry);
}
/* dict_cidr_parse_rule - parse CIDR table rule into network, mask and value */
-static DICT_CIDR_ENTRY *dict_cidr_parse_rule(const char *mapname, int lineno,
- char *p)
+static DICT_CIDR_ENTRY *dict_cidr_parse_rule(char *p, VSTRING *why)
{
DICT_CIDR_ENTRY *rule;
- char *key;
+ char *pattern;
char *value;
- char *mask;
- int mask_shift;
- unsigned long net_bits;
- unsigned long mask_bits;
- struct in_addr net_addr;
+ CIDR_MATCH cidr_info;
+ MAI_HOSTADDR_STR hostaddr;
/*
* Split the rule into key and value. We already eliminated leading
* whitespace, comments, empty lines or lines with whitespace only. This
* means a null key can't happen but we will handle this anyway.
*/
- key = p;
+ pattern = p;
while (*p && !ISSPACE(*p)) /* Skip over key */
p++;
if (*p) /* Terminate key */
p++;
value = p;
trimblanks(value, 0)[0] = 0; /* Trim trailing blanks */
- if (*key == 0) {
- msg_warn("cidr map %s, line %d: no address pattern: skipping this rule",
- mapname, lineno);
+ if (*pattern == 0) {
+ vstring_sprintf(why, "no address pattern");
return (0);
}
if (*value == 0) {
- msg_warn("cidr map %s, line %d: no lookup result: skipping this rule",
- mapname, lineno);
+ vstring_sprintf(why, "no lookup result");
return (0);
}
/*
- * Parse the key into network and mask, and destroy the key. Treat a bare
- * network address as /32.
- *
- * We need explicit code for /0. The result of << is undefined when the
- * shift is greater or equal to the number of bits in the shifted
- * operand.
+ * Parse the pattern, destroying it in the process.
*/
- if ((mask = split_at(key, '/')) != 0) {
- if (!alldig(mask) || (mask_shift = atoi(mask)) > BITS_PER_ADDR
- || (net_bits = inet_addr(key)) == INADDR_NONE) {
- msg_warn("cidr map %s, line %d: bad net/mask pattern: \"%s/%s\": "
- "skipping this rule", mapname, lineno, key, mask);
- return (0);
- }
- mask_bits = mask_shift > 0 ?
- htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift)) : 0;
- if (net_bits & ~mask_bits) {
- net_addr.s_addr = (net_bits & mask_bits);
- msg_warn("cidr map %s, line %d: net/mask pattern \"%s/%s\" with "
- "non-null host portion: skipping this rule",
- mapname, lineno, key, mask);
- msg_warn("specify \"%s/%d\" if this is really what you want",
- inet_ntoa(net_addr), mask_shift);
- return (0);
- }
- } else {
- if ((net_bits = inet_addr(key)) == INADDR_NONE) {
- msg_warn("cidr map %s, line %d: bad address pattern: \"%s\": "
- "skipping this rule", mapname, lineno, key);
- return (0);
- }
- mask_shift = 32;
- mask_bits = htonl(0xffffffff);
- }
+ if (cidr_match_parse(&cidr_info, pattern, why) != 0)
+ return (0);
/*
* Bundle up the result.
*/
rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY));
- rule->net_bits = net_bits;
- rule->mask_bits = mask_bits;
+ rule->cidr_info = cidr_info;
rule->value = mystrdup(value);
- rule->next = 0;
-
- if (msg_verbose)
- msg_info("dict_cidr_open: %s: %lu/%d %s",
- mapname, rule->net_bits, mask_shift, rule->value);
+ if (msg_verbose) {
+ if (inet_ntop(cidr_info.addr_family, cidr_info.net_bytes,
+ hostaddr.buf, sizeof(hostaddr.buf)) == 0)
+ msg_fatal("inet_ntop: %m");
+ msg_info("dict_cidr_open: add %s/%d %s",
+ hostaddr.buf, cidr_info.mask_shift, rule->value);
+ }
return (rule);
}
DICT_CIDR *dict_cidr;
VSTREAM *map_fp;
VSTRING *line_buffer = vstring_alloc(100);
+ VSTRING *why = vstring_alloc(100);
DICT_CIDR_ENTRY *rule;
DICT_CIDR_ENTRY *last_rule = 0;
int lineno = 0;
msg_fatal("open %s: %m", mapname);
while (readlline(line_buffer, map_fp, &lineno)) {
- rule = dict_cidr_parse_rule(mapname, lineno, vstring_str(line_buffer));
- if (rule == 0)
+ rule = dict_cidr_parse_rule(vstring_str(line_buffer), why);
+ if (rule == 0) {
+ msg_warn("cidr map %s, line %d: %s: skipping this rule",
+ mapname, lineno, vstring_str(why));
continue;
+ }
if (last_rule == 0)
dict_cidr->head = rule;
else
- last_rule->next = rule;
+ last_rule->cidr_info.next = &(rule->cidr_info);
last_rule = rule;
}
if (vstream_fclose(map_fp))
msg_fatal("cidr map %s: read error: %m", mapname);
vstring_free(line_buffer);
+ vstring_free(why);
return (DICT_DEBUG (&dict_cidr->dict));
}
get 172.16.17.1
get 172.17.1.1
get 172.17.1.2
+get 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+get 2001:240:5c7:0:2d0:b7ff:febe:ca9f
+get 1.1.1.1
+get 1:1:1:1:1:1:1:1
172.999.0.0/21 whatever
172.16.1.999 whatever
172.16.1.4
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7 match 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+2001:240:5c7::/64 match netblock 2001:240:5c7::/64
+1.0.0.0/0 match 0.0.0.0/0
+0.0.0.0/0 match 0.0.0.0/0
+1::/0 match ::/0
+::/0 match ::/0
+[1234 foo
+[1234]junk bar
+172.16.1.3/3x whatever
-./dict_open: warning: cidr map dict_cidr.map, line 5: net/mask pattern "172.16.1.3/21" with non-null host portion: skipping this rule
-./dict_open: warning: specify "172.16.0.0/21" if this is really what you want
+./dict_open: warning: cidr map dict_cidr.map, line 5: non-null host address bits in "172.16.1.3/21", perhaps you should use "172.16.0.0/21" instead: skipping this rule
./dict_open: warning: cidr map dict_cidr.map, line 6: bad net/mask pattern: "172.16.1.3/33": skipping this rule
./dict_open: warning: cidr map dict_cidr.map, line 7: bad net/mask pattern: "172.999.0.0/21": skipping this rule
./dict_open: warning: cidr map dict_cidr.map, line 8: bad address pattern: "172.16.1.999": skipping this rule
./dict_open: warning: cidr map dict_cidr.map, line 9: no lookup result: skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 12: non-null host address bits in "1.0.0.0/0", perhaps you should use "0.0.0.0/0" instead: skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 14: non-null host address bits in "1::/0", perhaps you should use "::/0" instead: skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 16: missing ']' character after "[1234": skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 17: garbage after "[1234]": skipping this rule
+./dict_open: warning: cidr map dict_cidr.map, line 18: bad net/mask pattern: "172.16.1.3/3x": skipping this rule
172.16.0.0=554 match bad netblock 172.16.0.0/21
172.16.0.1=554 match bad netblock 172.16.0.0/21
172.16.7.255=554 match bad netblock 172.16.0.0/21
172.16.8.1=554 match bad netblock 172.16.8.0/21
172.16.17.1=554 match bad netblock 172.16.0.0/16
172.17.1.1=554 match bad naked address
-172.17.1.2: not found
+172.17.1.2=match 0.0.0.0/0
+2001:240:5c7:0:2d0:b7ff:fe88:2ca7=match 2001:240:5c7:0:2d0:b7ff:fe88:2ca7
+2001:240:5c7:0:2d0:b7ff:febe:ca9f=match netblock 2001:240:5c7::/64
+1.1.1.1=match 0.0.0.0/0
+1:1:1:1:1:1:1:1=match ::/0
#include <vstream.h>
#include <msg_vstream.h>
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
msg_vstream_init(argv[0], VSTREAM_ERR);
if (argc != 2)
/* BSD TCP/IP network software.
/*
/* find_inet_addr() translates a symbolic or numerical hostname.
+/* This function is deprecated. Use hostname_to_hostaddr() instead.
/*
/* find_inet_port() translates a symbolic or numerical port name.
/* BUGS
return (len);
}
-main(int unused_argc, char **unused_argv)
+int main(int unused_argc, char **unused_argv)
{
VSTRING *raw = vstring_alloc(BUFLEN);
VSTRING *hex = vstring_alloc(100);
/* SYNOPSIS
/* #include <host_port.h>
/*
-/* const char *host_port(string, host, port, def_service)
+/* const char *host_port(string, host, def_host, port, def_service)
/* char *string;
/* char **host;
+/* char *def_host;
/* char **port;
/* char *def_service;
/* DESCRIPTION
/* name or address, and the service name or port number.
/* The input string is modified.
/*
-/* The following input formats are understood:
+/* The following input formats are understood (null means
+/* a null pointer argument):
/*
-/* [host]:port, [host]:, [host].
+/* When def_service is not null, and def_host is null:
/*
-/* host:port, host:, host.
+/* [host]:port, [host]:, [host]
+/*
+/* host:port, host:, host
+/*
+/* When def_host is not null, and def_service is null:
+/*
+/* :port, port
+/*
+/* Other combinations of def_service and def_host are
+/* not supported and produce undefined results.
/* DIAGNOSTICS
/* The result is a null pointer in case of success.
/* In case of problems the result is a string pointer with
/* the problem type.
+/* CLIENT EXAMPLE
+/* .ad
+/* .fi
+/* Typical client usage allows the user to omit the service port,
+/* in which case the client connects to a pre-determined default
+/* port:
+/* .nf
+/* .na
+/*
+/* buf = mystrdup(endpoint);
+/* if ((parse_error = host_port(buf, &host, NULL, &port, defport)) != 0)
+/* msg_fatal("%s in \"%s\"", parse_error, endpoint);
+/* if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
+/* msg_fatal("%s: %s", endpoint, MAI_STRERROR(aierr));
+/* myfree(buf);
+/* SERVER EXAMPLE
+/* .ad
+/* .fi
+/* Typical server usage allows the user to omit the host, meaning
+/* listen on all available network addresses:
+/* .nf
+/* .na
+/*
+/* buf = mystrdup(endpoint);
+/* if ((parse_error = host_port(buf, &host, "", &port, NULL)) != 0)
+/* msg_fatal("%s in \"%s\"", parse_error, endpoint);
+/* if (*host == 0)
+/* host = 0;
+/* if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
+/* msg_fatal("%s: %s", endpoint, MAI_STRERROR(aierr));
+/* myfree(buf);
/* LICENSE
/* .ad
/* .fi
/* host_port - parse string into host and port, destroy string */
-const char *host_port(char *buf, char **host, char **port,
- char *def_service)
+const char *host_port(char *buf, char **host, char *def_host,
+ char **port, char *def_service)
{
char *cp = buf;
return ("missing \"]\"");
if (*cp && *cp++ != ':')
return ("garbage after \"]\"");
- if (*cp == 0)
- *port = def_service;
- else
- *port = cp;
-
- /*
- * [host:port], [host:]. These conflict with IPV6 address literals.
- */
-#if 1
- if (strchr(*host, ':')) {
- msg_warn("old-style address form: [%s]", *host);
- msg_warn("support for [host:port] forms will go away");
- msg_warn("specify [host]:port instead");
- return (host_port(buf + 1, host, port, def_service));
- }
-#endif
+ *port = *cp ? cp : def_service;
}
/*
- * host:port, host:, host.
+ * host:port, host:, host, :port, port.
*/
else {
- *host = cp;
- if ((cp = split_at_right(cp, ':')) == 0 || *cp == 0)
- *port = def_service;
- else
- *port = cp;
+ if ((cp = split_at_right(buf, ':')) != 0) {
+ *host = *buf ? buf : def_host;
+ *port = *cp ? cp : def_service;
+ } else {
+ *host = def_host ? def_host : (*buf ? buf : 0);
+ *port = def_service ? def_service : (*buf ? buf : 0);
+ }
}
+ if (*host == 0)
+ return ("missing host information");
+ if (*port == 0)
+ return ("missing service information");
/*
* Final sanity checks. We're still sloppy, allowing bare numerical
* network addresses instead of requiring proper [ipaddress] forms.
*/
- if (!valid_hostname(*host, DONT_GRIPE)
+ if (*host != def_host && !valid_hostname(*host, DONT_GRIPE)
&& !valid_hostaddr(*host, DONT_GRIPE))
return ("valid hostname or network address required");
- if (ISDIGIT(**port) && !alldig(*port))
+ if (*port != def_service && ISDIGIT(**port) && !alldig(*port))
return ("garbage after numerical service");
return (0);
}
while (vstring_fgets_nonl(in_buf, VSTREAM_IN)) {
vstream_printf(">> %s\n", STR(in_buf));
vstream_fflush(VSTREAM_OUT);
+ if (*STR(in_buf) == '#')
+ continue;
vstring_strcpy(parse_buf, STR(in_buf));
- if ((err = host_port(STR(parse_buf), &host, &port, "default-service")) != 0) {
+ if ((err = host_port(STR(parse_buf), &host, (char *) 0, &port, "default-service")) != 0) {
msg_warn("%s in %s", err, STR(in_buf));
} else {
vstream_printf("host %s port %s\n", host, port);
/* External interface. */
-extern const char *host_port(char *, char **, char **, char *);
+extern const char *host_port(char *, char **, char *, char **, char *);
/* LICENSE
/* .ad
[hhh]:ppp
[hhh]:
[hhh]
-[hhh:ppp]
-[hhh:]
+#[hhh:ppp]
+#[hhh:]
hhh:1pp
[hh.]
hh.
host hhh port default-service
>> [hhh]
host hhh port default-service
->> [hhh:ppp]
-unknown: warning: old-style address form: [hhh:ppp]
-unknown: warning: support for [host:port] forms will go away
-unknown: warning: specify [host]:port instead
-host hhh port ppp
->> [hhh:]
-unknown: warning: old-style address form: [hhh:]
-unknown: warning: support for [host:port] forms will go away
-unknown: warning: specify [host]:port instead
-host hhh port default-service
+>> #[hhh:ppp]
+>> #[hhh:]
>> hhh:1pp
unknown: warning: garbage after numerical service in hhh:1pp
>> [hh.]
/* DESCRIPTION
/* inet_addr_host() determines all interface addresses of the
/* named host. The host may be specified as a symbolic name,
-/* or as a numerical address. Address results are appended to
+/* or as a numerical address. An empty host expands as the
+/* wild-card address. Address results are appended to
/* the specified address list. The result value is the number
/* of addresses appended to the list.
/* DIAGNOSTICS
#include <sys_defs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <sys/socket.h>
#include <netdb.h>
-
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
/* Utility library. */
+#include <mymalloc.h>
#include <inet_addr_list.h>
#include <inet_addr_host.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
+#include <inet_proto.h>
+#include <msg.h>
/* inet_addr_host - look up address list for host */
int inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname)
{
- struct hostent *hp;
- struct in_addr addr;
+ const char *myname = "inet_addr_host";
+ int sock;
+ struct addrinfo *res0;
+ struct addrinfo *res;
+ int aierr;
+ int hostnamelen;
+ const char *hname;
+ const char *serv;
int initial_count = addr_list->used;
-
- if ((addr.s_addr = inet_addr(hostname)) != INADDR_NONE) {
- inet_addr_list_append(addr_list, &addr);
+ INET_PROTO_INFO *proto_info;
+
+ /*
+ * The use of square brackets around an IPv6 addresses is required, even
+ * though we don't enforce it as it'd make the code unnecessarily
+ * complicated.
+ *
+ * XXX AIX 5.1 getaddrinfo() does not allow "0" as service, regardless of
+ * whether or not a host is specified.
+ */
+ if (*hostname == 0) {
+ hname = 0;
+ serv = "1";
+ } else if (*hostname == '['
+ && hostname[(hostnamelen = strlen(hostname)) - 1] == ']') {
+ hname = mystrndup(hostname + 1, hostnamelen - 2);
+ serv = 0;
} else {
- if ((hp = gethostbyname(hostname)) != 0)
- while (hp->h_addr_list[0])
- inet_addr_list_append(addr_list,
- (struct in_addr *) * hp->h_addr_list++);
+ hname = hostname;
+ serv = 0;
}
+
+ proto_info = inet_proto_info();
+ if ((aierr = hostname_to_sockaddr(hname, serv, SOCK_STREAM, &res0)) == 0) {
+ for (res = res0; res; res = res->ai_next) {
+
+ /*
+ * Safety net.
+ */
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("%s: skipping address family %d for host \"%s\"",
+ myname, res->ai_family, hostname);
+ continue;
+ }
+
+ /*
+ * On Linux systems it is not unusual for user-land to be out of
+ * sync with kernel-land. When this is the case we try to be
+ * helpful and filter out address families that the library
+ * claims to understand but that are not supported by the kernel.
+ */
+ if ((sock = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
+ msg_warn("%s: skipping address family %d: %m",
+ myname, res->ai_family);
+ continue;
+ }
+ if (close(sock))
+ msg_warn("%s: close socket: %m", myname);
+
+ inet_addr_list_append(addr_list, res->ai_addr);
+ }
+ freeaddrinfo(res0);
+ }
+ if (hname && hname != hostname)
+ myfree((char *) hname);
+
return (addr_list->used - initial_count);
}
#include <msg.h>
#include <vstream.h>
#include <msg_vstream.h>
+#include <sock_addr.h>
int main(int argc, char **argv)
{
- INET_ADDR_LIST addr_list;
- int i;
+ INET_ADDR_LIST list;
+ struct sockaddr_storage *sa;
+ MAI_HOSTADDR_STR hostaddr;
+ INET_PROTO_INFO *proto_info;
msg_vstream_init(argv[0], VSTREAM_ERR);
- if (argc < 2)
- msg_fatal("usage: %s hostname...", argv[0]);
+ if (argc < 3)
+ msg_fatal("usage: %s protocols hostname...", argv[0]);
+
+ proto_info = inet_proto_init(argv[0], *++argv);
+
+ inet_addr_list_init(&list);
while (--argc && *++argv) {
- inet_addr_list_init(&addr_list);
- if (inet_addr_host(&addr_list, *argv) == 0)
+ if (inet_addr_host(&list, *argv) == 0)
msg_fatal("not found: %s", *argv);
- for (i = 0; i < addr_list.used; i++)
- vstream_printf("%s\n", inet_ntoa(addr_list.addrs[i]));
+ for (sa = list.addrs; sa < list.addrs + list.used; sa++) {
+ SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ vstream_printf("%s\n", hostaddr.buf);
+ }
vstream_fflush(VSTREAM_OUT);
}
- inet_addr_list_free(&addr_list);
+ inet_addr_list_free(&list);
+ return (0);
}
#endif
/*
/* void inet_addr_list_append(list,addr)
/* INET_ADDR_LIST *list;
-/* struct in_addr *addr;
+/* struct sockaddr *addr;
/*
/* void inet_addr_list_uniq(list)
/* INET_ADDR_LIST *list;
/* System library. */
#include <sys_defs.h>
+#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
+#include <netdb.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
#include <inet_addr_list.h>
/* inet_addr_list_init - initialize internet address list */
list->used = 0;
list->size = 0;
init_size = 2;
- list->addrs = (struct in_addr *) mymalloc(sizeof(*list->addrs) * init_size);
+ list->addrs = (struct sockaddr_storage *)
+ mymalloc(sizeof(*list->addrs) * init_size);
list->size = init_size;
}
/* inet_addr_list_append - append address to internet address list */
-void inet_addr_list_append(INET_ADDR_LIST *list, struct in_addr * addr)
+void inet_addr_list_append(INET_ADDR_LIST *list,
+ struct sockaddr * addr)
{
char *myname = "inet_addr_list_append";
+ MAI_HOSTADDR_STR hostaddr;
int new_size;
- if (msg_verbose > 1)
- msg_info("%s: %s", myname, inet_ntoa(*addr));
-
+ if (msg_verbose > 1) {
+ SOCKADDR_TO_HOSTADDR(addr, SOCK_ADDR_LEN(addr),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ msg_info("%s: %s", myname, hostaddr.buf);
+ }
if (list->used >= list->size) {
new_size = list->size * 2;
- list->addrs = (struct in_addr *)
+ list->addrs = (struct sockaddr_storage *)
myrealloc((char *) list->addrs, sizeof(*list->addrs) * new_size);
list->size = new_size;
}
- list->addrs[list->used++] = *addr;
+ memcpy(list->addrs + list->used++, addr, SOCK_ADDR_LEN(addr));
}
/* inet_addr_list_comp - compare addresses */
static int inet_addr_list_comp(const void *a, const void *b)
{
- const struct in_addr *a_addr = (const struct in_addr *) a;
- const struct in_addr *b_addr = (const struct in_addr *) b;
- return (a_addr->s_addr - b_addr->s_addr);
+ /*
+ * In case (struct *) != (void *).
+ */
+ return (sock_addr_cmp_addr(SOCK_ADDR_PTR(a), SOCK_ADDR_PTR(b)));
}
/* inet_addr_list_uniq - weed out duplicates */
}
#ifdef TEST
+#include <inet_proto.h>
/*
* Duplicate elimination needs to be tested.
static void inet_addr_list_print(INET_ADDR_LIST *list)
{
- int n;
+ MAI_HOSTADDR_STR hostaddr;
+ struct sockaddr_storage *sa;
- for (n = 0; n < list->used; n++)
- msg_info("%s", inet_ntoa(list->addrs[n]));
+ for (sa = list->addrs; sa < list->addrs + list->used; sa++) {
+ SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ msg_info("%s", hostaddr.buf);
+ }
}
int main(int argc, char **argv)
{
INET_ADDR_LIST list;
+ INET_PROTO_INFO *proto_info;
+ proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
inet_addr_list_init(&list);
while (--argc && *++argv)
if (inet_addr_host(&list, *argv) == 0)
/* .nf
/*
- * System library.
+ * Utility library.
*/
-#include <netinet/in.h>
+#include <myaddrinfo.h> /* generic name/addr API */
/*
* External interface.
typedef struct INET_ADDR_LIST {
int used; /* nr of elements in use */
int size; /* actual list size */
- struct in_addr *addrs; /* payload */
+ struct sockaddr_storage *addrs; /* payload */
} INET_ADDR_LIST;
extern void inet_addr_list_init(INET_ADDR_LIST *);
extern void inet_addr_list_free(INET_ADDR_LIST *);
extern void inet_addr_list_uniq(INET_ADDR_LIST *);
-extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *);
+extern void inet_addr_list_append(INET_ADDR_LIST *, struct sockaddr *);
/* LICENSE
/* .ad
/* SYNOPSIS
/* #include <inet_addr_local.h>
/*
-/* int inet_addr_local(addr_list, mask_list)
+/* int inet_addr_local(addr_list, mask_list, addr_family_list)
/* INET_ADDR_LIST *addr_list;
/* INET_ADDR_LIST *mask_list;
+/* unsigned *addr_family;
/* DESCRIPTION
/* inet_addr_local() determines all active IP interface addresses
/* of the local system. Any address found is appended to the
/*
/* The mask_list is either a null pointer, or it is a list that
/* receives the netmasks of the interface addresses that were found.
+/*
+/* The addr_family_list specifies one or more of AF_INET or AF_INET6.
/* DIAGNOSTICS
/* Fatal errors: out of memory.
/* SEE ALSO
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Dean C. Strik
+/* Department ICT
+/* Eindhoven University of Technology
+/* P.O. Box 513
+/* 5600 MB Eindhoven, Netherlands
+/* E-mail: <dean@ipnet6.org>
/*--*/
/* System library. */
#endif
#include <errno.h>
#include <string.h>
+#ifdef HAS_IPV6 /* Linux only? */
+#include <netdb.h>
+#include <stdio.h>
+#endif
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#endif
/* Utility library. */
#include <vstring.h>
#include <inet_addr_list.h>
#include <inet_addr_local.h>
+#include <myaddrinfo.h>
+#include <sock_addr.h>
+#include <mask_addr.h>
+#include <hex_code.h>
/*
- * Support for variable-length addresses.
+ * Postfix needs its own interface address information to determine whether
+ * or not it is an MX host for some destination; without this information,
+ * mail would loop between MX hosts. Postfix also needs its interface
+ * addresses to figure out whether or not it is final destination for
+ * addresses of the form username@[ipaddress].
+ *
+ * Postfix needs its own interface netmask information when no explicit
+ * mynetworks setting is given in main.cf, and "mynetworks_style = subnet".
+ * The mynetworks parameter controls, among others, what mail clients are
+ * allowed to relay mail through Postfix.
+ *
+ * Different systems have different ways to find out this information. We will
+ * therefore use OS dependent methods. An overview:
+ *
+ * - Use getifaddrs() when available. This supports both IPv4/IPv6 addresses.
+ * The implementation however is not present in all major operating systems.
+ *
+ * - Use SIOCGLIFCONF when available. This supports both IPv4/IPv6 addresses.
+ * With SIOCGLIFNETMASK we can obtain the netmask for either address family.
+ * Again, this is not present in all major operating systems.
+ *
+ * - On Linux, get IPv4 interface information with SIOCGIFCONF, and read IPv6
+ * address/prefix information from a file in the /proc filesystem. Linux
+ * does not return IPv6 addresses with SIOCGIFCONF.
+ *
+ * - On other systems we expect SIOCGIFCONF to return IPv6 addresses. Since
+ * SIOCGIFNETMASK does not work reliably for IPv6 addresses, we always set
+ * the prefix length to /128 (host), and expect the user to configure a more
+ * appropriate mynetworks setting if needed.
+ *
+ * XXX: Each lookup method is implemented by its own function, so we duplicate
+ * some code. In this case, I think this is better than really drowning in
+ * the #ifdefs...
+ *
+ * -- Dean Strik (dcs)
*/
-#ifdef _SIZEOF_ADDR_IFREQ
-#define NEXT_INTERFACE(ifr) ((struct ifreq *) \
- ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)))
-#define IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr)
-#else
+
+/* ial_socket - make socket for ioctl() operations */
+
+static int ial_socket(int af)
+{
+ char *myname = "inet_addr_local[socket]";
+ int sock;
+
+ /*
+ * The host may not be actually configured with IPv6. When IPv6 support
+ * is not actually in the kernel, don't consider failure to create an
+ * IPv6 socket as fatal. This could be tuned better though. For other
+ * families, the error is fatal.
+ *
+ * XXX Now that Postfix controls protocol support centrally with the
+ * inet_proto(3) module, this workaround should no longer be needed.
+ */
+ if ((sock = socket(af, SOCK_DGRAM, 0)) < 0) {
+#ifdef HAS_IPV6
+ if (af == AF_INET6) {
+ if (msg_verbose)
+ msg_warn("%s: socket: %m", myname);
+ return (-1);
+ }
+#endif
+ msg_fatal("%s: socket: %m", myname);
+ }
+ return (sock);
+}
+
+#ifdef HAVE_GETIFADDRS
+
+/*
+ * The getifaddrs(3) function, introduced by BSD/OS, provides a
+ * platform-independent way of requesting interface addresses,
+ * including IPv6 addresses. The implementation however is not
+ * present in all major operating systems.
+ */
+
+/* ial_getifaddrs - determine IP addresses using getifaddrs(3) */
+
+static int ial_getifaddrs(INET_ADDR_LIST *addr_list,
+ INET_ADDR_LIST *mask_list,
+ int af)
+{
+ char *myname = "inet_addr_local[getifaddrs]";
+ struct ifaddrs *ifap, *ifa;
+ struct sockaddr *sa, *sam;
+
+ if (getifaddrs(&ifap) < 0)
+ msg_fatal("%s: getifaddrs: %m", myname);
+
+ /*
+ * Get the address of each IP network interface. According to BIND we
+ * must include interfaces that are down because the machine may still
+ * receive packets for that address (yes, via some other interface).
+ * Having no way to verify this claim on every machine, I will give them
+ * the benefit of the doubt.
+ *
+ * FIX 200501: The IPv6 patch did not report NetBSD loopback interfaces;
+ * fixed by replacing IFF_RUNNING by IFF_UP.
+ *
+ * FIX 200501: The IPV6 patch did not skip wild-card interface addresses
+ * (tested on FreeBSD).
+ */
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_addr == 0)
+ continue;
+ sa = ifa->ifa_addr;
+ sam = ifa->ifa_netmask;
+ if (af != AF_UNSPEC && sa->sa_family != af)
+ continue;
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY)
+ continue;
+ break;
+#ifdef HAS_IPV6
+ case AF_INET6:
+ if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))
+ continue;
+ break;
+#endif
+ default:
+ continue;
+ }
+
+ inet_addr_list_append(addr_list, sa);
+ if (mask_list != 0) {
+
+ /*
+ * Unfortunately, sa_len/sa_family may be broken in the netmask
+ * sockaddr structure. We must fix this manually to have correct
+ * addresses. --dcs
+ */
#ifdef HAS_SA_LEN
-#define NEXT_INTERFACE(ifr) ((struct ifreq *) \
+ sam->sa_len = sa->sa_family == AF_INET6 ?
+ sizeof(struct sockaddr_in6) :
+ sizeof(struct sockaddr_in);
+#endif
+ sam->sa_family = sa->sa_family;
+ inet_addr_list_append(mask_list, sam);
+ }
+ }
+ freeifaddrs(ifap);
+ return (0);
+}
+
+#endif /* HAVE_GETIFADDRS */
+
+#ifdef HAS_SIOCGLIF
+
+/*
+ * The SIOCLIF* ioctls are the successors of SIOCGIF* on the Solaris
+ * and HP/UX operating systems. The data is stored in sockaddr_storage
+ * structure. Both IPv4 and IPv6 addresses are returned though these
+ * calls.
+ */
+#define NEXT_INTERFACE(lifr) (lifr + 1)
+#define LIFREQ_SIZE(lifr) sizeof(lifr[0])
+
+/* ial_siocglif - determine IP addresses using ioctl(SIOCGLIF*) */
+
+static int ial_siocglif(INET_ADDR_LIST *addr_list,
+ INET_ADDR_LIST *mask_list,
+ int af)
+{
+ char *myname = "inet_addr_local[siocglif]";
+ struct lifconf lifc;
+ struct lifreq *lifr;
+ struct lifreq *lifr_mask;
+ struct lifreq *the_end;
+ struct sockaddr *sa;
+ int sock;
+ VSTRING *buf;
+
+ /*
+ * See also comments in ial_siocgif()
+ */
+ if (af != AF_INET && af != AF_INET6)
+ msg_fatal("%s: address family was %d, must be AF_INET (%d) or "
+ "AF_INET6 (%d)", myname, af, AF_INET, AF_INET6);
+ sock = ial_socket(af);
+ if (sock < 0)
+ return (0);
+ buf = vstring_alloc(1024);
+ for (;;) {
+ memset(&lifc, 0, sizeof(lifc));
+ lifc.lifc_family = AF_UNSPEC; /* XXX Why??? */
+ lifc.lifc_len = vstring_avail(buf);
+ lifc.lifc_buf = vstring_str(buf);
+ if (ioctl(sock, SIOCGLIFCONF, (char *) &lifc) < 0) {
+ if (errno != EINVAL)
+ msg_fatal("%s: ioctl SIOCGLIFCONF: %m", myname);
+ } else if (lifc.lifc_len < vstring_avail(buf) / 2)
+ break;
+ VSTRING_SPACE(buf, vstring_avail(buf) * 2);
+ }
+
+ the_end = (struct lifreq *) (lifc.lifc_buf + lifc.lifc_len);
+ for (lifr = lifc.lifc_req; lifr < the_end;) {
+ sa = (struct sockaddr *) & lifr->lifr_addr;
+ if (sa->sa_family != af) {
+ lifr = NEXT_INTERFACE(lifr);
+ continue;
+ }
+ if (af == AF_INET) {
+ if (SOCK_ADDR_IN_ADDR(sa).s_addr == INADDR_ANY) {
+ lifr = NEXT_INTERFACE(lifr);
+ continue;
+ }
+#ifdef HAS_IPV6
+ } else if (af == AF_INET6) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa))) {
+ lifr = NEXT_INTERFACE(lifr);
+ continue;
+ }
+ }
+#endif
+ inet_addr_list_append(addr_list, sa);
+ if (mask_list) {
+ lifr_mask = (struct lifreq *) mymalloc(sizeof(struct lifreq));
+ memcpy((char *) lifr_mask, (char *) lifr, sizeof(struct lifreq));
+ if (ioctl(sock, SIOCGLIFNETMASK, lifr_mask) < 0)
+ msg_fatal("%s: ioctl(SIOCGLIFNETMASK): %m", myname);
+ /* XXX: Check whether sa_len/family are honoured --dcs */
+ inet_addr_list_append(mask_list,
+ (struct sockaddr *) & lifr_mask->lifr_addr);
+ myfree((char *) lifr_mask);
+ }
+ lifr = NEXT_INTERFACE(lifr);
+ }
+ vstring_free(buf);
+ (void) close(sock);
+ return (0);
+}
+
+#else /* HAVE_SIOCGLIF */
+
+/*
+ * The classic SIOCGIF* ioctls. Modern BSD operating systems will
+ * also return IPv6 addresses through these structure. Note however
+ * that recent versions of these operating systems have getifaddrs.
+ */
+#if defined(_SIZEOF_ADDR_IFREQ)
+# define NEXT_INTERFACE(ifr) ((struct ifreq *) \
+ ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)))
+# define IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr)
+#elif defined(HAS_SA_LEN)
+# define NEXT_INTERFACE(ifr) ((struct ifreq *) \
((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len))
-#define IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
+# define IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
#else
-#define NEXT_INTERFACE(ifr) (ifr + 1)
-#define IFREQ_SIZE(ifr) sizeof(ifr[0])
-#endif
+# define NEXT_INTERFACE(ifr) (ifr + 1)
+# define IFREQ_SIZE(ifr) sizeof(ifr[0])
#endif
-/* inet_addr_local - find all IP addresses for this host */
+/* ial_siocgif - determine IP addresses using ioctl(SIOCGIF*) */
-int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list)
+static int ial_siocgif(INET_ADDR_LIST *addr_list,
+ INET_ADDR_LIST *mask_list,
+ int af)
{
- char *myname = "inet_addr_local";
+ char *myname = "inet_addr_local[siocgif]";
+ struct in_addr addr;
struct ifconf ifc;
struct ifreq *ifr;
+ struct ifreq *ifr_mask;
struct ifreq *the_end;
int sock;
- VSTRING *buf = vstring_alloc(1024);
- int initial_count = addr_list->used;
- struct in_addr addr;
- struct ifreq *ifr_mask;
-
- if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
- msg_fatal("%s: socket: %m", myname);
+ VSTRING *buf;
/*
* Get the network interface list. XXX The socket API appears to have no
* that the program can run out of memory due to a non-memory problem,
* making it more difficult than necessary to diagnose the real problem.
*/
+ sock = ial_socket(af);
+ if (sock < 0)
+ return (0);
+ buf = vstring_alloc(1024);
for (;;) {
ifc.ifc_len = vstring_avail(buf);
ifc.ifc_buf = vstring_str(buf);
VSTRING_SPACE(buf, vstring_avail(buf) * 2);
}
- /*
- * Get the address of each IP network interface. According to BIND we
- * must include interfaces that are down because the machine may still
- * receive packets for that address (yes, via some other interface).
- * Having no way to verify this claim on every machine, I will give them
- * the benefit of the doubt.
- */
the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
for (ifr = ifc.ifc_req; ifr < the_end;) {
- if (ifr->ifr_addr.sa_family == AF_INET) { /* IP interface */
+ if (ifr->ifr_addr.sa_family != af) {
+ ifr = NEXT_INTERFACE(ifr);
+ continue;
+ }
+ if (af == AF_INET) {
addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
- if (addr.s_addr != INADDR_ANY) { /* has IP address */
- inet_addr_list_append(addr_list, &addr);
+ if (addr.s_addr != INADDR_ANY) {
+ inet_addr_list_append(addr_list, &ifr->ifr_addr);
if (mask_list) {
ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr));
memcpy((char *) ifr_mask, (char *) ifr, IFREQ_SIZE(ifr));
if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0)
msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);
- addr = ((struct sockaddr_in *) & ifr_mask->ifr_addr)->sin_addr;
- inet_addr_list_append(mask_list, &addr);
+
+ /*
+ * Note that this SIOCGIFNETMASK has truly screwed up the
+ * contents of sa_len/sa_family. We must fix this
+ * manually to have correct addresses. --dcs
+ */
+ ifr_mask->ifr_addr.sa_family = af;
+#ifdef HAS_SA_LEN
+ ifr_mask->ifr_addr.sa_len = sizeof(struct sockaddr_in);
+#endif
+ inet_addr_list_append(mask_list, &ifr_mask->ifr_addr);
myfree((char *) ifr_mask);
}
}
}
+#ifdef HAS_IPV6
+ else if (af == AF_INET6) {
+ struct sockaddr *sa;
+
+ sa = SOCK_ADDR_PTR(&ifr->ifr_addr);
+ if (!(IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))) {
+ inet_addr_list_append(addr_list, sa);
+ if (mask_list) {
+ /* XXX Assume /128 for everything */
+ struct sockaddr_in6 mask6;
+
+ mask6 = *SOCK_ADDR_IN6_PTR(sa);
+ memset((char *) &mask6.sin6_addr, ~0,
+ sizeof(mask6.sin6_addr));
+ inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask6));
+ }
+ }
+ }
+#endif
ifr = NEXT_INTERFACE(ifr);
}
vstring_free(buf);
(void) close(sock);
+ return (0);
+}
+
+#endif /* HAVE_SIOCGLIF */
+
+#ifdef HAS_PROCNET_IFINET6
+
+/*
+ * Linux does not provide proper calls to retrieve IPv6 interface
+ * addresses. Instead, the addresses can be read from a file in the
+ * /proc tree. The most important issue with this approach however
+ * is that the /proc tree may not always be available, for example
+ * in a chrooted environment or in "hardened" (sic) installations.
+ */
+
+/* ial_procnet_ifinet6 - determine IPv6 addresses using /proc/net/if_inet6 */
+
+static int ial_procnet_ifinet6(INET_ADDR_LIST *addr_list,
+ INET_ADDR_LIST *mask_list)
+{
+ char *myname = "inet_addr_local[procnet_ifinet6]";
+ FILE *fp;
+ char buf[BUFSIZ];
+ unsigned plen;
+ VSTRING *addrbuf;
+ struct sockaddr_in6 addr;
+ struct sockaddr_in6 mask;
+
+ /*
+ * Example: 00000000000000000000000000000001 01 80 10 80 lo
+ *
+ * Fields: address, interface index, prefix length, scope value
+ * (net/ipv6.h), interface flags (linux/rtnetlink.h), device name.
+ *
+ * FIX 200501 The IPv6 patch used fscanf(), which will hang on unexpected
+ * input. Use fgets() + sscanf() instead.
+ */
+ if ((fp = fopen(_PATH_PROCNET_IFINET6, "r")) != 0) {
+ addrbuf = vstring_alloc(MAI_V6ADDR_BYTES + 1);
+ memset((char *) &addr, 0, sizeof(addr));
+ addr.sin6_family = AF_INET6;
+#ifdef HAS_SA_LEN
+ addr.sin6_len = sizeof(addr);
+#endif
+ mask = addr;
+ while (fgets(buf, sizeof(buf), fp) != 0) {
+ /* 200501 hex_decode() is light-weight compared to getaddrinfo(). */
+ if (hex_decode(addrbuf, buf, MAI_V6ADDR_BYTES * 2) == 0
+ || sscanf(buf + MAI_V6ADDR_BYTES * 2, " %*x %x", &plen) != 1
+ || plen > MAI_V6ADDR_BITS) {
+ msg_warn("unexpected data in %s - skipping IPv6 configuration",
+ _PATH_PROCNET_IFINET6);
+ break;
+ }
+ /* vstring_str(addrbuf) has worst-case alignment. */
+ addr.sin6_addr = *(struct in6_addr *) vstring_str(addrbuf);
+ inet_addr_list_append(addr_list, SOCK_ADDR_PTR(&addr));
+
+ memset((char *) &mask.sin6_addr, ~0, sizeof(mask.sin6_addr));
+ mask_addr((char *) &mask.sin6_addr, sizeof(mask.sin6_addr), plen);
+ inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask));
+ }
+ vstring_free(addrbuf);
+ fclose(fp); /* FIX 200501 */
+ } else {
+ msg_warn("can't open %s (%m) - skipping IPv6 configuration",
+ _PATH_PROCNET_IFINET6);
+ }
+ return (0);
+}
+
+#endif /* HAS_PROCNET_IFINET6 */
+
+/* inet_addr_local - find all IP addresses for this host */
+
+int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list,
+ unsigned *addr_family_list)
+{
+ char *myname = "inet_addr_local";
+ int initial_count = addr_list->used;
+ unsigned family;
+ int count;
+
+ while ((family = *addr_family_list++) != 0) {
+
+ /*
+ * IP Version 4
+ */
+ if (family == AF_INET) {
+ count = addr_list->used;
+#if defined(HAVE_GETIFADDRS)
+ ial_getifaddrs(addr_list, mask_list, AF_INET);
+#elif defined (HAS_SIOCGLIF)
+ ial_siocglif(addr_list, mask_list, AF_INET);
+#else
+ ial_siocgif(addr_list, mask_list, AF_INET);
+#endif
+ if (msg_verbose)
+ msg_info("%s: configured %d IPv4 addresses",
+ myname, addr_list->used - count);
+ }
+
+ /*
+ * IP Version 6
+ */
+#ifdef HAS_IPV6
+ else if (family == AF_INET6) {
+ count = addr_list->used;
+#if defined(HAVE_GETIFADDRS)
+ ial_getifaddrs(addr_list, mask_list, AF_INET6);
+#elif defined(HAS_PROCNET_IFINET6)
+ ial_procnet_ifinet6(addr_list, mask_list);
+#elif defined(HAS_SIOCGLIF)
+ ial_siocglif(addr_list, mask_list, AF_INET6);
+#else
+ ial_siocgif(addr_list, mask_list, AF_INET6);
+#endif
+ if (msg_verbose)
+ msg_info("%s: configured %d IPv6 addresses", myname,
+ addr_list->used - count);
+ }
+#endif
+
+ /*
+ * Something's not right.
+ */
+ else
+ msg_panic("%s: unknown address family %d", myname, family);
+ }
return (addr_list->used - initial_count);
}
#ifdef TEST
+#include <string.h>
#include <vstream.h>
#include <msg_vstream.h>
+#include <inet_proto.h>
int main(int unused_argc, char **argv)
{
INET_ADDR_LIST addr_list;
INET_ADDR_LIST mask_list;
+ MAI_HOSTADDR_STR hostaddr;
+ MAI_HOSTADDR_STR hostmask;
+ struct sockaddr *sa;
int i;
+ INET_PROTO_INFO *proto_info;
msg_vstream_init(argv[0], VSTREAM_ERR);
+ msg_verbose = 1;
+ proto_info = inet_proto_init(argv[0], INET_PROTO_NAME_ALL);
inet_addr_list_init(&addr_list);
inet_addr_list_init(&mask_list);
- inet_addr_local(&addr_list, &mask_list);
+ inet_addr_local(&addr_list, &mask_list, proto_info->ai_family_list);
if (addr_list.used == 0)
msg_fatal("cannot find any active network interfaces");
msg_warn("found only one active network interface");
for (i = 0; i < addr_list.used; i++) {
- vstream_printf("%s/", inet_ntoa(addr_list.addrs[i]));
- vstream_printf("%s\n", inet_ntoa(mask_list.addrs[i]));
+ sa = SOCK_ADDR_PTR(addr_list.addrs + i);
+ SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ sa = SOCK_ADDR_PTR(mask_list.addrs + i);
+ SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
+ &hostmask, (MAI_SERVPORT_STR *) 0, 0);
+ vstream_printf("%s/%s\n", hostaddr.buf, hostmask.buf);
+ vstream_fflush(VSTREAM_OUT);
}
- vstream_fflush(VSTREAM_OUT);
inet_addr_list_free(&addr_list);
inet_addr_list_free(&mask_list);
}
/*
* External interface.
*/
-extern int inet_addr_local(INET_ADDR_LIST *, INET_ADDR_LIST *);
+extern int inet_addr_local(INET_ADDR_LIST *, INET_ADDR_LIST *, unsigned *);
/* LICENSE
/* .ad
/* NAME
/* inet_connect 3
/* SUMMARY
-/* connect to INET-domain listener
+/* connect to TCP listener
/* SYNOPSIS
/* #include <connect.h>
/*
/* int block_mode;
/* int timeout;
/* DESCRIPTION
-/* inet_connect connects to a listener in the AF_INET domain at
+/* inet_connect connects to a TCP listener at
/* the specified address, and returns the resulting file descriptor.
/*
/* Arguments:
/* a value <= 0 to disable the time limit.
/* DIAGNOSTICS
/* The result is -1 when the connection could not be made.
-/* Th nature of the error is available via the global \fIerrno\fR
+/* The nature of the error is available via the global \fIerrno\fR
/* variable.
/* Fatal errors: other system call failures.
-/* BUGS
-/* This routine uses find_inet_addr() which ignores all but the
-/* first address listed for the named host.
-/* SEE ALSO
-/* find_inet(3), simple inet name service interface
/* LICENSE
/* .ad
/* .fi
#include <string.h>
#include <unistd.h>
#include <errno.h>
+#include <netdb.h>
/* Utility library. */
#include "mymalloc.h"
#include "msg.h"
-#include "find_inet.h"
-#include "inet_util.h"
#include "iostuff.h"
+#include "host_port.h"
#include "sane_connect.h"
#include "connect.h"
#include "timed_connect.h"
+#include "myaddrinfo.h"
+#include "sock_addr.h"
+#include "inet_proto.h"
-/* inet_connect - connect to AF_INET-domain listener */
+static int inet_connect_one(struct addrinfo *, int, int);
+
+/* inet_connect - connect to TCP listener */
int inet_connect(const char *addr, int block_mode, int timeout)
{
char *buf;
char *host;
char *port;
- struct sockaddr_in sin;
+ const char *parse_err;
+ struct addrinfo *res;
+ struct addrinfo *res0;
+ int aierr;
int sock;
+ MAI_HOSTADDR_STR hostaddr;
+ INET_PROTO_INFO *proto_info;
+ int found;
/*
* Translate address information to internal form. No host defaults to
* the local host.
*/
- buf = inet_parse(addr, &host, &port);
- if (*host == 0)
- host = "localhost";
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = find_inet_addr(host);
- sin.sin_port = find_inet_port(port, "tcp");
+ buf = mystrdup(addr);
+ if ((parse_err = host_port(buf, &host, "localhost", &port, (char *) 0)) != 0)
+ msg_fatal("%s: %s", addr, parse_err);
+ if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res0)) != 0)
+ msg_fatal("host/service %s/%s not found: %s",
+ host, port, MAI_STRERROR(aierr));
myfree(buf);
+ proto_info = inet_proto_info();
+ for (sock = -1, found = 0, res = res0; res != 0; res = res->ai_next) {
+
+ /*
+ * Safety net.
+ */
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for host %s",
+ res->ai_family, host);
+ continue;
+ }
+ found++;
+
+ /*
+ * In case of multiple addresses, show what address we're trying now.
+ */
+ if (msg_verbose) {
+ SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
+ &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
+ msg_info("trying... [%s]", hostaddr.buf);
+ }
+ if ((sock = inet_connect_one(res, block_mode, timeout)) < 0) {
+ if (msg_verbose)
+ msg_info("%m");
+ } else
+ break;
+ }
+ if (found == 0)
+ msg_fatal("host not found: %s", addr);
+ freeaddrinfo(res0);
+ return (sock);
+}
+
+/* inet_connect_one - try to connect to one address */
+
+static int inet_connect_one(struct addrinfo * res, int block_mode, int timeout)
+{
+ int sock;
+
/*
* Create a client socket.
*/
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- msg_fatal("socket: %m");
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (sock < 0)
+ return (-1);
/*
* Timed connect.
*/
if (timeout > 0) {
non_blocking(sock, NON_BLOCKING);
- if (timed_connect(sock, (struct sockaddr *) & sin, sizeof(sin), timeout) < 0) {
+ if (timed_connect(sock, res->ai_addr, res->ai_addrlen, timeout) < 0) {
close(sock);
return (-1);
}
*/
else {
non_blocking(sock, block_mode);
- if (sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0
+ if (sane_connect(sock, res->ai_addr, res->ai_addrlen) < 0
&& errno != EINPROGRESS) {
close(sock);
return (-1);
/* NAME
/* inet_listen 3
/* SUMMARY
-/* start INET-domain listener
+/* start TCP listener
/* SYNOPSIS
/* #include <listen.h>
/*
/* int inet_accept(fd)
/* int fd;
/* DESCRIPTION
-/* The \fBinet_listen\fR routine starts a listener in the INET domain
+/* The \fBinet_listen\fR routine starts a TCP listener
/* on the specified address, with the specified backlog, and returns
/* the resulting file descriptor.
/*
#ifndef MAXHOSTNAMELEN
#include <sys/param.h>
#endif
+#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "mymalloc.h"
#include "msg.h"
-#include "find_inet.h"
-#include "inet_util.h"
+#include "host_port.h"
#include "iostuff.h"
#include "listen.h"
#include "sane_accept.h"
+#include "myaddrinfo.h"
+#include "sock_addr.h"
+#include "inet_proto.h"
-/* Application-specific stuff. */
-
-#ifndef INADDR_ANY
-#define INADDR_ANY 0xffffffff
-#endif
-
-/* inet_listen - create inet-domain listener */
+/* inet_listen - create TCP listener */
int inet_listen(const char *addr, int backlog, int block_mode)
{
- struct sockaddr_in sin;
+ struct addrinfo *res;
+ struct addrinfo *res0;
+ int aierr;
int sock;
- int t = 1;
+ int on = 1;
char *buf;
char *host;
char *port;
+ const char *parse_err;
+ MAI_HOSTADDR_STR hostaddr;
+ MAI_SERVPORT_STR portnum;
+ INET_PROTO_INFO *proto_info;
+ int found;
/*
* Translate address information to internal form.
*/
- buf = inet_parse(addr, &host, &port);
- memset((char *) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = find_inet_port(port, "tcp");
- sin.sin_addr.s_addr = (*host ? find_inet_addr(host) : INADDR_ANY);
+ buf = mystrdup(addr);
+ if ((parse_err = host_port(buf, &host, "", &port, (char *) 0)) != 0)
+ msg_fatal("%s: %s", addr, parse_err);
+ if (*host == 0)
+ host = 0;
+ if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res0)) != 0)
+ msg_fatal("%s: %s", addr, MAI_STRERROR(aierr));
myfree(buf);
+ /* No early returns or res0 leaks. */
- /*
- * Create a listener socket.
- */
- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- msg_fatal("socket: %m");
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0)
- msg_fatal("setsockopt: %m");
- if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
- msg_fatal("bind %s port %d: %m", sin.sin_addr.s_addr == INADDR_ANY ?
- "INADDR_ANY" : inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+ proto_info = inet_proto_info();
+ for (found = 0, res = res0; res != 0; res = res->ai_next) {
+
+ /*
+ * Safety net.
+ */
+ if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
+ msg_info("skipping address family %d for %s",
+ res->ai_family, addr);
+ continue;
+ }
+ found++;
+
+ /*
+ * Show what address we're trying.
+ */
+ if (msg_verbose) {
+ SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
+ &hostaddr, &portnum, 0);
+ msg_info("trying... [%s]:%s", hostaddr.buf, portnum.buf);
+ }
+
+ /*
+ * Create a listener socket.
+ */
+ if ((sock = socket(res->ai_family, res->ai_socktype, 0)) < 0)
+ msg_fatal("socket: %m");
+#ifdef HAS_IPV6
+# if defined(IPV6_V6ONLY) && !defined(BROKEN_AI_PASSIVE_NULL_HOST)
+ if (res->ai_family == AF_INET6
+ && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *) &on, sizeof(on)) < 0)
+ msg_fatal("setsockopt(IPV6_V6ONLY): %m");
+# endif
+#endif
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &on, sizeof(on)) < 0)
+ msg_fatal("setsockopt(SO_REUSEADDR): %m");
+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
+ &hostaddr, &portnum, 0);
+ msg_fatal("bind %s port %s: %m", hostaddr.buf, portnum.buf);
+ }
+ break;
+ }
+ freeaddrinfo(res0);
+ if (found == 0)
+ msg_fatal("%s: host not found", addr);
non_blocking(sock, block_mode);
if (listen(sock, backlog) < 0)
msg_fatal("listen: %m");
--- /dev/null
+/*++
+/* NAME
+/* inet_proto 3
+/* SUMMARY
+/* convert protocol names to assorted constants
+/* SYNOPSIS
+/* #include <inet_proto.h>
+/*
+/* typedef struct {
+/* .in +4
+/* unsigned ai_family; /* PF_UNSPEC, PF_INET, or PF_INET6 */
+/* unsigned *ai_family_list; /* PF_INET and/or PF_INET6 */
+/* unsigned *dns_atype_list;/* TAAAA and/or TA */
+/* unsigned char *sa_family_list;/* AF_INET6 and/or AF_INET */
+/* .in -4
+/* } INET_PROTO_INFO;
+/*
+/* INET_PROTO_INFO *inet_proto_init(context, protocols)
+/*
+/* INET_PROTO_INFO *inet_proto_info()
+/* DESCRIPTION
+/* inet_proto_init() converts a string with protocol names
+/* into null-terminated lists of appropriate constants used
+/* by Postfix library routines. The idea is that one should
+/* be able to configure an MTA for IPv4 only, without having
+/* to recompile code (what a concept).
+/*
+/* Unfortunately, some compilers won't link initialized data
+/* without a function call into the same source module, so
+/* we invoke inet_proto_info() in order to access the result
+/* from inet_proto_init() from within library routines.
+/* inet_proto_info() also conveniently initializes the data
+/* to built-in defaults.
+/*
+/* Arguments:
+/* .IP context
+/* Typically, a configuration parameter name.
+/* .IP protocols
+/* Null-terminated string with protocol names separated by
+/* whitespace and/or commas:
+/* .RS
+/* .IP INET_PROTO_NAME_ALL
+/* Enable all available IP protocols.
+/* .IP INET_PROTO_NAME_IPV4
+/* Enable IP version 4 support.
+/* .IP INET_PROTO_NAME_IPV6
+/* Enable IP version 6 support.
+/* .RS
+/* .PP
+/* Results:
+/* .IP ai_family
+/* Only one of PF_UNSPEC, PF_INET, or PF_INET6. This can be
+/* used as input for the getaddrinfo() and getnameinfo()
+/* routines.
+/* .IP ai_family_list
+/* One or more of PF_INET or PF_INET6. This can be used as
+/* input for the inet_addr_local() routine.
+/* .IP dns_atype_list
+/* One or more of T_AAAA or TA. This can be used as input for
+/* the dns_lookup_v() and dns_lookup_l() routines.
+/* .IP sa_family_list
+/* One or more of AF_INET6 or AF_INET. This can be used as an
+/* output filter for the results from the getaddrinfo() and
+/* getnameinfo() routines.
+/* SEE ALSO
+/* msg(3) diagnostics interface
+/* DIAGNOSTICS
+/* This module will report if IPv6 is unavailable, and will
+/* disable IPv6 support in Postfix. When IPv6 is the only
+/* selected protocol, this is a fatal error.
+/*
+/* Fatal errors: memory allocation problem.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#ifdef RESOLVE_H_NEEDS_STDIO_H
+#include <stdio.h>
+#endif
+#include <resolv.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <name_mask.h>
+#include <inet_proto.h>
+
+ /*
+ * Application-specific.
+ */
+
+ /*
+ * Run-time initialization, so we can work around LINUX where IPv6 falls
+ * flat on its face because it is not turned on in the kernel.
+ */
+INET_PROTO_INFO *inet_proto_table = 0;
+
+ /*
+ * Infrastructure: lookup table with the protocol names that we support.
+ */
+#define INET_PROTO_MASK_IPV4 (1<<0)
+#define INET_PROTO_MASK_IPV6 (1<<1)
+
+static NAME_MASK proto_table[] = {
+#ifdef HAS_IPV6
+ INET_PROTO_NAME_ALL, INET_PROTO_MASK_IPV4 | INET_PROTO_MASK_IPV6,
+ INET_PROTO_NAME_IPV6, INET_PROTO_MASK_IPV6,
+#else
+ INET_PROTO_NAME_ALL, INET_PROTO_MASK_IPV4,
+#endif
+ INET_PROTO_NAME_IPV4, INET_PROTO_MASK_IPV4,
+ 0,
+};
+
+/* make_uchar_vector - create and initialize uchar vector */
+
+static unsigned char *make_uchar_vector(int len,...)
+{
+ const char *myname = "make_uchar_vector";
+ va_list ap;
+ int count;
+ unsigned char *vp;
+
+ va_start(ap, len);
+ if (len <= 0)
+ msg_panic("%s: bad vector length: %d", myname, len);
+ vp = (unsigned char *) mymalloc(sizeof(*vp) * len);
+ for (count = 0; count < len; count++)
+ vp[count] = va_arg(ap, unsigned);
+ va_end(ap);
+ return (vp);
+}
+
+/* make_unsigned_vector - create and initialize integer vector */
+
+static unsigned *make_unsigned_vector(int len,...)
+{
+ const char *myname = "make_unsigned_vector";
+ va_list ap;
+ int count;
+ unsigned *vp;
+
+ va_start(ap, len);
+ if (len <= 0)
+ msg_panic("%s: bad vector length: %d", myname, len);
+ vp = (unsigned *) mymalloc(sizeof(*vp) * len);
+ for (count = 0; count < len; count++)
+ vp[count] = va_arg(ap, unsigned);
+ va_end(ap);
+ return (vp);
+}
+
+/* inet_proto_free - destroy data */
+
+static void inet_proto_free(INET_PROTO_INFO *pf)
+{
+ myfree((char *) pf->ai_family_list);
+ myfree((char *) pf->dns_atype_list);
+ myfree((char *) pf->sa_family_list);
+ myfree((char *) pf);
+}
+
+/* inet_proto_init - convert protocol names to library inputs */
+
+INET_PROTO_INFO *inet_proto_init(const char *context, const char *protocols)
+{
+ const char *myname = "inet_proto";
+ INET_PROTO_INFO *pf;
+ int inet_proto_mask;
+ int sock;
+
+ /*
+ * Store addess family etc. info as null-terminated vectors. If that
+ * breaks because we must be able to store nulls, we'll deal with the
+ * additional complexity.
+ *
+ * XXX Use compile-time initialized data templates instead of building the
+ * reply on the fly.
+ */
+ inet_proto_mask = name_mask(context, proto_table, protocols);
+ switch (inet_proto_mask) {
+#ifdef HAS_IPV6
+ case INET_PROTO_MASK_IPV6:
+ if ((sock = socket(PF_INET6, SOCK_STREAM, 0)) >= 0) {
+ close(sock);
+ pf = (INET_PROTO_INFO *) mymalloc(sizeof(*pf));
+ pf->ai_family = PF_INET6;
+ pf->ai_family_list = make_unsigned_vector(2, PF_INET6, 0);
+ pf->dns_atype_list = make_unsigned_vector(2, T_AAAA, 0);
+ pf->sa_family_list = make_uchar_vector(2, AF_INET6, 0);
+ break;
+ } else if (errno == EAFNOSUPPORT) {
+ msg_fatal("%s: IPv6 support is disabled: %m", context);
+ } else {
+ msg_fatal("socket: %m");
+ }
+ case (INET_PROTO_MASK_IPV6 | INET_PROTO_MASK_IPV4):
+ if ((sock = socket(PF_INET6, SOCK_STREAM, 0)) >= 0) {
+ close(sock);
+ pf = (INET_PROTO_INFO *) mymalloc(sizeof(*pf));
+ pf->ai_family = PF_UNSPEC;
+ pf->ai_family_list = make_unsigned_vector(3, PF_INET, PF_INET6, 0);
+ pf->dns_atype_list = make_unsigned_vector(3, T_A, T_AAAA, 0);
+ pf->sa_family_list = make_uchar_vector(3, AF_INET, AF_INET6, 0);
+ break;
+ } else if (errno == EAFNOSUPPORT) {
+ msg_warn("%s: IPv6 support is disabled: %m", context);
+ msg_warn("%s: configuring for IPv4 support only", context);
+ /* FALLTHROUGH */
+ } else {
+ msg_fatal("socket: %m");
+ }
+#endif
+ case INET_PROTO_MASK_IPV4:
+ pf = (INET_PROTO_INFO *) mymalloc(sizeof(*pf));
+ pf->ai_family = PF_INET;
+ pf->ai_family_list = make_unsigned_vector(2, PF_INET, 0);
+ pf->dns_atype_list = make_unsigned_vector(2, T_A, 0);
+ pf->sa_family_list = make_uchar_vector(2, AF_INET, 0);
+ break;
+ default:
+ msg_panic("%s: bad inet_proto_mask 0x%x", myname, inet_proto_mask);
+ }
+ if (inet_proto_table)
+ inet_proto_free(inet_proto_table);
+ return (inet_proto_table = pf);
+}
+
+#ifdef TEST
+
+ /*
+ * Small driver for unit tests.
+ */
+int main(int argc, char **argv)
+{
+ char *myname = argv[0];
+ INET_PROTO_INFO *pf;
+
+ if (argc < 2)
+ msg_fatal("usage: %s protocol(s)...", myname);
+
+ while (*++argv) {
+ msg_info("=== %s ===", *argv);
+ if (**argv)
+ inet_proto_init(myname, *argv);
+ pf = inet_proto_table;
+ msg_info("ai_family = %u", pf->ai_family);
+ msg_info("ai_family_list = %u %u...",
+ pf->ai_family_list[0], pf->ai_family_list[1]);
+ msg_info("dns_atype_list = %u %u...",
+ pf->dns_atype_list[0], pf->dns_atype_list[1]);
+ msg_info("sa_family_list = %u %u...",
+ pf->sa_family_list[0], pf->sa_family_list[1]);
+ }
+ return (0);
+}
+
+#endif
--- /dev/null
+#ifndef _INET_PROTO_INFO_H_INCLUDED_
+#define _INET_PROTO_INFO_H_INCLUDED_
+
+/*++
+/* NAME
+/* inet_proto_info 3h
+/* SUMMARY
+/* convert protocol names to assorted constants
+/* SYNOPSIS
+/* #include <inet_proto_info.h>
+ DESCRIPTION
+ .nf
+
+ /*
+ * External interface.
+ */
+typedef struct {
+ unsigned int ai_family; /* PF_UNSPEC, PF_INET, or PF_INET6 */
+ unsigned int *ai_family_list; /* PF_INET and/or PF_INET6 */
+ unsigned int *dns_atype_list; /* TAAAA and/or TA */
+ unsigned char *sa_family_list; /* AF_INET6 and/or AF_INET */
+} INET_PROTO_INFO;
+
+ /*
+ * Some compilers won't link initialized data unless we call a function in
+ * the same source file. Therefore, inet_proto_info() is a function instead
+ * of a global variable.
+ */
+#define inet_proto_info() \
+ (inet_proto_table ? inet_proto_table : \
+ inet_proto_init("default protocol setting", DEF_INET_PROTOCOLS))
+
+extern INET_PROTO_INFO *inet_proto_init(const char *, const char *);
+extern INET_PROTO_INFO *inet_proto_table;
+
+#define INET_PROTO_NAME_IPV6 "ipv6"
+#define INET_PROTO_NAME_IPV4 "ipv4"
+#define INET_PROTO_NAME_ALL "all"
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
+++ /dev/null
-/*++
-/* NAME
-/* inet_util 3
-/* SUMMARY
-/* INET-domain utilities
-/* SYNOPSIS
-/* #include <inet_util.h>
-/*
-/* char *inet_parse(addr, hostp, portp)
-/* const char *addr;
-/* char **hostp;
-/* char **portp;
-/* DESCRIPTION
-/* This module implements various support routines for
-/* dealing with AF_INET connections, addresses etc.
-/*
-/* inet_parse() takes an address of the form host:port and
-/* breaks it up into its constituent parts. The resulting
-/* host information is an empty string when the address
-/* contains no host part or no host: part. inet_parse()
-/* returns a pointer to memory that it has allocated for
-/* string storage. The caller should pass the host to the
-/* myfree() function when the storage is no longer needed.
-/* DIAGNOSTICS
-/* Fatal errors: invalid address or host forms.
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-/* System libraries. */
-
-#include <sys_defs.h>
-
-/* Utility library. */
-
-#include "mymalloc.h"
-#include "split_at.h"
-#include "inet_util.h"
-
-/* inet_parse - parse host:port address spec */
-
-char *inet_parse(const char *addr, char **hostp, char **portp)
-{
- char *buf;
-
- buf = mystrdup(addr);
- if ((*portp = split_at_right(buf, ':')) != 0) {
- *hostp = buf;
- } else {
- *portp = buf;
- *hostp = "";
- }
- return (buf);
-}
/* mac_parse_print - print parse tree */
-static void mac_parse_print(int type, VSTRING *buf, char *unused_context)
+static int mac_parse_print(int type, VSTRING *buf, char *unused_context)
{
char *type_name;
msg_panic("unknown token type %d", type);
}
vstream_printf("%s \"%s\"\n", type_name, vstring_str(buf));
+ return (0);
}
int main(int unused_argc, char **unused_argv)
#include <stdlib.h>
#include <msg_vstream.h>
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
msg_vstream_init(argv[0], VSTREAM_ERR);
if (argc < 2)
--- /dev/null
+/*++
+/* NAME
+/* mask_addr 3
+/* SUMMARY
+/* address bit banging
+/* SYNOPSIS
+/* #include <mask_addr.h>
+/*
+/* void mask_addr(addr_bytes, addr_byte_count, network_bits)
+/* unsigned char *addr_bytes;
+/* unsigned addr_byte_count;
+/* unsigned network_bits;
+/* DESCRIPTION
+/* mask_addr() clears all the host bits in the specified
+/* address. The code can handle addresses of any length,
+/* and bytes of any width.
+/*
+/* Arguments:
+/* .IP addr_bytes
+/* The network address in network byte order.
+/* .IP addr_byte_count
+/* The network address length in bytes.
+/* .IP network_bits
+/* The number of initial bits that will not be cleared.
+/* DIAGNOSTICS
+/* Fatal errors: the number of network bits exceeds the address size.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <limits.h> /* CHAR_BIT */
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mask_addr.h>
+
+/* mask_addr - mask off a variable-length address */
+
+void mask_addr(unsigned char *addr_bytes,
+ unsigned addr_byte_count,
+ unsigned network_bits)
+{
+ unsigned char *p;
+
+ if (network_bits > addr_byte_count * CHAR_BIT)
+ msg_panic("mask_addr: address byte count %d too small for bit count %d",
+ addr_byte_count, network_bits);
+
+ p = addr_bytes + network_bits / CHAR_BIT;
+ network_bits %= CHAR_BIT;
+
+ if (network_bits != 0)
+ *p++ &= ~0 << (CHAR_BIT - network_bits);
+
+ while (p < addr_bytes + addr_byte_count)
+ *p++ = 0;
+}
-#ifndef _INET_UTIL_H_INCLUDED_
-#define _INET_UTIL_H_INCLUDED_
+#ifndef _MASK_ADDR_H_INCLUDED_
+#define _MASK_ADDR_H_INCLUDED_
/*++
/* NAME
-/* inet_util 3h
+/* mask_addr 3h
/* SUMMARY
-/* INET-domain utilities
+/* address bit banging
/* SYNOPSIS
-/* #include <inet_util.h>
+/* #include <mask_addr.h>
/* DESCRIPTION
/* .nf
- /* External interface. */
-
-extern char *inet_parse(const char *, char **, char **);
+ /*
+ * External interface.
+ */
+extern void mask_addr(unsigned char *, unsigned, unsigned);
/* LICENSE
/* .ad
const char **match_args; /* match arguments */
};
+#define MATCH_DICTIONARY(pattern) \
+ ((pattern)[0] != '[' && strchr((pattern), ':') != 0)
+
/* match_list_parse - parse buffer, destroy buffer */
static ARGV *match_list_parse(ARGV *list, char *string)
list = match_list_parse(list, vstring_str(buf));
if (vstream_fclose(fp))
msg_fatal("%s: read file %s: %m", myname, pattern);
- } else if (strchr(pattern, ':') != 0) { /* type:table */
+ } else if (MATCH_DICTIONARY(pattern)) { /* type:table */
if (buf == 0)
buf = vstring_alloc(10);
#define OPEN_FLAGS O_RDONLY
map_type_name_flags = STR(buf) + (map_type_name - pattern);
if (dict_handle(map_type_name_flags) == 0)
dict_register(map_type_name_flags,
- dict_open(map_type_name, OPEN_FLAGS, DICT_FLAGS));
+ dict_open(map_type_name, OPEN_FLAGS, DICT_FLAGS));
argv_add(list, STR(buf), (char *) 0);
} else { /* other pattern */
argv_add(list, pattern, (char *) 0);
#include <strings.h>
#endif
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
-#endif
-
/* Utility library. */
#include <msg.h>
#include <dict.h>
#include <match_ops.h>
#include <stringops.h>
+#include <cidr_match.h>
+
+#define MATCH_DICTIONARY(pattern) \
+ ((pattern)[0] != '[' && strchr((pattern), ':') != 0)
/* match_string - match a string literal */
/*
* Try dictionary lookup: exact match.
*/
- if (strchr(pattern, ':') != 0) {
+ if (MATCH_DICTIONARY(pattern)) {
key = lowercase(mystrdup(string));
match = (dict_lookup(pattern, key) != 0);
myfree(key);
/*
* Try dictionary lookup: exact match and parent domains.
*/
- if (strchr(pattern, ':') != 0) {
+ if (MATCH_DICTIONARY(pattern)) {
temp = lowercase(mystrdup(name));
match = 0;
for (entry = temp; *entry != 0; entry = next) {
return (0);
}
-/* match_parse_mask - parse net/mask pattern */
-
-static int match_parse_mask(const char *pattern, unsigned long *net_bits,
- unsigned int *mask_shift)
-{
- char *saved_pattern;
- char *mask;
-
-#define BITS_PER_ADDR 32
-
- saved_pattern = mystrdup(pattern);
- if ((mask = split_at(saved_pattern, '/')) != 0) {
- if (!alldig(mask) || (*mask_shift = atoi(mask)) > BITS_PER_ADDR
- || (*net_bits = inet_addr(saved_pattern)) == INADDR_NONE) {
- msg_fatal("bad net/mask pattern: %s", pattern);
- }
- }
- myfree(saved_pattern);
- return (mask != 0);
-}
-
/* match_hostaddr - match host by address */
int match_hostaddr(int unused_flags, const char *addr, const char *pattern)
{
char *myname = "match_hostaddr";
- unsigned int mask_shift;
- unsigned long mask_bits;
- unsigned long net_bits;
- unsigned long addr_bits;
- struct in_addr net_addr;
+ char *saved_patt;
+ CIDR_MATCH match_info;
+ VSTRING *err;
if (msg_verbose)
msg_info("%s: %s ~? %s", myname, addr, pattern);
- if (addr[strspn(addr, "01234567890./:")] != 0)
+#define V4_ADDR_STRING_CHARS "01234567890."
+#define V6_ADDR_STRING_CHARS V4_ADDR_STRING_CHARS "abcdefABCDEF:"
+
+ if (addr[strspn(addr, V6_ADDR_STRING_CHARS)] != 0)
return (0);
/*
- * Try dictionary lookup. This can be case insensitive. XXX Probably
- * should also try again after stripping least significant octets.
+ * Try dictionary lookup. This can be case insensitive.
*/
- if (strchr(pattern, ':') != 0) {
+ if (MATCH_DICTIONARY(pattern)) {
if (dict_lookup(pattern, addr) != 0)
return (1);
if (dict_errno != 0)
/*
* Try an exact match with the host address.
*/
- if (strcasecmp(addr, pattern) == 0) {
- return (1);
+ if (pattern[0] != '[') {
+ if (strcasecmp(addr, pattern) == 0)
+ return (1);
+ } else {
+ int addr_len = strlen(addr);
+
+ if (strncasecmp(addr, pattern + 1, addr_len) == 0
+ && strcmp(pattern + 1 + addr_len, "]") == 0)
+ return (1);
}
/*
- * In a net/mask pattern, the mask is specified as the number of bits of
- * the network part.
+ * Light-weight tests before we get into expensive operations.
+ *
+ * - Don't bother matching IPv4 against IPv6. Postfix transforms
+ * IPv4-in-IPv6 to native IPv4 form when IPv4 support is enabled in
+ * Postfix; if not, then Postfix has no business dealing with IPv4
+ * addresses anyway.
+ *
+ * - Don't bother if the pattern is a bare IPv4 address. That form would
+ * have been matched with the strcasecmp() call above.
+ *
+ * - Don't bother if the pattern isn't an address or address/mask.
*/
- if (match_parse_mask(pattern, &net_bits, &mask_shift)) {
- addr_bits = inet_addr(addr);
- if (addr_bits == INADDR_NONE)
- msg_fatal("%s: bad address argument: %s", myname, addr);
- mask_bits = mask_shift > 0 ?
- htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift)) : 0;
- if ((addr_bits & mask_bits) == net_bits)
- return (1);
- if (net_bits & ~mask_bits) {
- net_addr.s_addr = (net_bits & mask_bits);
- msg_fatal("net/mask pattern %s has a non-null host portion; "
- "specify %s/%d if this is really what you want",
- pattern, inet_ntoa(net_addr), mask_shift);
- }
- }
- return (0);
+ if (!strchr(addr, ':') != !strchr(pattern, ':')
+ || pattern[strspn(pattern, V4_ADDR_STRING_CHARS)] == 0
+ || pattern[strspn(pattern, V6_ADDR_STRING_CHARS "[]/")] != 0)
+ return (0);
+
+ /*
+ * No escape from expensive operations: either we have a net/mask
+ * pattern, or we have an address that can have multiple valid
+ * representations (e.g., 0:0:0:0:0:0:0:1 versus ::1, etc.). The only way
+ * to find out if the address matches the pattern is to transform
+ * everything into to binary form, and to do the comparison there.
+ */
+ saved_patt = mystrdup(pattern);
+ if ((err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0)) != 0)
+ msg_fatal("%s", vstring_str(err));
+ myfree(saved_patt);
+ return (cidr_match_execute(&match_info, addr) != 0);
}
* Usage: msg_syslog_test text...
*/
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
VSTRING *vp = vstring_alloc(256);
--- /dev/null
+/*++
+/* NAME
+/* myaddrinfo 3
+/* SUMMARY
+/* addrinfo encapsulation and emulation
+/* SYNOPSIS
+/* #include <myaddrinfo.h>
+/*
+/* #define MAI_V4ADDR_BITS ...
+/* #define MAI_V6ADDR_BITS ...
+/* #define MAI_V4ADDR_BYTES ...
+/* #define MAI_V6ADDR_BYTES ...
+/*
+/* typedef struct { char buf[....]; } MAI_HOSTNAME_STR;
+/* typedef struct { char buf[....]; } MAI_HOSTADDR_STR;
+/* typedef struct { char buf[....]; } MAI_SERVNAME_STR;
+/* typedef struct { char buf[....]; } MAI_SERVPORT_STR;
+/*
+/* int hostname_to_sockaddr(hostname, service, socktype, result)
+/* const char *hostname;
+/* const char *service;
+/* int socktype;
+/* struct addrinfo **result;
+/*
+/* int hostaddr_to_sockaddr(hostaddr, service, socktype, result)
+/* const char *hostaddr;
+/* const char *service;
+/* int socktype;
+/* struct addrinfo **result;
+/*
+/* int sockaddr_to_hostaddr(sa, salen, hostaddr, portnum, socktype)
+/* const struct sockaddr *sa;
+/* SOCKADDR_SIZE salen;
+/* MAI_HOSTADDR_STR *hostaddr;
+/* MAI_SERVPORT_STR *portnum;
+/* int socktype;
+/*
+/* int sockaddr_to_hostname(sa, salen, hostname, service, socktype)
+/* const struct sockaddr *sa;
+/* SOCKADDR_SIZE salen;
+/* MAI_HOSTNAME_STR *hostname;
+/* MAI_SERVNAME_STR *service;
+/* int socktype;
+/*
+/* const char *MAI_STRERROR(error)
+/* int error;
+/* DESCRIPTION
+/* This module provides a simplified user interface to the
+/* getaddrinfo(3) and getnameinfo(3) routines (which provide
+/* a unified interface to manipulate IPv4 and IPv6 socket
+/* address structures).
+/*
+/* On systems without getaddrinfo(3) and getnameinfo(3) support,
+/* emulation for IPv4 only can be enabled by defining
+/* EMULATE_IPV4_ADDRINFO.
+/*
+/* hostname_to_sockaddr() looks up the binary addresses for
+/* the specified symbolic hostname or numeric address. The
+/* result should be destroyed with freeaddrinfo(). A null host
+/* pointer converts to the null host address.
+/*
+/* hostaddr_to_sockaddr() converts a printable network address
+/* into the corresponding binary form. The result should be
+/* destroyed with freeaddrinfo(). A null host pointer converts
+/* to the null host address.
+/*
+/* sockaddr_to_hostaddr() converts a binary network address
+/* into printable form. The result buffers should be large
+/* enough to hold the printable address or port including the
+/* null terminator.
+/*
+/* sockaddr_to_hostname() converts a binary network address
+/* into a hostname or service. The result buffer should be
+/* large enough to hold the hostname or service including the
+/* null terminator. This routine rejects malformed hostnames
+/* or numeric hostnames and pretends that the lookup failed.
+/*
+/* MAI_STRERROR() is an unsafe macro (it evaluates the argument
+/* multiple times) that invokes strerror() or gai_strerror()
+/* as appropriate.
+/*
+/* This module exports the following constants that should be
+/* user for storage allocation of name or address information:
+/* .IP MAI_V4ADDR_BITS
+/* .IP MAI_V6ADDR_BITS
+/* .IP MAI_V4ADDR_BYTES
+/* .IP MAI_V6ADDR_BYTES
+/* The number of bits or bytes needed to store a binary
+/* IPv4 or IPv6 network address.
+/* .PP
+/* The types MAI_HOST{NAME,ADDR}_STR and MAI_SERV{NAME,PORT}_STR
+/* implement buffers for the storage of the string representations
+/* of symbolic or numerical hosts or services. Do not use
+/* buffer types other than the ones that are expected here,
+/* or things will blow up with buffer overflow problems.
+/*
+/* Arguments:
+/* .IP hostname
+/* On input to hostname_to_sockaddr(), a numeric or symbolic
+/* hostname, or a null pointer (meaning the wild-card listen
+/* address). On output from sockaddr_to_hostname(), storage
+/* for the result hostname, or a null pointer.
+/* .IP hostaddr
+/* On input to hostaddr_to_sockaddr(), a numeric hostname,
+/* or a null pointer (meaning the wild-card listen address).
+/* On output from sockaddr_to_hostaddr(), storage for the
+/* result hostaddress, or a null pointer.
+/* .IP service
+/* On input to hostname/addr_to_sockaddr(), a numeric or
+/* symbolic service name, or a null pointer in which case the
+/* socktype argument is ignored. On output from
+/* sockaddr_to_hostname/addr(), storage for the result service
+/* name, or a null pointer.
+/* .IP portnum
+/* Storage for the result service port number, or a null pointer.
+/* .IP socktype
+/* Socket type: SOCK_STREAM, SOCK_DGRAM, etc. This argument is
+/* ignored when no service or port are specified.
+/* .IP sa
+/* Protocol-independent socket address structure.
+/* .IP salen
+/* Protocol-dependent socket address structure size in bytes.
+/* SEE ALSO
+/* getaddrinfo(3), getnameinfo(3), freeaddrinfo(3), gai_strerror(3)
+/* DIAGNOSTICS
+/* All routines either return 0 upon success, or an error code
+/* that is compatible with gai_strerror().
+/*
+/* On systems where addrinfo support is emulated by Postfix,
+/* some out-of-memory errors are not reported to the caller,
+/* but are handled by mymalloc().
+/* BUGS
+/* The IPv4-only emulation code does not support requests that
+/* specify a service but no socket type. It returns an error
+/* indication, instead of enumerating all the possible answers.
+/*
+/* The hostname/addr_to_sockaddr() routines should accept a
+/* list of address families that the caller is interested in,
+/* and they should return only information of those types.
+/*
+/* Unfortunately, it is not possible to remove unwanted address
+/* family results from hostname_to_sockaddr(), because we
+/* don't know how the system library routine getaddrinfo()
+/* allocates memory. For example, getaddrinfo() could save
+/* space by referencing the same string object from multiple
+/* addrinfo structures; or it could allocate a string object
+/* and the addrinfo structure as one memory block.
+/*
+/* We could get around this by copying getaddrinfo() results
+/* to our own private data structures, but that would only
+/* make an already expensive API even more expensive.
+/*
+/* A better workaround is to return a vector of addrinfo
+/* pointers to the elements that contain only the elements
+/* that the caller is interested in. The pointer to the
+/* original getaddrinfo() result can be hidden at the end
+/* after the null terminator, or before the first element.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <valid_hostname.h>
+#include <sock_addr.h>
+#include <stringops.h>
+#include <msg.h>
+#include <inet_proto.h>
+#include <myaddrinfo.h>
+
+/* Application-specific. */
+
+ /*
+ * Use an old trick to save some space: allocate space for two objects in
+ * one. In Postfix we often use this trick for structures that have an array
+ * of things at the end.
+ */
+struct ipv4addrinfo {
+ struct addrinfo info;
+ struct sockaddr_in sin;
+};
+
+ /*
+ * Make nulls more descriptive.
+ */
+#define NO_SERVICE ((char *) 0)
+
+ /*
+ * When we're not interested in service ports, we must pick a socket type
+ * otherwise getaddrinfo() will give us duplicate results: one set for TCP,
+ * and another set for UDP. For consistency, we'll use the same default
+ * socket type for the results from emulation mode.
+ */
+#define MAI_SOCKTYPE SOCK_STREAM /* getaddrinfo() query */
+
+#ifdef EMULATE_IPV4_ADDRINFO
+
+/* clone_ipv4addrinfo - clone ipv4addrinfo structure */
+
+static struct ipv4addrinfo *clone_ipv4addrinfo(struct ipv4addrinfo * tp)
+{
+ struct ipv4addrinfo *ip;
+
+ ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
+ *ip = *tp;
+ ip->info.ai_addr = (struct sockaddr *) & (ip->sin);
+ return (ip);
+}
+
+/* init_ipv4addrinfo - initialize an ipv4addrinfo structure */
+
+static void init_ipv4addrinfo(struct ipv4addrinfo * ip, int socktype)
+{
+
+ /*
+ * Portability: null pointers aren't necessarily all-zero bits, so we
+ * make explicit assignments to all the pointers that we're aware of.
+ */
+ memset((char *) ip, 0, sizeof(*ip));
+ ip->info.ai_family = PF_INET;
+ ip->info.ai_socktype = socktype;
+ ip->info.ai_protocol = 0; /* XXX */
+ ip->info.ai_addrlen = sizeof(ip->sin);
+ ip->info.ai_canonname = 0;
+ ip->info.ai_addr = (struct sockaddr *) & (ip->sin);
+ ip->info.ai_next = 0;
+ ip->sin.sin_family = AF_INET;
+#ifdef HAS_SA_LEN
+ ip->sin.sin_len = sizeof(ip->sin);
+#endif
+}
+
+/* find_service - translate numeric or symbolic service name */
+
+static int find_service(const char *service, int socktype)
+{
+ struct servent *sp;
+ const char *proto;
+ unsigned port;
+
+ if (alldig(service)) {
+ port = atoi(service);
+ return (port < 65536 ? htons(port) : -1);
+ }
+ if (socktype == SOCK_STREAM) {
+ proto = "tcp";
+ } else if (socktype == SOCK_DGRAM) {
+ proto = "udp";
+ } else {
+ return (-1);
+ }
+ if ((sp = getservbyname(service, proto)) != 0) {
+ return (sp->s_port);
+ } else {
+ return (-1);
+ }
+}
+
+#endif
+
+/* hostname_to_sockaddr - hostname to binary address form */
+
+int hostname_to_sockaddr(const char *hostname, const char *service,
+ int socktype, struct addrinfo ** res)
+{
+#ifdef EMULATE_IPV4_ADDRINFO
+
+ /*
+ * Emulated getaddrinfo(3) version.
+ */
+ static struct ipv4addrinfo template;
+ struct ipv4addrinfo *ip;
+ struct ipv4addrinfo *prev;
+ struct in_addr addr;
+ struct hostent *hp;
+ char **name_list;
+ int port;
+
+ /*
+ * Validate the service.
+ */
+ if (service) {
+ if ((port = find_service(service, socktype)) < 0)
+ return (EAI_SERVICE);
+ } else {
+ port = 0;
+ socktype = MAI_SOCKTYPE;
+ }
+
+ /*
+ * No host means INADDR_ANY.
+ */
+ if (hostname == 0) {
+ ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
+ init_ipv4addrinfo(ip, socktype);
+ ip->sin.sin_addr.s_addr = INADDR_ANY;
+ ip->sin.sin_port = port;
+ *res = &(ip->info);
+ return (0);
+ }
+
+ /*
+ * Numeric host.
+ */
+ if (inet_pton(AF_INET, hostname, (void *) &addr) == 1) {
+ ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
+ init_ipv4addrinfo(ip, socktype);
+ ip->sin.sin_addr = addr;
+ ip->sin.sin_port = port;
+ *res = &(ip->info);
+ return (0);
+ }
+
+ /*
+ * Look up the IPv4 address list.
+ */
+ if ((hp = gethostbyname(hostname)) == 0)
+ return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NODATA);
+ if (hp->h_addrtype != AF_INET
+ || hp->h_length != sizeof(template.sin.sin_addr))
+ return (EAI_NODATA);
+
+ /*
+ * Initialize the result template.
+ */
+ if (template.info.ai_addrlen == 0)
+ init_ipv4addrinfo(&template, socktype);
+
+ /*
+ * Copy the address information into an addrinfo structure.
+ */
+ prev = &template;
+ for (name_list = hp->h_addr_list; name_list[0]; name_list++) {
+ ip = clone_ipv4addrinfo(prev);
+ ip->sin.sin_addr = IN_ADDR(name_list[0]);
+ ip->sin.sin_port = port;
+ if (prev == &template)
+ *res = &(ip->info);
+ else
+ prev->info.ai_next = &(ip->info);
+ prev = ip;
+ }
+ return (0);
+#else
+
+ /*
+ * Native getaddrinfo(3) version.
+ *
+ * XXX Wild-card listener issues.
+ *
+ * With most IPv4 plus IPv6 systems, an IPv6 wild-card listener also listens
+ * on the IPv4 wild-card address. Connections from IPv4 clients appear as
+ * IPv4-in-IPv6 addresses; when Postfix support for IPv4 is turned on,
+ * Postfix automatically maps these embedded addresses to their original
+ * IPv4 form. So everything seems to be fine.
+ *
+ * However, some applications prefer to use separate listener sockets for
+ * IPv4 and IPv6. The Postfix IPv6 patch provided such an example. And
+ * this is where things become tricky. On many systems the IPv6 and IPv4
+ * wild-card listeners cannot coexist. When one is already active, the
+ * other fails with EADDRINUSE. Solaris 9, however, will automagically
+ * "do the right thing" and allow both listeners to coexist.
+ *
+ * Recent systems have the IPV6_V6ONLY feature (RFC 3493), which tells the
+ * system that we really mean IPv6 when we say IPv6. This allows us to
+ * set up separate wild-card listener sockets for IPv4 and IPv6. So
+ * everything seems to be fine again.
+ *
+ * The following workaround disables the wild-card IPv4 listener when
+ * IPV6_V6ONLY is unavailable. This is necessary for some Linux versions,
+ * but is not needed for Solaris 9 (which allows IPv4 and IPv6 wild-card
+ * listeners to coexist). Solaris 10 beta already has IPV6_V6ONLY.
+ *
+ * XXX This workaround obviously breaks if we want to support protocols in
+ * addition to IPv6 and IPv4, but it is needed only until IPv6
+ * implementations catch up with RFC 3493. A nicer fix is to filter the
+ * getaddrinfo() result, and to return a vector of addrinfo pointers to
+ * only those types of elements that the caller has expressed interested
+ * in.
+ *
+ * XXX Vanilla AIX 5.1 getaddrinfo() does not support a null hostname with
+ * AI_PASSIVE. And since we don't know how getaddrinfo() manages its
+ * memory we can't bypass it for this special case, or freeaddrinfo()
+ * might blow up. Instead we turn off IPV6_V6ONLY in inet_listen(), and
+ * supply a protocol-dependent hard-coded string value to getaddrinfo()
+ * below, so that it will convert into the appropriate wild-card address.
+ */
+ struct addrinfo hints;
+
+ memset((char *) &hints, 0, sizeof(hints));
+ hints.ai_family = inet_proto_info()->ai_family;
+ hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
+ if (!hostname) {
+ hints.ai_flags = AI_PASSIVE;
+#if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
+ switch (hints.ai_family) {
+ case PF_UNSPEC:
+ hints.ai_family = PF_INET6;
+#ifdef BROKEN_AI_PASSIVE_NULL_HOST
+ case PF_INET6:
+ hostname = "::";
+ break;
+ case PF_INET:
+ hostname = "0.0.0.0";
+ break;
+#endif
+ }
+#endif
+ }
+ return (getaddrinfo(hostname, service, &hints, res));
+#endif
+}
+
+/* hostaddr_to_sockaddr - printable address to binary address form */
+
+int hostaddr_to_sockaddr(const char *hostaddr, const char *service,
+ int socktype, struct addrinfo ** res)
+{
+#ifdef EMULATE_IPV4_ADDRINFO
+
+ /*
+ * Emulated getaddrinfo(3) version.
+ */
+ struct ipv4addrinfo *ip;
+ struct in_addr addr;
+ int port;
+
+ /*
+ * Validate the service.
+ */
+ if (service) {
+ if ((port = find_service(service, socktype)) < 0)
+ return (EAI_SERVICE);
+ } else {
+ port = 0;
+ socktype = MAI_SOCKTYPE;
+ }
+
+ /*
+ * No host means INADDR_ANY.
+ */
+ if (hostaddr == 0) {
+ ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
+ init_ipv4addrinfo(ip, socktype);
+ ip->sin.sin_addr.s_addr = INADDR_ANY;
+ ip->sin.sin_port = port;
+ *res = &(ip->info);
+ return (0);
+ }
+
+ /*
+ * Deal with bad address forms.
+ */
+ switch (inet_pton(AF_INET, hostaddr, (void *) &addr)) {
+ case 1: /* Success */
+ break;
+ default: /* Unparsable */
+ return (EAI_NONAME);
+ case -1: /* See errno */
+ return (EAI_SYSTEM);
+ }
+
+ /*
+ * Initialize the result structure.
+ */
+ ip = (struct ipv4addrinfo *) mymalloc(sizeof(*ip));
+ init_ipv4addrinfo(ip, socktype);
+
+ /*
+ * And copy the result.
+ */
+ ip->sin.sin_addr = addr;
+ ip->sin.sin_port = port;
+ *res = &(ip->info);
+
+ return (0);
+#else
+
+ /*
+ * Native getaddrinfo(3) version. See comments in hostname_to_sockaddr().
+ *
+ * XXX Vanilla AIX 5.1 getaddrinfo() returns multiple results when
+ * converting a printable ipv4 or ipv6 address to socket address with
+ * ai_family=PF_UNSPEC, ai_flags=AI_NUMERICHOST, ai_socktype=SOCK_STREAM,
+ * ai_protocol=0 or IPPROTO_TCP, and service=0. The workaround is to
+ * ignore all but the first result.
+ */
+ struct addrinfo hints;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = inet_proto_info()->ai_family;
+ hints.ai_socktype = service ? socktype : MAI_SOCKTYPE;
+ hints.ai_flags = AI_NUMERICHOST;
+ if (!hostaddr) {
+ hints.ai_flags |= AI_PASSIVE;
+#if !defined(IPV6_V6ONLY) || defined(BROKEN_AI_PASSIVE_NULL_HOST)
+ switch (hints.ai_family) {
+ case PF_UNSPEC:
+ hints.ai_family = PF_INET6;
+#ifdef BROKEN_AI_PASSIVE_NULL_HOST
+ case PF_INET6:
+ hostaddr = "::";
+ break;
+ case PF_INET:
+ hostaddr = "0.0.0.0";
+ break;
+#endif
+ }
+#endif
+ }
+ return (getaddrinfo(hostaddr, service, &hints, res));
+#endif
+}
+
+/* sockaddr_to_hostaddr - binary address to printable address form */
+
+int sockaddr_to_hostaddr(const struct sockaddr * sa, SOCKADDR_SIZE salen,
+ MAI_HOSTADDR_STR *hostaddr,
+ MAI_SERVPORT_STR *portnum,
+ int unused_socktype)
+{
+#ifdef EMULATE_IPV4_ADDRINFO
+ char portbuf[sizeof("65535")];
+ int len;
+
+ /*
+ * Emulated getnameinfo(3) version. The buffer length includes the space
+ * for the null terminator.
+ */
+ if (sa->sa_family != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return (EAI_SYSTEM);
+ }
+ if (hostaddr != 0) {
+ if (inet_ntop(AF_INET, (void *) &(SOCK_ADDR_IN_ADDR(sa)),
+ hostaddr->buf, sizeof(hostaddr->buf)) == 0)
+ return (EAI_SYSTEM);
+ }
+ if (portnum != 0) {
+ sprintf(portbuf, "%d", ntohs(SOCK_ADDR_IN_PORT(sa)) & 0xffff);
+ if ((len = strlen(portbuf)) >= sizeof(portnum->buf)) {
+ errno = ENOSPC;
+ return (EAI_SYSTEM);
+ }
+ memcpy(portnum->buf, portbuf, len + 1);
+ }
+ return (0);
+#else
+
+ /*
+ * Native getnameinfo(3) version.
+ */
+ return (getnameinfo(sa, salen,
+ hostaddr ? hostaddr->buf : (char *) 0,
+ hostaddr ? sizeof(hostaddr->buf) : 0,
+ portnum ? portnum->buf : (char *) 0,
+ portnum ? sizeof(portnum->buf) : 0,
+ NI_NUMERICHOST | NI_NUMERICSERV));
+#endif
+}
+
+/* sockaddr_to_hostname - binary address to printable hostname */
+
+int sockaddr_to_hostname(const struct sockaddr * sa, SOCKADDR_SIZE salen,
+ MAI_HOSTNAME_STR *hostname,
+ MAI_SERVNAME_STR *service,
+ int socktype)
+{
+#ifdef EMULATE_IPV4_ADDRINFO
+
+ /*
+ * Emulated getnameinfo(3) version.
+ */
+ struct hostent *hp;
+ struct servent *sp;
+ size_t len;
+
+ /*
+ * Sanity check.
+ */
+ if (sa->sa_family != AF_INET)
+ return (EAI_NODATA);
+
+ /*
+ * Look up the host name.
+ */
+ if (hostname != 0) {
+ if ((hp = gethostbyaddr((char *) &(SOCK_ADDR_IN_ADDR(sa)),
+ sizeof(SOCK_ADDR_IN_ADDR(sa)),
+ AF_INET)) == 0)
+ return (h_errno == TRY_AGAIN ? EAI_AGAIN : EAI_NONAME);
+
+ /*
+ * Save the result. The buffer length includes the space for the null
+ * terminator. Hostname sanity checks are at the end of this
+ * function.
+ */
+ if ((len = strlen(hp->h_name)) >= sizeof(hostname->buf)) {
+ errno = ENOSPC;
+ return (EAI_SYSTEM);
+ }
+ memcpy(hostname->buf, hp->h_name, len + 1);
+ }
+
+ /*
+ * Look up the service.
+ */
+ if (service != 0) {
+ if ((sp = getservbyport(ntohs(SOCK_ADDR_IN_PORT(sa)),
+ socktype == SOCK_DGRAM ? "udp" : "tcp")) == 0)
+ return (EAI_NONAME);
+
+ /*
+ * Save the result. The buffer length includes the space for the null
+ * terminator.
+ */
+ if ((len = strlen(sp->s_name)) >= sizeof(service->buf)) {
+ errno = ENOSPC;
+ return (EAI_SYSTEM);
+ }
+ memcpy(service->buf, sp->s_name, len + 1);
+ }
+#else
+
+ /*
+ * Native getnameinfo(3) version.
+ */
+ int err;
+
+ err = getnameinfo(sa, salen,
+ hostname ? hostname->buf : (char *) 0,
+ hostname ? sizeof(hostname->buf) : 0,
+ service ? service->buf : (char *) 0,
+ service ? sizeof(service->buf) : 0,
+ socktype == SOCK_DGRAM ?
+ NI_NAMEREQD | NI_DGRAM : NI_NAMEREQD);
+ if (err != 0)
+ return (err);
+#endif
+
+ /*
+ * Hostname sanity checks.
+ */
+ if (hostname != 0) {
+ if (valid_hostaddr(hostname->buf, DONT_GRIPE)) {
+ msg_warn("numeric hostname: %s", hostname->buf);
+ return (EAI_NONAME);
+ }
+ if (!valid_hostname(hostname->buf, DO_GRIPE))
+ return (EAI_NONAME);
+ }
+ return (0);
+}
+
+/* myaddrinfo_control - fine control */
+
+void myaddrinfo_control(int name,...)
+{
+ const char *myname = "myaddrinfo_control";
+ va_list ap;
+
+ for (va_start(ap, name); name != 0; name = va_arg(ap, int)) {
+ switch (name) {
+ default:
+ msg_panic("%s: bad name %d", myname, name);
+ }
+ }
+}
+
+#ifdef EMULATE_IPV4_ADDRINFO
+
+/* freeaddrinfo - release storage */
+
+void freeaddrinfo(struct addrinfo * ai)
+{
+ struct addrinfo *ap;
+ struct addrinfo *next;
+
+ /*
+ * Artefact of implementation: tolerate a null pointer argument.
+ */
+ for (ap = ai; ap != 0; ap = next) {
+ next = ap->ai_next;
+ if (ap->ai_canonname)
+ myfree(ap->ai_canonname);
+ /* ap->ai_addr is allocated within this memory block */
+ myfree((char *) ap);
+ }
+}
+
+static char *ai_errlist[] = {
+ "Success",
+ "Address family for hostname not supported", /* EAI_ADDRFAMILY */
+ "Temporary failure in name resolution", /* EAI_AGAIN */
+ "Invalid value for ai_flags", /* EAI_BADFLAGS */
+ "Non-recoverable failure in name resolution", /* EAI_FAIL */
+ "ai_family not supported", /* EAI_FAMILY */
+ "Memory allocation failure", /* EAI_MEMORY */
+ "No address associated with hostname", /* EAI_NODATA */
+ "hostname nor servname provided, or not known", /* EAI_NONAME */
+ "service name not supported for ai_socktype", /* EAI_SERVICE */
+ "ai_socktype not supported", /* EAI_SOCKTYPE */
+ "System error returned in errno", /* EAI_SYSTEM */
+ "Invalid value for hints", /* EAI_BADHINTS */
+ "Resolved protocol is unknown", /* EAI_PROTOCOL */
+ "Unknown error", /* EAI_MAX */
+};
+
+/* gai_strerror - error number to string */
+
+char *gai_strerror(int ecode)
+{
+
+ /*
+ * Note: EAI_SYSTEM errors are not automatically handed over to
+ * strerror(). The application decides.
+ */
+ if (ecode < 0 || ecode > EAI_MAX)
+ ecode = EAI_MAX;
+ return (ai_errlist[ecode]);
+}
+
+#endif
+
+#ifdef TEST
+
+ /*
+ * A test program that takes some info from the command line and runs it
+ * forward and backward through the above conversion routines.
+ */
+#include <msg.h>
+#include <vstream.h>
+#include <msg_vstream.h>
+
+int main(int argc, char **argv)
+{
+ struct addrinfo *info;
+ struct addrinfo *ip;
+ MAI_HOSTNAME_STR host;
+ MAI_HOSTADDR_STR addr;
+ int err;
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+
+ if (argc != 4)
+ msg_fatal("usage: %s protocols hostname hostaddress", argv[0]);
+
+ inet_proto_init(argv[0], argv[1]);
+
+ msg_info("=== hostname %s ===", argv[2]);
+
+ if ((err = hostname_to_sockaddr(argv[2], (char *) 0, 0, &info)) != 0) {
+ msg_info("hostname_to_sockaddr(%s): %s",
+ argv[2], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
+ } else {
+ for (ip = info; ip != 0; ip = ip->ai_next) {
+ if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
+ (MAI_SERVPORT_STR *) 0, 0)) != 0) {
+ msg_info("sockaddr_to_hostaddr: %s",
+ err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
+ continue;
+ }
+ msg_info("%s -> family=%d sock=%d proto=%d %s", argv[2],
+ ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf);
+ if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
+ (MAI_SERVNAME_STR *) 0, 0)) != 0) {
+ msg_info("sockaddr_to_hostname: %s",
+ err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
+ continue;
+ }
+ msg_info("%s -> %s", addr.buf, host.buf);
+ }
+ freeaddrinfo(info);
+ }
+
+ msg_info("=== host address %s ===", argv[3]);
+
+ if ((err = hostaddr_to_sockaddr(argv[3], (char *) 0, 0, &ip)) != 0) {
+ msg_info("hostaddr_to_sockaddr(%s): %s",
+ argv[3], err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
+ } else {
+ if ((err = sockaddr_to_hostaddr(ip->ai_addr, ip->ai_addrlen, &addr,
+ (MAI_SERVPORT_STR *) 0, 0)) != 0) {
+ msg_info("sockaddr_to_hostaddr: %s",
+ err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
+ } else {
+ msg_info("%s -> family=%d sock=%d proto=%d %s", argv[3],
+ ip->ai_family, ip->ai_socktype, ip->ai_protocol, addr.buf);
+ if ((err = sockaddr_to_hostname(ip->ai_addr, ip->ai_addrlen, &host,
+ (MAI_SERVNAME_STR *) 0, 0)) != 0) {
+ msg_info("sockaddr_to_hostname: %s",
+ err == EAI_SYSTEM ? strerror(errno) : gai_strerror(err));
+ } else
+ msg_info("%s -> %s", addr.buf, host.buf);
+ freeaddrinfo(ip);
+ }
+ }
+ exit(0);
+}
+
+#endif
--- /dev/null
+#ifndef _MYADDRINFO_H_INCLUDED_
+#define _MYADDRINFO_H_INCLUDED_
+
+/*++
+/* NAME
+/* myaddrinfo 3h
+/* SUMMARY
+/* addrinfo encapsulation and emulation
+/* SYNOPSIS
+/* #include <myaddrinfo.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <errno.h> /* MAI_STRERROR() */
+#include <limits.h> /* CHAR_BIT */
+
+ /*
+ * Backwards compatibility support for IPV4 systems without addrinfo API.
+ */
+#ifdef EMULATE_IPV4_ADDRINFO
+
+ /*
+ * Avoid clashes with global symbols, just in case some third-party library
+ * provides its own addrinfo() implementation. This also allows us to test
+ * the IPV4 emulation code on an IPV6 enabled system.
+ */
+#undef freeaddrinfo
+#define freeaddrinfo mai_freeaddrinfo
+#undef gai_strerror
+#define gai_strerror mai_strerror
+#undef addrinfo
+#define addrinfo mai_addrinfo
+#undef sockaddr_storage
+#define sockaddr_storage mai_sockaddr_storage
+
+ /*
+ * Modern systems define this in <netdb.h>.
+ */
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE|CANONNAME|NUMERICHOST */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for nodename */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+
+ /*
+ * Modern systems define this in <sys/socket.h>.
+ */
+struct sockaddr_storage {
+ struct sockaddr_in dummy; /* alignment!! */
+};
+
+ /*
+ * Result codes. See gai_strerror() for text. Undefine already imported
+ * definitions so that we can test the IPv4-only emulation on a modern
+ * system without getting a ton of compiler warnings.
+ */
+#undef EAI_ADDRFAMILY
+#define EAI_ADDRFAMILY 1
+#undef EAI_AGAIN
+#define EAI_AGAIN 2
+#undef EAI_BADFLAGS
+#define EAI_BADFLAGS 3
+#undef EAI_FAIL
+#define EAI_FAIL 4
+#undef EAI_FAMILY
+#define EAI_FAMILY 5
+#undef EAI_MEMORY
+#define EAI_MEMORY 6
+#undef EAI_NODATA
+#define EAI_NODATA 7
+#undef EAI_NONAME
+#define EAI_NONAME 8
+#undef EAI_SERVICE
+#define EAI_SERVICE 9
+#undef EAI_SOCKTYPE
+#define EAI_SOCKTYPE 10
+#undef EAI_SYSTEM
+#define EAI_SYSTEM 11
+#undef EAI_BADHINTS
+#define EAI_BADHINTS 12
+#undef EAI_PROTOCOL
+#define EAI_PROTOCOL 13
+#undef EAI_RESNULL
+#define EAI_RESNULL 14
+#undef EAI_MAX
+#define EAI_MAX 15
+
+extern void freeaddrinfo(struct addrinfo *);
+extern char *gai_strerror(int);
+
+#endif
+
+ /*
+ * Bounds grow in leaps. These macros attempt to keep non-library code free
+ * from IPV6 #ifdef pollution. Avoid macro names that end in STRLEN because
+ * they suggest that space for the null terminator is not included.
+ */
+#ifdef HAS_IPV6
+# define MAI_HOSTADDR_STRSIZE INET6_ADDRSTRLEN
+#else
+# ifndef INET_ADDRSTRLEN
+# define INET_ADDRSTRLEN 16
+# endif
+# define MAI_HOSTADDR_STRSIZE INET_ADDRSTRLEN
+#endif
+
+#define MAI_HOSTNAME_STRSIZE 1025
+#define MAI_SERVNAME_STRSIZE 32
+#define MAI_SERVPORT_STRSIZE sizeof("65535")
+
+#define MAI_V4ADDR_BITS 32
+#define MAI_V6ADDR_BITS 128
+#define MAI_V4ADDR_BYTES ((MAI_V4ADDR_BITS + (CHAR_BIT - 1))/CHAR_BIT)
+#define MAI_V6ADDR_BYTES ((MAI_V6ADDR_BITS + (CHAR_BIT - 1))/CHAR_BIT)
+
+ /*
+ * Routines and data structures to hide some of the complexity of the
+ * addrinfo API. They still don't hide that we may get results for address
+ * families that we aren't interested in.
+ */
+typedef struct {
+ char buf[MAI_HOSTNAME_STRSIZE];
+} MAI_HOSTNAME_STR;
+
+typedef struct {
+ char buf[MAI_HOSTADDR_STRSIZE];
+} MAI_HOSTADDR_STR;
+
+typedef struct {
+ char buf[MAI_SERVNAME_STRSIZE];
+} MAI_SERVNAME_STR;
+
+typedef struct {
+ char buf[MAI_SERVPORT_STRSIZE];
+} MAI_SERVPORT_STR;
+
+extern int hostname_to_sockaddr(const char *, const char *, int,
+ struct addrinfo **);
+extern int hostaddr_to_sockaddr(const char *, const char *, int,
+ struct addrinfo **);
+extern int sockaddr_to_hostaddr(const struct sockaddr *, SOCKADDR_SIZE,
+ MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *, int);
+extern int sockaddr_to_hostname(const struct sockaddr *, SOCKADDR_SIZE,
+ MAI_HOSTNAME_STR *, MAI_SERVNAME_STR *, int);
+extern void myaddrinfo_control(int,...);
+
+#define MAI_CTL_END 0 /* list terminator */
+
+#define MAI_STRERROR(e) ((e) == EAI_SYSTEM ? strerror(errno) : gai_strerror(e))
+
+ /*
+ * Macros for the case where we really don't want to be bothered with things
+ * that may fail.
+ */
+#define HOSTNAME_TO_SOCKADDR(host, serv, sock, res) \
+ do { \
+ int _aierr; \
+ _aierr = hostname_to_sockaddr((host), (serv), (sock), (res)); \
+ if (_aierr) \
+ msg_fatal("hostname_to_sockaddr: %s", MAI_STRERROR(_aierr)); \
+ } while (0)
+
+#define HOSTADDR_TO_SOCKADDR(host, serv, sock, res) \
+ do { \
+ int _aierr; \
+ _aierr = hostaddr_to_sockaddr((host), (serv), (sock), (res)); \
+ if (_aierr) \
+ msg_fatal("hostaddr_to_sockaddr: %s", MAI_STRERROR(_aierr)); \
+ } while (0)
+
+#define SOCKADDR_TO_HOSTADDR(sa, salen, host, port, sock) \
+ do { \
+ int _aierr; \
+ _aierr = sockaddr_to_hostaddr((sa), (salen), (host), (port), (sock)); \
+ if (_aierr) \
+ msg_fatal("sockaddr_to_hostaddr: %s", MAI_STRERROR(_aierr)); \
+ } while (0)
+
+#define SOCKADDR_TO_HOSTNAME(sa, salen, host, service, sock) \
+ do { \
+ int _aierr; \
+ _aierr = sockaddr_to_hostname((sa), (salen), (host), (service), (sock)); \
+ if (_aierr) \
+ msg_fatal("sockaddr_to_hostname: %s", MAI_STRERROR(_aierr)); \
+ } while (0)
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
--- /dev/null
+./myaddrinfo: === hostname belly.porcupine.org ===
+./myaddrinfo: belly.porcupine.org -> family=28 sock=1 proto=6 2001:240:5c7:0:250:56ff:fe10:bd03
+./myaddrinfo: 2001:240:5c7:0:250:56ff:fe10:bd03 -> belly.porcupine.org
+./myaddrinfo: belly.porcupine.org -> family=2 sock=1 proto=6 168.100.189.6
+./myaddrinfo: 168.100.189.6 -> belly.porcupine.org
+./myaddrinfo: === host address 168.100.189.2 ===
+./myaddrinfo: 168.100.189.2 -> family=2 sock=1 proto=6 168.100.189.2
+./myaddrinfo: 168.100.189.2 -> spike.porcupine.org
--- /dev/null
+./myaddrinfo: === hostname null.porcupine.org ===
+./myaddrinfo: hostname_to_sockaddr(null.porcupine.org): No address associated with hostname
+./myaddrinfo: === host address 10.0.0.0 ===
+./myaddrinfo: 10.0.0.0 -> family=2 sock=1 proto=6 10.0.0.0
+./myaddrinfo: sockaddr_to_hostname: hostname nor servname provided, or not known
--- /dev/null
+./myaddrinfo4: === hostname belly.porcupine.org ===
+./myaddrinfo4: belly.porcupine.org -> family=2 sock=1 proto=6 168.100.189.6
+./myaddrinfo4: 168.100.189.6 -> belly.porcupine.org
+./myaddrinfo4: === host address 168.100.189.2 ===
+./myaddrinfo4: 168.100.189.2 -> family=2 sock=1 proto=6 168.100.189.2
+./myaddrinfo4: 168.100.189.2 -> spike.porcupine.org
--- /dev/null
+./myaddrinfo4: === hostname null.porcupine.org ===
+./myaddrinfo4: hostname2sockaddr(null.porcupine.org): No address associated with hostname
+./myaddrinfo4: === host address 10.0.0.0 ===
+./myaddrinfo4: 10.0.0.0 -> family=2 sock=1 proto=6 10.0.0.0
+./myaddrinfo4: sockaddr2hostname: hostname nor servname provided, or not known
return (STR(buf));
}
- /*
- * ABI backwards compatibility.
- */
-#undef name_mask
-#undef str_name_mask
-
-int name_mask(const char *context, NAME_MASK *table, const char *names)
-{
- return(name_mask_opt(context, table,names, NAME_MASK_DEFAULT));
-}
-
-const char *str_name_mask(const char *context, NAME_MASK *table, int mask)
-{
- return(str_name_mask_opt(context, table, mask, NAME_MASK_DEFAULT));
-}
-
#ifdef TEST
/*
--- /dev/null
+/*++
+/* NAME
+/* sock_addr 3
+/* SUMMARY
+/* sockaddr utilities
+/* SYNOPSIS
+/* #include <sock_addr.h>
+/*
+/* int sock_addr_cmp_addr(sa, sb)
+/* const struct sockaddr *sa;
+/* const struct sockaddr *sb;
+/*
+/* int sock_addr_cmp_port(sa, sb)
+/* const struct sockaddr *sa;
+/* const struct sockaddr *sb;
+/*
+/* int SOCK_ADDR_EQ_ADDR(sa, sb)
+/* const struct sockaddr *sa;
+/* const struct sockaddr *sb;
+/*
+/* int SOCK_ADDR_EQ_PORT(sa, sb)
+/* const struct sockaddr *sa;
+/* const struct sockaddr *sb;
+/*
+/* int sock_addr_in_loopback(sa)
+/* const struct sockaddr *sa;
+/* AUXILIARY MACROS
+/* struct sockaddr *SOCK_ADDR_PTR(ptr)
+/* unsigned char SOCK_ADDR_FAMILY(ptr)
+/* unsigned char SOCK_ADDR_LEN(ptr)
+/*
+/* struct sockaddr_in *SOCK_ADDR_IN_PTR(ptr)
+/* unsigned char SOCK_ADDR_IN_FAMILY(ptr)
+/* unsigned short SOCK_ADDR_IN_PORT(ptr)
+/* struct in_addr SOCK_ADDR_IN_ADDR(ptr)
+/* struct in_addr IN_ADDR(ptr)
+/*
+/* struct sockaddr_in6 *SOCK_ADDR_IN6_PTR(ptr)
+/* unsigned char SOCK_ADDR_IN6_FAMILY(ptr)
+/* unsigned short SOCK_ADDR_IN6_PORT(ptr)
+/* struct in6_addr SOCK_ADDR_IN6_ADDR(ptr)
+/* struct in6_addr IN6_ADDR(ptr)
+/* DESCRIPTION
+/* These utilities take protocol-independent address structures
+/* and perform protocol-dependent operations on structure members.
+/* Some of the macros described here are called unsafe,
+/* because they evaluate one or more arguments multiple times.
+/*
+/* sock_addr_cmp_addr() or sock_addr_cmp_port() compare the
+/* address family and network address or port fields for
+/* equality, and return indication of the difference between
+/* their arguments: < 0 if the first argument is "smaller",
+/* 0 for equality, and > 0 if the first argument is "larger".
+/*
+/* The unsafe macros SOCK_ADDR_EQ_ADDR() or SOCK_ADDR_EQ_PORT()
+/* compare compare the address family and network address or
+/* port fields for equality, and return non-zero when their
+/* arguments differ.
+/*
+/* sock_addr_in_loopback() determines if the argument specifies
+/* a loopback address.
+/*
+/* The SOCK_ADDR_PTR() macro casts a generic pointer to (struct
+/* sockaddr *). The name is upper case for consistency not
+/* safety. SOCK_ADDR_FAMILY() and SOCK_ADDR_LEN() return the
+/* address family and length of the real structure that hides
+/* inside a generic sockaddr structure. On systems where struct
+/* sockaddr has no sa_len member, SOCK_ADDR_LEN() cannot be
+/* used as lvalue.
+/*
+/* The macros SOCK_ADDR_IN{,6}_{PTR,FAMILY,PORT,ADDR}() cast
+/* a generic pointer to a specific socket address structure
+/* pointer, or access a specific socket address structure
+/* member. These can be used as lvalues.
+/*
+/* The unsafe INADDR() and IN6_ADDR() macros dereference a
+/* generic pointer to a specific address structure.
+/* DIAGNOSTICS
+/* Panic: unsupported address family.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <sock_addr.h>
+
+/* sock_addr_cmp_addr - compare addresses for equality */
+
+int sock_addr_cmp_addr(const struct sockaddr * sa,
+ const struct sockaddr * sb)
+{
+ if (sa->sa_family != sb->sa_family)
+ return (sa->sa_family - sb->sa_family);
+
+ /*
+ * With IPv6 address structures, assume a non-hostile implementation that
+ * stores the address as a contiguous sequence of bits. Any holes in the
+ * sequence would invalidate the use of memcmp().
+ */
+ if (sa->sa_family == AF_INET) {
+ return (SOCK_ADDR_IN_ADDR(sa).s_addr - SOCK_ADDR_IN_ADDR(sb).s_addr);
+#ifdef HAS_IPV6
+ } else if (sa->sa_family == AF_INET6) {
+ return (memcmp((char *) &(SOCK_ADDR_IN6_ADDR(sa)),
+ (char *) &(SOCK_ADDR_IN6_ADDR(sb)),
+ sizeof(SOCK_ADDR_IN6_ADDR(sa))));
+#endif
+ } else {
+ msg_panic("sock_addr_cmp_addr: unsupported address family %d",
+ sa->sa_family);
+ }
+}
+
+/* sock_addr_cmp_port - compare ports for equality */
+
+int sock_addr_cmp_port(const struct sockaddr * sa,
+ const struct sockaddr * sb)
+{
+ if (sa->sa_family != sb->sa_family)
+ return (sa->sa_family - sb->sa_family);
+
+ if (sa->sa_family == AF_INET) {
+ return (SOCK_ADDR_IN_PORT(sa) - SOCK_ADDR_IN_PORT(sb));
+#ifdef HAS_IPV6
+ } else if (sa->sa_family == AF_INET6) {
+ return (SOCK_ADDR_IN6_PORT(sa) - SOCK_ADDR_IN6_PORT(sb));
+#endif
+ } else {
+ msg_panic("sock_addr_cmp_port: unsupported address family %d",
+ sa->sa_family);
+ }
+}
+
+/* sock_addr_in_loopback - determine if address is loopback */
+
+int sock_addr_in_loopback(const struct sockaddr * sa)
+{
+ unsigned long inaddr;
+
+ if (sa->sa_family == AF_INET) {
+ inaddr = ntohl(SOCK_ADDR_IN_ADDR(sa).s_addr);
+ return (IN_CLASSA(inaddr)
+ && ((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT)
+ == IN_LOOPBACKNET);
+#ifdef HAS_IPV6
+ } else if (sa->sa_family == AF_INET6) {
+ return (IN6_IS_ADDR_LOOPBACK(&SOCK_ADDR_IN6_ADDR(sa)));
+#endif
+ } else {
+ msg_panic("sock_addr_in_loopback: unsupported address family %d",
+ sa->sa_family);
+ }
+}
--- /dev/null
+#ifndef _SOCK_ADDR_EQ_H_INCLUDED_
+#define _SOCK_ADDR_EQ_H_INCLUDED_
+
+/*++
+/* NAME
+/* sock_addr 3h
+/* SUMMARY
+/* socket address utilities
+/* SYNOPSIS
+/* #include <sock_addr.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * System library.
+ */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+
+ /*
+ * External interface.
+ */
+#define SOCK_ADDR_PTR(ptr) ((struct sockaddr *)(ptr))
+#define SOCK_ADDR_FAMILY(ptr) SOCK_ADDR_PTR(ptr)->sa_family
+#ifdef HAS_SA_LEN
+#define SOCK_ADDR_LEN(ptr) SOCK_ADDR_PTR(ptr)->sa_len
+#endif
+
+#define SOCK_ADDR_IN_PTR(sa) ((struct sockaddr_in *)(sa))
+#define SOCK_ADDR_IN_FAMILY(sa) SOCK_ADDR_IN_PTR(sa)->sin_family
+#define SOCK_ADDR_IN_PORT(sa) SOCK_ADDR_IN_PTR(sa)->sin_port
+#define SOCK_ADDR_IN_ADDR(sa) SOCK_ADDR_IN_PTR(sa)->sin_addr
+#define IN_ADDR(ia) (*((struct in_addr *) (ia)))
+
+extern int sock_addr_cmp_addr(const struct sockaddr *, const struct sockaddr *);
+extern int sock_addr_cmp_port(const struct sockaddr *, const struct sockaddr *);
+extern int sock_addr_in_loopback(const struct sockaddr *);
+
+#ifdef HAS_IPV6
+
+#ifndef HAS_SA_LEN
+#define SOCK_ADDR_LEN(sa) \
+ (SOCK_ADDR_PTR(sa)->sa_family == AF_INET6 ? \
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
+#endif
+
+#define SOCK_ADDR_IN6_PTR(sa) ((struct sockaddr_in6 *)(sa))
+#define SOCK_ADDR_IN6_FAMILY(sa) SOCK_ADDR_IN6_PTR(sa)->sin6_family
+#define SOCK_ADDR_IN6_PORT(sa) SOCK_ADDR_IN6_PTR(sa)->sin6_port
+#define SOCK_ADDR_IN6_ADDR(sa) SOCK_ADDR_IN6_PTR(sa)->sin6_addr
+#define IN6_ADDR(ia) (*((struct in6_addr *) (ia)))
+
+#define SOCK_ADDR_EQ_ADDR(sa, sb) \
+ ((SOCK_ADDR_FAMILY(sa) == AF_INET && SOCK_ADDR_FAMILY(sb) == AF_INET \
+ && SOCK_ADDR_IN_ADDR(sa).s_addr == SOCK_ADDR_IN_ADDR(sb).s_addr) \
+ || (SOCK_ADDR_FAMILY(sa) == AF_INET6 && SOCK_ADDR_FAMILY(sb) == AF_INET6 \
+ && memcmp((char *) &(SOCK_ADDR_IN6_ADDR(sa)), \
+ (char *) &(SOCK_ADDR_IN6_ADDR(sb)), \
+ sizeof(SOCK_ADDR_IN6_ADDR(sa))) == 0))
+
+#define SOCK_ADDR_EQ_PORT(sa, sb) \
+ ((SOCK_ADDR_FAMILY(sa) == AF_INET && SOCK_ADDR_FAMILY(sb) == AF_INET \
+ && SOCK_ADDR_IN_PORT(sa) == SOCK_ADDR_IN_PORT(sb)) \
+ || (SOCK_ADDR_FAMILY(sa) == AF_INET6 && SOCK_ADDR_FAMILY(sb) == AF_INET6 \
+ && SOCK_ADDR_IN6_PORT(sa) == SOCK_ADDR_IN6_PORT(sb)))
+
+#else
+
+#ifndef HAS_SA_LEN
+#define SOCK_ADDR_LEN(sa) sizeof(struct sockaddr_in)
+#endif
+
+#define SOCK_ADDR_EQ_ADDR(sa, sb) \
+ (SOCK_ADDR_FAMILY(sa) == AF_INET && SOCK_ADDR_FAMILY(sb) == AF_INET \
+ && SOCK_ADDR_IN_ADDR(sa).s_addr == SOCK_ADDR_IN_ADDR(sb).s_addr)
+
+#define SOCK_ADDR_EQ_PORT(sa, sb) \
+ (SOCK_ADDR_FAMILY(sa) == AF_INET && SOCK_ADDR_FAMILY(sb) == AF_INET \
+ && SOCK_ADDR_IN_PORT(sa) == SOCK_ADDR_IN_PORT(sb))
+
+#endif
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
if (stream_send_fd(server_sock, client_fd) < 0)
msg_fatal("send file descriptor: %m");
if (close(client_fd) != 0)
- msg_fatal("close(%d): %m");
+ msg_fatal("close(%d): %m", client_fd);
}
exit(0);
}
/* int setsid()
/*
/* void dup2_pass_on_exec(int oldd, int newd)
+/*
+/* char *inet_ntop(af, src, dst, size)
+/* int af;
+/* const void *src;
+/* char *dst;
+/* size_t size;
+/*
+/* int inet_pton(af, src, dst)
+/* int af;
+/* const char *src;
+/* void *dst;
/* DESCRIPTION
/* These routines are compiled for platforms that lack the functionality
/* or that have broken versions that we prefer to stay away from.
#ifndef HAS_CLOSEFROM
+#include <unistd.h>
#include <errno.h>
+#include <iostuff.h>
/* closefrom() - closes all file descriptors from the given one up */
}
#endif
+
+#ifdef MISSING_INET_NTOP
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* inet_ntop - convert binary address to printable address */
+
+const char *inet_ntop(int af, const void *src, char *dst, size_t size)
+{
+ const unsigned char *addr;
+ char buffer[sizeof("255.255.255.255")];
+ int len;
+
+ if (af != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return (0);
+ }
+ addr = (const unsigned char *) src;
+#if (CHAR_BIT > 8)
+ sprintf(buffer, "%d.%d.%d.%d", addr[0] & 0xff,
+ addr[1] & 0xff, addr[2] & 0xff, addr[3] & 0xff);
+#else
+ sprintf(buffer, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
+#endif
+ if ((len = strlen(buffer)) >= size) {
+ errno = ENOSPC;
+ return (0);
+ } else {
+ memcpy(dst, buffer, len + 1);
+ return (dst);
+ }
+}
+
+#endif
+
+#ifdef MISSING_INET_PTON
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <errno.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+/* inet_pton - convert printable address to binary address */
+
+int inet_pton(int af, const char *src, void *dst)
+{
+ struct in_addr addr;
+
+ /*
+ * inet_addr() accepts a wider range of input formats than inet_pton();
+ * the former accepts 1-, 2-, or 3-part dotted addresses, while the
+ * latter requires dotted quad form.
+ */
+ if (af != AF_INET) {
+ errno = EAFNOSUPPORT;
+ return (-1);
+ } else if ((addr.s_addr = inet_addr(src)) == INADDR_NONE
+ && strcmp(src, "255.255.255.255") != 0) {
+ return (0);
+ } else {
+ memcpy(dst, (char *) &addr, sizeof(addr));
+ return (1);
+ }
+}
+
+#endif
#define NATIVE_DAEMON_DIR "/usr/libexec/postfix"
#endif
+#ifdef BSDI4
+/* #define HAS_IPV6 find out interface lookup method */
+#endif
+
/* __FreeBSD_version version is major+minor */
#if __FreeBSD_version >= 200000
#define HAS_DEV_URANDOM /* XXX probably earlier */
#endif
-#if __NetBSD_Version__ >= 105000000 /* XXX maybe earlier */
-#define HAS_ISSETUGID
+#if __NetBSD_Version__ >= 105000000
+#define HAS_ISSETUGID /* XXX maybe earlier */
#endif
#if __NetBSD_Version__ >= 106000000 /* XXX maybe earlier */
#if __NetBSD_Version__ >= 200060000 /* 2.0F */
#define HAS_CLOSEFROM
+#endif
+
+#if (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 105000000) \
+ || (defined(__FreeBSD__) && __FreeBSD__ >= 4) \
+ || (defined(OpenBSD) && OpenBSD >= 200003) \
+ || defined(USAGI_LIBINET6)
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAVE_GETIFADDRS
+#endif
+
#endif
/*
#define PRINTFLIKE(x,y)
#define SCANFLIKE(x,y)
#ifndef NO_NETINFO
-#define HAS_NETINFO
+# define HAS_NETINFO
+#endif
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAVE_GETIFADDRS
#endif
#define NATIVE_SENDMAIL_PATH "/usr/sbin/sendmail"
#define NATIVE_MAILQ_PATH "/usr/bin/mailq"
#define STATFS_IN_SYS_MOUNT_H
#define HAS_POSIX_REGEXP
#define BROKEN_WRITE_SELECT_ON_NON_BLOCKING_PIPE
+#ifndef NO_IPV6
+# define HAS_IPV6
+#endif
+
#endif
/*
#define FIONREAD_IN_SYS_FILIO_H
#define USE_STATVFS
#define STATVFS_IN_SYS_STATVFS_H
+#define INT_MAX_IN_LIMITS_H
#define STREAM_CONNECTIONS /* avoid UNIX-domain sockets */
#define LOCAL_LISTEN stream_listen
#define LOCAL_ACCEPT stream_accept
#define LOCAL_RECV_FD stream_recv_fd
#define HAS_VOLATILE_LOCKS
#define BROKEN_READ_SELECT_ON_TCP_SOCKET
+#define CANT_WRITE_BEFORE_SENDING_FD
+#ifndef NO_POSIX_REGEXP
+# define HAS_POSIX_REGEXP
+#endif
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAS_SIOCGLIF
+#endif
+#ifndef NO_CLOSEFROM
+# define HAS_CLOSEFROM
+#endif
/*
* Allow build environment to override paths.
#ifndef CMSG_LEN
#define CMSG_LEN(len) (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif
-
+#ifndef NO_IPV6
+# define HAS_IPV6
+#endif
+#define BROKEN_AI_PASSIVE_NULL_HOST
#endif
#ifdef AIX4
#define SOCKADDR_SIZE socklen_t
#define SOCKOPT_SIZE socklen_t
#endif
+#ifndef NO_IPV6
+# define HAS_IPV6
+# define HAS_PROCNET_IFINET6
+# define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
+#endif
#include <linux/version.h>
#if !defined(KERNEL_VERSION) || (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)) \
|| (__GLIBC__ < 2)
#if !defined(USE_STATFS) && !defined(USE_STATVFS)
#error "define USE_STATFS or USE_STATVFS"
+#endif
+
+ /*
+ * Defaults for systems that pre-date IPv6 support.
+ */
+#ifndef HAS_IPV6
+#define EMULATE_IPV4_ADDRINFO
+#define MISSING_INET_PTON
+#define MISSING_INET_NTOP
+extern const char *inet_ntop(int, const void *, char *, size_t);
+extern int inet_pton(int, const char *, void *);
+
+#endif
+
+ /*
+ * Defaults for all systems.
+ */
+#ifndef DEF_INET_PROTOCOLS
+#define DEF_INET_PROTOCOLS "ipv4"
#endif
/*
/* const char *addr;
/* int gripe;
/*
-/* int valid_hostliteral(addr, gripe)
+/* int valid_ipv4_hostaddr(addr, gripe)
+/* const char *addr;
+/* int gripe;
+/*
+/* int valid_ipv6_hostaddr(addr, gripe)
/* const char *addr;
/* int gripe;
/* DESCRIPTION
-/* valid_hostname() scrutinizes a hostname: the name should be no
-/* longer than VALID_HOSTNAME_LEN characters, should contain only
-/* letters, digits, dots and hyphens, no adjacent dots and hyphens,
-/* no leading or trailing dots or hyphens, no labels longer than
-/* VALID_LABEL_LEN characters, and no numeric top-level domain.
+/* valid_hostname() scrutinizes a hostname: the name should
+/* be no longer than VALID_HOSTNAME_LEN characters, should
+/* contain only letters, digits, dots and hyphens, no adjacent
+/* dots and hyphens, no leading or trailing dots or hyphens,
+/* no labels longer than VALID_LABEL_LEN characters, and it
+/* should not be all numeric.
/*
/* valid_hostaddr() requires that the input is a valid string
-/* representation of an internet network address.
+/* representation of an IPv4 or IPv6 network address as
+/* described next.
/*
-/* valid_hostliteral() requires an address enclosed in [].
+/* valid_ipv4_hostaddr() and valid_ipv6_hostaddr() implement
+/* protocol-specific address syntax checks. A valid IPv4
+/* address is in dotted-quad decimal form. A valid IPv6 address
+/* has 16-bit hexadecimal fields separated by ":", and does not
+/* include the RFC 2821 style "IPv6:" prefix.
/*
/* These routines operate silently unless the gripe parameter
/* specifies a non-zero value. The macros DO_GRIPE and DONT_GRIPE
/* provide suitable constants.
/* DIAGNOSTICS
-/* Both functions return zero if they disagree with the input.
+/* All functions return zero if they disagree with the input.
/* SEE ALSO
-/* RFC 952, 1123, RFC 1035
+/* RFC 952, RFC 1123, RFC 1035, RFC 2373.
/* LICENSE
/* .ad
/* .fi
msg_warn("%s: misplaced hyphen: %.100s", myname, name);
return (0);
}
- } else {
+ }
+#ifdef SLOPPY_VALID_HOSTNAME
+ else if (ch == ':' && valid_ipv6_hostaddr(name, DONT_GRIPE)) {
+ non_numeric = 0;
+ break;
+ }
+#endif
+ else {
if (gripe)
msg_warn("%s: invalid character %d(decimal): %.100s",
myname, ch, name);
if (non_numeric == 0) {
if (gripe)
msg_warn("%s: numeric hostname: %.100s", myname, name);
- /* NOT: return (0); this confuses users of the DNS client */
+#ifndef SLOPPY_VALID_HOSTNAME
+ return (0);
+#endif
}
if (cp - name > VALID_HOSTNAME_LEN) {
if (gripe)
return (1);
}
-/* valid_hostaddr - test dotted quad string for correctness */
+/* valid_hostaddr - verify numerical address syntax */
int valid_hostaddr(const char *addr, int gripe)
{
- const char *cp;
- char *myname = "valid_hostaddr";
- int in_byte = 0;
- int byte_count = 0;
- int byte_val = 0;
- int ch;
-
-#define BYTES_NEEDED 4
+ const char *myname = "valid_hostaddr";
/*
* Trivial cases first.
}
/*
- * Preliminary IPV6 support.
+ * Protocol-dependent processing next.
*/
- if (strchr(addr, ':')) {
- if (*(cp = addr + strspn(addr, ":./0123456789abcdefABCDEF")) != 0) {
- if (gripe)
- msg_warn("%s: invalid character %d(decimal): %.100s",
- myname, *cp, addr);
- return (0);
- }
- return (1);
- }
+ if (strchr(addr, ':') != 0)
+ return (valid_ipv6_hostaddr(addr, gripe));
+ else
+ return (valid_ipv4_hostaddr(addr, gripe));
+}
+
+/* valid_ipv4_hostaddr - test dotted quad string for correctness */
+
+int valid_ipv4_hostaddr(const char *addr, int gripe)
+{
+ const char *cp;
+ char *myname = "valid_ipv4_hostaddr";
+ int in_byte = 0;
+ int byte_count = 0;
+ int byte_val = 0;
+ int ch;
+
+#define BYTES_NEEDED 4
/*
* Scary code to avoid sscanf() overflow nasties.
+ *
+ * This routine is called by valid_ipv6_hostaddr(). It must not call that
+ * routine, to avoid deadly recursion.
*/
for (cp = addr; (ch = *(unsigned const char *) cp) != 0; cp++) {
if (ISDIGIT(ch)) {
msg_warn("%s: misplaced dot: %.100s", myname, addr);
return (0);
}
- if ((byte_count == 1 && byte_val == 0)) {
+ /* XXX Allow 0.0.0.0 but not 0.1.2.3 */
+ if (byte_count == 1 && byte_val == 0 && addr[strspn(addr, "0.")]) {
if (gripe)
msg_warn("%s: bad initial octet value: %.100s", myname, addr);
return (0);
return (1);
}
-/* valid_hostliteral - validate address literal */
+/* valid_ipv6_hostaddr - validate IPv6 address syntax */
-int valid_hostliteral(const char *addr, int gripe)
+int valid_ipv6_hostaddr(const char *addr, int gripe)
{
- const char *myname = "valid_hostliteral";
- char buf[100];
- const char *last;
+ const char *myname = "valid_ipv6_hostaddr";
+ int null_field = 0;
+ int field = 0;
+ unsigned char *cp = (unsigned char *) addr;
+ int len = 0;
- if (*addr != '[') {
- if (gripe)
- msg_warn("%s: '[' expected at start: %.100s", myname, addr);
- return (0);
- }
- if ((last = strchr(addr, ']')) == 0) {
- if (gripe)
- msg_warn("%s: ']' expected at end: %.100s", myname, addr);
- return (0);
- }
- if (last[1]) {
- if (gripe)
- msg_warn("%s: unexpected text after ']': %.100s", myname, addr);
- return (0);
- }
- if (last >= addr + sizeof(buf)) {
- if (gripe)
- msg_warn("%s: too much text: %.100s", myname, addr);
- return (0);
+ /*
+ * FIX 200501 The IPv6 patch validated syntax with getaddrinfo(), but I
+ * am not confident that everyone's system library routines are robust
+ * enough, like buffer overflow free. Remember, the valid_hostmumble()
+ * routines are meant to protect Postfix against malformed information
+ * in data received from the network.
+ *
+ * We require eight-field hex addresses of the form 0:1:2:3:4:5:6:7,
+ * 0:1:2:3:4:5:6a.6b.7c.7d, or some :: compressed version of the same.
+ *
+ * Note: the character position is advanced inside the loop. I have added
+ * comments to show why we can't get stuck.
+ */
+ for (;;) {
+ switch (*cp) {
+ case 0:
+ /* Terminate the loop. */
+ if (field < 2) {
+ if (gripe)
+ msg_warn("%s: too few `:' in IPv6 address: %.100s",
+ myname, addr);
+ return (0);
+ } else if (len == 0 && null_field != field - 1) {
+ if (gripe)
+ msg_warn("%s: bad null last field in IPv6 address: %.100s",
+ myname, addr);
+ return (0);
+ } else
+ return (1);
+ case '.':
+ /* Terminate the loop. */
+ if (field < 2 || field > 6) {
+ if (gripe)
+ msg_warn("%s: malformed IPv4-in-IPv6 address: %.100s",
+ myname, addr);
+ return (0);
+ } else
+ /* NOT: valid_hostaddr(). Avoid recursion. */
+ return (valid_ipv4_hostaddr((char *) cp - len, gripe));
+ case ':':
+ /* Advance by exactly 1 character position or terminate. */
+ if (field == 0 && len == 0 && ISALNUM(cp[1])) {
+ if (gripe)
+ msg_warn("%s: bad null first field in IPv6 address: %.100s",
+ myname, addr);
+ return (0);
+ }
+ field++;
+ if (field > 7) {
+ if (gripe)
+ msg_warn("%s: too many `:' in IPv6 address: %.100s",
+ myname, addr);
+ return (0);
+ }
+ cp++;
+ len = 0;
+ if (*cp == ':') {
+ if (null_field > 0) {
+ if (gripe)
+ msg_warn("%s: too many `::' in IPv6 address: %.100s",
+ myname, addr);
+ return (0);
+ }
+ null_field = field;
+ }
+ break;
+ default:
+ /* Advance by at least 1 character position or terminate. */
+ len = strspn(cp, "0123456789abcdefABCDEF");
+ if (len /* - strspn(cp, "0") */ > 4) {
+ if (gripe)
+ msg_warn("%s: malformed IPv6 address: %.100s",
+ myname, addr);
+ return (0);
+ }
+ if (len <= 0) {
+ if (gripe)
+ msg_warn("%s: invalid character %d(decimal) in IPv6 address: %.100s",
+ myname, *cp, addr);
+ return (0);
+ }
+ cp += len;
+ break;
+ }
}
- strncpy(buf, addr + 1, last - addr - 1);
- buf[last - addr - 1] = 0;
- return (valid_hostaddr(buf, gripe));
}
#ifdef TEST
msg_info("testing: \"%s\"", vstring_str(buffer));
valid_hostname(vstring_str(buffer), DO_GRIPE);
valid_hostaddr(vstring_str(buffer), DO_GRIPE);
- valid_hostliteral(vstring_str(buffer), DO_GRIPE);
}
exit(0);
}
extern int valid_hostname(const char *, int);
extern int valid_hostaddr(const char *, int);
-extern int valid_hostliteral(const char *, int);
+extern int valid_ipv4_hostaddr(const char *, int);
+extern int valid_ipv6_hostaddr(const char *, int);
/* LICENSE
/* .ad
a.b.-bb
a.b.bb-
a-a.b-b
-[1.2.3.4]
-[321.255.255.255]
-[1.2.3.4
-[1.2.3.4]foo
-[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
-[a:a:a:a:a:a:a:a]
-[g:a:a:a:a:a:a:a]
+:
+::
+:::
+a::
+::a
+::1.2.3.4
+a:a:a:a:a:1.2.3.4
+a:a:a:a:a:a:1.2.3.4
+a:a:a:a:a:a:a:1.2.3.4
+a:a:a:a:a:a:1.2.3.
+a:a:a:a:a:a:1.2.3
+a:a:a:a:a:a:a:a
+a:a:a:a:a:a:a:a:a
+g:a:a:a:a:a:a:a
+a::b
+:a::b
+a::b:
./valid_hostname: testing: "123456789012345678901234567890123456789012345678901234567890123"
./valid_hostname: warning: valid_hostname: numeric hostname: 123456789012345678901234567890123456789012345678901234567890123
-./valid_hostname: warning: valid_hostaddr: invalid octet value: 123456789012345678901234567890123456789012345678901234567890123
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 123456789012345678901234567890123456789012345678901234567890123
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet value: 123456789012345678901234567890123456789012345678901234567890123
./valid_hostname: testing: "1234567890123456789012345678901234567890123456789012345678901234"
./valid_hostname: warning: valid_hostname: hostname label too long: 1234567890123456789012345678901234567890123456789012345678901234
-./valid_hostname: warning: valid_hostaddr: invalid octet value: 1234567890123456789012345678901234567890123456789012345678901234
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1234567890123456789012345678901234567890123456789012345678901234
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet value: 1234567890123456789012345678901234567890123456789012345678901234
./valid_hostname: testing: "a.123456789012345678901234567890123456789012345678901234567890123.b"
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.123456789012345678901234567890123456789012345678901234567890123.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.123456789012345678901234567890123456789012345678901234567890123.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.123456789012345678901234567890123456789012345678901234567890123.b
./valid_hostname: testing: "a.1234567890123456789012345678901234567890123456789012345678901234.b"
./valid_hostname: warning: valid_hostname: hostname label too long: a.1234567890123456789012345678901234567890123456789012345678901234.b
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.1234567890123456789012345678901234567890123456789012345678901234.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.1234567890123456789012345678901234567890123456789012345678901234.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.1234567890123456789012345678901234567890123456789012345678901234.b
./valid_hostname: testing: "1.2.3.4"
./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4
./valid_hostname: testing: "321.255.255.255"
./valid_hostname: warning: valid_hostname: numeric hostname: 321.255.255.255
-./valid_hostname: warning: valid_hostaddr: invalid octet value: 321.255.255.255
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 321.255.255.255
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet value: 321.255.255.255
./valid_hostname: testing: "0.0.0.0"
./valid_hostname: warning: valid_hostname: numeric hostname: 0.0.0.0
-./valid_hostname: warning: valid_hostaddr: bad initial octet value: 0.0.0.0
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 0.0.0.0
./valid_hostname: testing: "255.255.255.255"
./valid_hostname: warning: valid_hostname: numeric hostname: 255.255.255.255
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 255.255.255.255
./valid_hostname: testing: "0.255.255.255"
./valid_hostname: warning: valid_hostname: numeric hostname: 0.255.255.255
-./valid_hostname: warning: valid_hostaddr: bad initial octet value: 0.255.255.255
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 0.255.255.255
+./valid_hostname: warning: valid_ipv4_hostaddr: bad initial octet value: 0.255.255.255
./valid_hostname: testing: "1.2.3.321"
./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.321
-./valid_hostname: warning: valid_hostaddr: invalid octet value: 1.2.3.321
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.321
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet value: 1.2.3.321
./valid_hostname: testing: "1.2.3"
./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3
-./valid_hostname: warning: valid_hostaddr: invalid octet count: 1.2.3
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet count: 1.2.3
./valid_hostname: testing: "1.2.3.4.5"
./valid_hostname: warning: valid_hostname: numeric hostname: 1.2.3.4.5
-./valid_hostname: warning: valid_hostaddr: invalid octet count: 1.2.3.4.5
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4.5
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet count: 1.2.3.4.5
./valid_hostname: testing: "1..2.3.4"
./valid_hostname: warning: valid_hostname: misplaced delimiter: 1..2.3.4
-./valid_hostname: warning: valid_hostaddr: misplaced dot: 1..2.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1..2.3.4
+./valid_hostname: warning: valid_ipv4_hostaddr: misplaced dot: 1..2.3.4
./valid_hostname: testing: ".1.2.3.4"
./valid_hostname: warning: valid_hostname: misplaced delimiter: .1.2.3.4
-./valid_hostname: warning: valid_hostaddr: misplaced dot: .1.2.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: .1.2.3.4
+./valid_hostname: warning: valid_ipv4_hostaddr: misplaced dot: .1.2.3.4
./valid_hostname: testing: "1.2.3.4.5."
./valid_hostname: warning: valid_hostname: misplaced delimiter: 1.2.3.4.5.
-./valid_hostname: warning: valid_hostaddr: misplaced dot: 1.2.3.4.5.
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4.5.
+./valid_hostname: warning: valid_ipv4_hostaddr: misplaced dot: 1.2.3.4.5.
./valid_hostname: testing: "1"
./valid_hostname: warning: valid_hostname: numeric hostname: 1
-./valid_hostname: warning: valid_hostaddr: invalid octet count: 1
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet count: 1
./valid_hostname: testing: "."
./valid_hostname: warning: valid_hostname: misplaced delimiter: .
-./valid_hostname: warning: valid_hostaddr: misplaced dot: .
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: .
+./valid_hostname: warning: valid_ipv4_hostaddr: misplaced dot: .
./valid_hostname: testing: ""
./valid_hostname: warning: valid_hostname: empty hostname
./valid_hostname: warning: valid_hostaddr: empty address
-./valid_hostname: warning: valid_hostliteral: '[' expected at start:
./valid_hostname: testing: "321"
./valid_hostname: warning: valid_hostname: numeric hostname: 321
-./valid_hostname: warning: valid_hostaddr: invalid octet value: 321
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 321
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet value: 321
./valid_hostname: testing: "f"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: f
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): f
./valid_hostname: testing: "f.2.3.4"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f.2.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: f.2.3.4
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): f.2.3.4
./valid_hostname: testing: "1f.2.3.4"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1f.2.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1f.2.3.4
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): 1f.2.3.4
./valid_hostname: testing: "f1.2.3.4"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): f1.2.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: f1.2.3.4
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): f1.2.3.4
./valid_hostname: testing: "1.2f.3.4"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2f.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2f.3.4
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): 1.2f.3.4
./valid_hostname: testing: "1.f2.3.4"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.f2.3.4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.f2.3.4
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): 1.f2.3.4
./valid_hostname: testing: "1.2.3.4f"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.4f
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.4f
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): 1.2.3.4f
./valid_hostname: testing: "1.2.3.f4"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f4
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.f4
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): 1.2.3.f4
./valid_hostname: testing: "1.2.3.f"
-./valid_hostname: warning: valid_hostaddr: invalid character 102(decimal): 1.2.3.f
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: 1.2.3.f
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 102(decimal): 1.2.3.f
./valid_hostname: testing: "-.a.b"
./valid_hostname: warning: valid_hostname: misplaced hyphen: -.a.b
-./valid_hostname: warning: valid_hostaddr: invalid character 45(decimal): -.a.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: -.a.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 45(decimal): -.a.b
./valid_hostname: testing: "a.-.b"
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.-.b
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.-.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.-.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.-.b
./valid_hostname: testing: "a.b.-"
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.-
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.-
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.b.-
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.b.-
./valid_hostname: testing: "-aa.b.b"
./valid_hostname: warning: valid_hostname: misplaced hyphen: -aa.b.b
-./valid_hostname: warning: valid_hostaddr: invalid character 45(decimal): -aa.b.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: -aa.b.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 45(decimal): -aa.b.b
./valid_hostname: testing: "aa-.b.b"
./valid_hostname: warning: valid_hostname: misplaced hyphen: aa-.b.b
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): aa-.b.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: aa-.b.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): aa-.b.b
./valid_hostname: testing: "a.-bb.b"
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.-bb.b
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.-bb.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.-bb.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.-bb.b
./valid_hostname: testing: "a.bb-.b"
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.bb-.b
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.bb-.b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.bb-.b
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.bb-.b
./valid_hostname: testing: "a.b.-bb"
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.-bb
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.-bb
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.b.-bb
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.b.-bb
./valid_hostname: testing: "a.b.bb-"
./valid_hostname: warning: valid_hostname: misplaced hyphen: a.b.bb-
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a.b.bb-
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a.b.bb-
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a.b.bb-
./valid_hostname: testing: "a-a.b-b"
-./valid_hostname: warning: valid_hostaddr: invalid character 97(decimal): a-a.b-b
-./valid_hostname: warning: valid_hostliteral: '[' expected at start: a-a.b-b
-./valid_hostname: testing: "[1.2.3.4]"
-./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [1.2.3.4]
-./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [1.2.3.4]
-./valid_hostname: testing: "[321.255.255.255]"
-./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [321.255.255.255]
-./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [321.255.255.255]
-./valid_hostname: warning: valid_hostaddr: invalid octet value: 321.255.255.255
-./valid_hostname: testing: "[1.2.3.4"
-./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [1.2.3.4
-./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [1.2.3.4
-./valid_hostname: warning: valid_hostliteral: ']' expected at end: [1.2.3.4
-./valid_hostname: testing: "[1.2.3.4]foo"
-./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [1.2.3.4]foo
-./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [1.2.3.4]foo
-./valid_hostname: warning: valid_hostliteral: unexpected text after ']': [1.2.3.4]foo
-./valid_hostname: testing: "[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]"
-./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-./valid_hostname: warning: valid_hostliteral: too much text: [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-./valid_hostname: testing: "[a:a:a:a:a:a:a:a]"
-./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [a:a:a:a:a:a:a:a]
-./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [a:a:a:a:a:a:a:a]
-./valid_hostname: testing: "[g:a:a:a:a:a:a:a]"
-./valid_hostname: warning: valid_hostname: invalid character 91(decimal): [g:a:a:a:a:a:a:a]
-./valid_hostname: warning: valid_hostaddr: invalid character 91(decimal): [g:a:a:a:a:a:a:a]
-./valid_hostname: warning: valid_hostaddr: invalid character 103(decimal): g:a:a:a:a:a:a:a
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid character 97(decimal): a-a.b-b
+./valid_hostname: testing: ":"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): :
+./valid_hostname: warning: valid_ipv6_hostaddr: too few `:' in IPv6 address: :
+./valid_hostname: testing: "::"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): ::
+./valid_hostname: testing: ":::"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): :::
+./valid_hostname: warning: valid_ipv6_hostaddr: too many `::' in IPv6 address: :::
+./valid_hostname: testing: "a::"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a::
+./valid_hostname: testing: "::a"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): ::a
+./valid_hostname: testing: "::1.2.3.4"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): ::1.2.3.4
+./valid_hostname: testing: "a:a:a:a:a:1.2.3.4"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a:a:a:a:a:1.2.3.4
+./valid_hostname: testing: "a:a:a:a:a:a:1.2.3.4"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a:a:a:a:a:a:1.2.3.4
+./valid_hostname: testing: "a:a:a:a:a:a:a:1.2.3.4"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a:a:a:a:a:a:a:1.2.3.4
+./valid_hostname: warning: valid_ipv6_hostaddr: malformed IPv4-in-IPv6 address: a:a:a:a:a:a:a:1.2.3.4
+./valid_hostname: testing: "a:a:a:a:a:a:1.2.3."
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a:a:a:a:a:a:1.2.3.
+./valid_hostname: warning: valid_ipv4_hostaddr: misplaced dot: 1.2.3.
+./valid_hostname: testing: "a:a:a:a:a:a:1.2.3"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a:a:a:a:a:a:1.2.3
+./valid_hostname: warning: valid_ipv4_hostaddr: invalid octet count: 1.2.3
+./valid_hostname: testing: "a:a:a:a:a:a:a:a"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a:a:a:a:a:a:a:a
+./valid_hostname: testing: "a:a:a:a:a:a:a:a:a"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a:a:a:a:a:a:a:a:a
+./valid_hostname: warning: valid_ipv6_hostaddr: too many `:' in IPv6 address: a:a:a:a:a:a:a:a:a
+./valid_hostname: testing: "g:a:a:a:a:a:a:a"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): g:a:a:a:a:a:a:a
+./valid_hostname: warning: valid_ipv6_hostaddr: invalid character 103(decimal) in IPv6 address: g:a:a:a:a:a:a:a
+./valid_hostname: testing: "a::b"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a::b
+./valid_hostname: testing: ":a::b"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): :a::b
+./valid_hostname: warning: valid_ipv6_hostaddr: bad null first field in IPv6 address: :a::b
+./valid_hostname: testing: "a::b:"
+./valid_hostname: warning: valid_hostname: invalid character 58(decimal): a::b:
+./valid_hostname: warning: valid_ipv6_hostaddr: bad null last field in IPv6 address: a::b:
*/
#include <stdio.h>
-main(int argc, char **argv)
+int main(int argc, char **argv)
{
VSTRING *vp = vstring_alloc(1);
#define TEXT_VSTREAM "vstring_vstream.c"
-main(void)
+int main(void)
{
VSTRING *vp = vstring_alloc(1);
VSTREAM *fp;
#include <vstream.h>
-main(int unused_argc, char **unused_argv)
+int main(int unused_argc, char **unused_argv)
{
WATCHDOG *wp;
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)
#include <dict_ht.h>
#include <dict.h>
#include <split_at.h>
+#include <stringops.h>
/* Global library. */
ATTR_TYPE_NUM, MAIL_ATTR_ADDR_STATUS, &addr_status,
ATTR_TYPE_STR, MAIL_ATTR_WHY, text,
ATTR_TYPE_END) == 3) {
+ /* FIX 200501 IPv6 patch did not neuter ":" in address literals. */
+ translit(STR(addr), ":", "_");
if ((status_name = verify_stat2name(addr_status)) == 0) {
msg_warn("bad recipient status %d for recipient %s",
addr_status, STR(addr));
(addr_status != DEL_RCPT_STAT_OK && updated + var_verify_neg_exp < now)
#define PROBE_TTL 1000
+ /* FIX 200501 IPv6 patch did not neuter ":" in address literals. */
+ translit(STR(addr), ":", "_");
if ((raw_data = dict_get(verify_map, STR(addr))) == 0 /* not found */
|| ((get_buf = vstring_alloc(10)),
vstring_strcpy(get_buf, raw_data), /* malformed */
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
Makefile: Makefile.in
- (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs; cat $?) >$@
+ (echo "# DO NOT EDIT"; tail +2 ../../conf/makedefs.out; cat $?) >$@
test: $(TESTPROG)