fallback_transport_maps, the local delivery agent did not
log the problem before deferring mail, and produced no defer
logfile record. Files: local/mailbox.c, local/unknown.c.
+
+20120102
+
+ Workaround: degrade gracefully when the network protocols
+ specified with inet_protocols are unavailable. Files:
+ global/mail_params.c, global/mynetworks.c, global/own_inet_addr.c
+ master/master_ent.c, master/master_vars.c, postscreen/postscreen.c,
+ qmqpd/qmqpd.c, smtp/smtp_connect.c, smtpd/smtpd.c,
+ util/inet_proto.c.
dict_sqlite.o: dict_sqlite.c
dict_sqlite.o: dict_sqlite.h
dict_sqlite.o: string_list.h
-domain_list.cdebug_peer.o: domain_list.cdebug_peer.c
domain_list.o: ../../include/argv.h
domain_list.o: ../../include/dict.h
domain_list.o: ../../include/match_list.h
msg_stats_scan.o: msg_stats_scan.c
mynetworks.o: ../../include/argv.h
mynetworks.o: ../../include/inet_addr_list.h
+mynetworks.o: ../../include/inet_proto.h
mynetworks.o: ../../include/mask_addr.h
mynetworks.o: ../../include/msg.h
mynetworks.o: ../../include/myaddrinfo.h
{
static const 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,
+ VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 0, 0,
VAR_MULTI_CONF_DIRS, DEF_MULTI_CONF_DIRS, &var_multi_conf_dirs, 0, 0,
/* multi_instance_wrapper may have dependencies but not dependents. */
VAR_MULTI_GROUP, DEF_MULTI_GROUP, &var_multi_group, 0, 0,
VAR_COMMAND_DIR, DEF_COMMAND_DIR, &var_command_dir, 1, 0,
VAR_QUEUE_DIR, DEF_QUEUE_DIR, &var_queue_dir, 1, 0,
VAR_PID_DIR, DEF_PID_DIR, &var_pid_dir, 1, 0,
- VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces, 1, 0,
+ VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces, 0, 0,
VAR_PROXY_INTERFACES, DEF_PROXY_INTERFACES, &var_proxy_interfaces, 0, 0,
VAR_DOUBLE_BOUNCE, DEF_DOUBLE_BOUNCE, &var_double_bounce_sender, 1, 0,
VAR_DEFAULT_PRIVS, DEF_DEFAULT_PRIVS, &var_default_privs, 1, 0,
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20111230"
+#define MAIL_RELEASE_DATE "20120102"
#define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT
#include <myaddrinfo.h>
#include <mask_addr.h>
#include <argv.h>
+#include <inet_proto.h>
/* Global library. */
BH_TABLE *dup_filter;
char **cpp;
+ /*
+ * Avoid run-time errors when all network protocols are disabled. We
+ * can't look up interface information, and we can't convert explicit
+ * names or addresses.
+ */
+ if (inet_proto_info()->ai_family_list[0] == 0) {
+ if (msg_verbose)
+ msg_info("skipping %s setting - "
+ "all network protocols are disabled",
+ VAR_MYNETWORKS);
+ result = vstring_alloc(1);
+ return (vstring_str(result));
+ }
mask_style = name_mask("mynetworks mask style", mask_styles,
var_mynetworks_style);
inet_addr_list_init(addr_list);
inet_addr_list_init(mask_list);
+ /*
+ * Avoid run-time errors when all network protocols are disabled. We
+ * can't look up interface information, and we can't convert explicit
+ * names or addresses.
+ */
+ if (inet_proto_info()->ai_family_list[0] == 0) {
+ if (msg_verbose)
+ msg_info("skipping %s setting - "
+ "all network protocols are disabled",
+ VAR_INET_INTERFACES);
+ return;
+ }
+
/*
* If we are listening on all interfaces (default), ask the system what
* the interfaces are.
@$(EXPORT) make -f Makefile.in Makefile 1>&2
# do not edit below this line - it is generated by 'make depend'
+event_server.o: ../../include/argv.h
event_server.o: ../../include/chroot_uid.h
event_server.o: ../../include/debug_process.h
+event_server.o: ../../include/dict.h
event_server.o: ../../include/events.h
event_server.o: ../../include/iostuff.h
event_server.o: ../../include/listen.h
master_ent.o: ../../include/host_port.h
master_ent.o: ../../include/inet_addr_host.h
master_ent.o: ../../include/inet_addr_list.h
+master_ent.o: ../../include/inet_proto.h
master_ent.o: ../../include/iostuff.h
master_ent.o: ../../include/mail_conf.h
master_ent.o: ../../include/mail_params.h
master_watch.o: ../../include/sys_defs.h
master_watch.o: master.h
master_watch.o: master_watch.c
+multi_server.o: ../../include/argv.h
multi_server.o: ../../include/chroot_uid.h
multi_server.o: ../../include/debug_process.h
+multi_server.o: ../../include/dict.h
multi_server.o: ../../include/events.h
multi_server.o: ../../include/iostuff.h
multi_server.o: ../../include/listen.h
multi_server.o: mail_server.h
multi_server.o: master_proto.h
multi_server.o: multi_server.c
+single_server.o: ../../include/argv.h
single_server.o: ../../include/chroot_uid.h
single_server.o: ../../include/debug_process.h
+single_server.o: ../../include/dict.h
single_server.o: ../../include/events.h
single_server.o: ../../include/iostuff.h
single_server.o: ../../include/listen.h
single_server.o: mail_server.h
single_server.o: master_proto.h
single_server.o: single_server.c
+trigger_server.o: ../../include/argv.h
trigger_server.o: ../../include/chroot_uid.h
trigger_server.o: ../../include/debug_process.h
+trigger_server.o: ../../include/dict.h
trigger_server.o: ../../include/events.h
trigger_server.o: ../../include/iostuff.h
trigger_server.o: ../../include/listen.h
#include <host_port.h>
#include <inet_addr_host.h>
#include <sock_addr.h>
+#include <inet_proto.h>
/* Global library. */
void set_master_ent()
{
const char *myname = "set_master_ent";
+ char *disable;
if (master_fp != 0)
msg_panic("%s: configuration file still open", myname);
master_line = 0;
if (master_disable != 0)
msg_panic("%s: service disable list still exists", myname);
- master_disable = match_service_init(var_master_disable);
+ if (inet_proto_info()->ai_family_list[0] == 0) {
+ msg_warn("all network protocols are disabled (%s = %s)",
+ VAR_INET_PROTOCOLS, var_inet_protocols);
+ msg_warn("disabling all type \"inet\" services in master.cf");
+ disable = concatenate(MASTER_XPORT_NAME_INET, ",",
+ var_master_disable, (char *) 0);
+ master_disable = match_service_init(disable);
+ myfree(disable);
+ } else
+ master_disable = match_service_init(var_master_disable);
}
/* end_master_ent - close configuration file */
{
char *path;
static const CONFIG_STR_TABLE str_table[] = {
- VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 1, 0,
VAR_MASTER_DISABLE, DEF_MASTER_DISABLE, &var_master_disable, 0, 0,
0,
};
postscreen.o: ../../include/dict_cache.h
postscreen.o: ../../include/events.h
postscreen.o: ../../include/htable.h
+postscreen.o: ../../include/inet_proto.h
postscreen.o: ../../include/iostuff.h
postscreen.o: ../../include/mail_conf.h
postscreen.o: ../../include/mail_params.h
#include <set_eugid.h>
#include <vstream.h>
#include <name_code.h>
+#include <inet_proto.h>
/* Global library. */
const char *stamp_str;
int saved_flags;
+ /*
+ * For sanity, require that at least one of INET or INET6 is enabled.
+ * Otherwise, we can't look up interface information, and we can't
+ * convert names or addresses.
+ */
+ if (inet_proto_info()->ai_family_list[0] == 0)
+ msg_fatal("all network protocols are disabled (%s = %s)",
+ VAR_INET_PROTOCOLS, var_inet_protocols);
+
/*
* This program handles all incoming connections, so it must not block.
* We use event-driven code for all operations that introduce latency.
qmqpd.o: ../../include/cleanup_user.h
qmqpd.o: ../../include/debug_peer.h
qmqpd.o: ../../include/dict.h
+qmqpd.o: ../../include/inet_proto.h
qmqpd.o: ../../include/input_transp.h
qmqpd.o: ../../include/iostuff.h
qmqpd.o: ../../include/lex_822.h
#include <vstream.h>
#include <netstring.h>
#include <dict.h>
+#include <inet_proto.h>
/* Global library. */
if (argv[0])
msg_fatal("unexpected command-line argument: %s", argv[0]);
+ /*
+ * For sanity, require that at least one of INET or INET6 is enabled.
+ * Otherwise, we can't look up interface information, and we can't
+ * convert names or addresses.
+ */
+ if (inet_proto_info()->ai_family_list[0] == 0)
+ msg_fatal("all network protocols are disabled (%s = %s)",
+ VAR_INET_PROTOCOLS, var_inet_protocols);
+
/*
* This routine runs when a client has connected to our network port.
* Look up and sanitize the peer name and initialize some connection-
smtp_connect.o: ../../include/host_port.h
smtp_connect.o: ../../include/htable.h
smtp_connect.o: ../../include/inet_addr_list.h
+smtp_connect.o: ../../include/inet_proto.h
smtp_connect.o: ../../include/iostuff.h
smtp_connect.o: ../../include/mail_addr.h
smtp_connect.o: ../../include/mail_error.h
#include <sane_connect.h>
#include <myaddrinfo.h>
#include <sock_addr.h>
+#include <inet_proto.h>
/* Global library. */
return (session_count);
}
-/* smtp_connect_remote - establish remote connection */
+/* smtp_connect_inet - establish network connection */
-static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop,
- char *def_service)
+static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
+ char *def_service)
{
DELIVER_REQUEST *request = state->request;
ARGV *sites;
int retry_plain = 0;
DSN_BUF *why = state->why;
+ /*
+ * For sanity, require that at least one of INET or INET6 is enabled.
+ * Otherwise, we can't look up interface information, and we can't
+ * convert names or addresses.
+ */
+ if (inet_proto_info()->ai_family_list[0] == 0) {
+ dsb_simple(why, "4.4.4", "all network protocols are disabled");
+ return;
+ }
+
/*
* First try to deliver to the indicated destination, then try to deliver
* to the optional fall-back relays.
} else {
if (strncmp(destination, "inet:", 5) == 0)
destination += 5;
- smtp_connect_remote(state, destination, DEF_LMTP_SERVICE);
+ smtp_connect_inet(state, destination, DEF_LMTP_SERVICE);
}
}
* Postfix configurations that have a host with such a name.
*/
else {
- smtp_connect_remote(state, destination, DEF_SMTP_SERVICE);
+ smtp_connect_inet(state, destination, DEF_SMTP_SERVICE);
}
/*
smtpd.o: ../../include/ehlo_mask.h
smtpd.o: ../../include/events.h
smtpd.o: ../../include/flush_clnt.h
+smtpd.o: ../../include/inet_proto.h
smtpd.o: ../../include/input_transp.h
smtpd.o: ../../include/iostuff.h
smtpd.o: ../../include/is_header.h
#include <iostuff.h>
#include <split_at.h>
#include <name_code.h>
+#include <inet_proto.h>
/* Global library. */
if (argv[0])
msg_fatal("unexpected command-line argument: %s", argv[0]);
+ /*
+ * For sanity, require that at least one of INET or INET6 is enabled.
+ * Otherwise, we can't look up interface information, and we can't
+ * convert names or addresses.
+ */
+ if (SMTPD_STAND_ALONE_STREAM(stream) == 0
+ && inet_proto_info()->ai_family_list[0] == 0)
+ msg_fatal("all network protocols are disabled (%s = %s)",
+ VAR_INET_PROTOCOLS, var_inet_protocols);
+
/*
* This routine runs when a client has connected to our network port, or
* when the smtp server is run in stand-alone mode (input from pipe).
* If running in stand-alone mode, do not try to talk to Postfix daemons but
* write to queue file instead.
*/
+#define SMTPD_STAND_ALONE_STREAM(stream) \
+ (stream == VSTREAM_IN && getuid() != var_owner_uid)
+
#define SMTPD_STAND_ALONE(state) \
(state->client == VSTREAM_IN && getuid() != var_owner_uid)
else {
state->name = mystrdup("localhost");
state->reverse_name = mystrdup("localhost");
- state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */
- state->rfc_addr = mystrdup("127.0.0.1");/* XXX bogus. */
+ if (proto_info->sa_family_list[0] == PF_INET6) {
+ state->addr = mystrdup("::1"); /* XXX bogus. */
+ state->rfc_addr = mystrdup(IPV6_COL "::1"); /* XXX bogus. */
+ } else {
+ state->addr = mystrdup("127.0.0.1");/* XXX bogus. */
+ state->rfc_addr = mystrdup("127.0.0.1"); /* XXX bogus. */
+ }
state->addr_family = AF_UNSPEC;
state->name_status = SMTPD_PEER_CODE_OK;
state->reverse_name_status = SMTPD_PEER_CODE_OK;
/* 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
+/* One or more of T_AAAA or T_A. 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
/* 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.
+/* This module will warn and turn off support for any protocol
+/* that is requested but unavailable.
/*
/* Fatal errors: memory allocation problem.
/* LICENSE
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.
+ * Avoid run-time errors when all network protocols are disabled. We
+ * can't look up interface information, and we can't convert explicit
+ * names or addresses.
*/
inet_proto_mask = name_mask(context, proto_table, protocols);
- switch (inet_proto_mask) {
#ifdef HAS_IPV6
- case INET_PROTO_MASK_IPV6:
+ if (inet_proto_mask & 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 if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
+ msg_warn("%s: disabling IPv6 name/address support: %m", context);
+ inet_proto_mask &= ~INET_PROTO_MASK_IPV6;
} else {
msg_fatal("socket: %m");
}
- case (INET_PROTO_MASK_IPV6 | INET_PROTO_MASK_IPV4):
- if ((sock = socket(PF_INET6, SOCK_STREAM, 0)) >= 0) {
+ }
+#endif
+ if (inet_proto_mask & INET_PROTO_MASK_IPV4) {
+ if ((sock = socket(PF_INET, 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 || errno == EPROTONOSUPPORT) {
- msg_warn("%s: IPv6 support is disabled: %m", context);
- msg_warn("%s: configuring for IPv4 support only", context);
- /* FALLTHROUGH */
+ msg_warn("%s: disabling IPv4 name/address support: %m", context);
+ inet_proto_mask &= ~INET_PROTO_MASK_IPV4;
} else {
msg_fatal("socket: %m");
}
+ }
+
+ /*
+ * 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.
+ */
+ switch (inet_proto_mask) {
+#ifdef HAS_IPV6
+ case INET_PROTO_MASK_IPV6:
+ 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;
+ case (INET_PROTO_MASK_IPV6 | INET_PROTO_MASK_IPV4):
+ 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;
#endif
case INET_PROTO_MASK_IPV4:
pf = (INET_PROTO_INFO *) mymalloc(sizeof(*pf));
pf->dns_atype_list = make_unsigned_vector(2, T_A, 0);
pf->sa_family_list = make_uchar_vector(2, AF_INET, 0);
break;
+ case 0:
+ pf = (INET_PROTO_INFO *) mymalloc(sizeof(*pf));
+ pf->ai_family = PF_UNSPEC;
+ pf->ai_family_list = make_unsigned_vector(1, 0);
+ pf->dns_atype_list = make_unsigned_vector(1, 0);
+ pf->sa_family_list = make_uchar_vector(1, 0);
+ break;
default:
msg_panic("%s: bad inet_proto_mask 0x%x", myname, inet_proto_mask);
}
/*
* Small driver for unit tests.
*/
+
+static char *print_unsigned_vector(VSTRING *buf, unsigned *vector)
+{
+ unsigned *p;
+
+ VSTRING_RESET(buf);
+ for (p = vector; *p; p++) {
+ vstring_sprintf_append(buf, "%u", *p);
+ if (p[1])
+ VSTRING_ADDCH(buf, ' ');
+ }
+ VSTRING_TERMINATE(buf);
+ return (vstring_str(buf));
+}
+
+static char *print_uchar_vector(VSTRING *buf, unsigned char *vector)
+{
+ unsigned char *p;
+
+ VSTRING_RESET(buf);
+ for (p = vector; *p; p++) {
+ vstring_sprintf_append(buf, "%u", *p);
+ if (p[1])
+ VSTRING_ADDCH(buf, ' ');
+ }
+ VSTRING_TERMINATE(buf);
+ return (vstring_str(buf));
+}
+
int main(int argc, char **argv)
{
const char *myname = argv[0];
INET_PROTO_INFO *pf;
+ VSTRING *buf;
if (argc < 2)
msg_fatal("usage: %s protocol(s)...", myname);
+ buf = vstring_alloc(10);
while (*++argv) {
msg_info("=== %s ===", *argv);
- if (**argv)
- inet_proto_init(myname, *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]);
+ msg_info("ai_family_list = %s",
+ print_unsigned_vector(buf, pf->ai_family_list));
+ msg_info("dns_atype_list = %s",
+ print_unsigned_vector(buf, pf->dns_atype_list));
+ msg_info("sa_family_list = %s",
+ print_uchar_vector(buf, pf->sa_family_list));
}
+ vstring_free(buf);
return (0);
}