]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20120102
authorWietse Venema <wietse@porcupine.org>
Mon, 2 Jan 2012 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:52 +0000 (06:37 +0000)
20 files changed:
postfix/HISTORY
postfix/src/global/Makefile.in
postfix/src/global/mail_params.c
postfix/src/global/mail_version.h
postfix/src/global/mynetworks.c
postfix/src/global/own_inet_addr.c
postfix/src/master/Makefile.in
postfix/src/master/master_ent.c
postfix/src/master/master_vars.c
postfix/src/postscreen/Makefile.in
postfix/src/postscreen/postscreen.c
postfix/src/qmqpd/Makefile.in
postfix/src/qmqpd/qmqpd.c
postfix/src/smtp/Makefile.in
postfix/src/smtp/smtp_connect.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_peer.c
postfix/src/util/inet_proto.c

index af7475222e85fe59ae5dc3ab8bd747f23f0da38f..48365be9987444773fee4e59d5bfa2b353bb1bea 100644 (file)
@@ -17443,3 +17443,12 @@ Apologies for any names omitted.
        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.
index 6a4ee997eaf1ea11df4fdc930373115e33817ddb..e496ca9fc658b4148e4eabc33d3910c314793243 100644 (file)
@@ -983,7 +983,6 @@ dict_sqlite.o: db_common.h
 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
@@ -1700,6 +1699,7 @@ msg_stats_scan.o: msg_stats.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
index 009beb49b1a223c26495529c5fb969753c4781fe..dff3b72b87aed0597b7143d988a7f432648ea15d 100644 (file)
@@ -510,7 +510,7 @@ void    mail_params_init()
 {
     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,
@@ -535,7 +535,7 @@ void    mail_params_init()
        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,
index d480339378e672f4bd16a8466e29c34c4759795c..95bf2c2e2458626dec3b8f1f8cd1056d50abb08c 100644 (file)
@@ -20,7 +20,7 @@
   * 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
index f2b9d5c228d3e3eb2c6d3969f5e6e2f821aa65f6..93c69676c4e2f2a60bf06dd37a8cd3ff9fe818e7 100644 (file)
@@ -58,6 +58,7 @@
 #include <myaddrinfo.h>
 #include <mask_addr.h>
 #include <argv.h>
+#include <inet_proto.h>
 
 /* Global library. */
 
@@ -101,6 +102,19 @@ const char *mynetworks(void)
        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);
 
index 362aaf954cebc28604993fe0e807a3dbb12a3ad4..d164a20b2035344c8c4b0423d25d34d334e58609 100644 (file)
@@ -92,6 +92,19 @@ static void own_inet_addr_init(INET_ADDR_LIST *addr_list,
     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.
index a78173916478299a80179251748374aa9ec3e19c..43f9db57e3b43c92c5986c0f354c3eea06591426 100644 (file)
@@ -83,8 +83,10 @@ depend: $(MAKES)
        @$(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
@@ -161,6 +163,7 @@ master_ent.o: ../../include/attr.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
@@ -270,8 +273,10 @@ master_watch.o: ../../include/mymalloc.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
@@ -300,8 +305,10 @@ multi_server.o: mail_flow.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
@@ -330,8 +337,10 @@ single_server.o: mail_flow.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
index cc0bb56d72902a2d27edaafbcfa2be6e11863851..9441255fa1aaf9b1b2ac3421ab6a4ece28dbdaeb 100644 (file)
@@ -87,6 +87,7 @@
 #include <host_port.h>
 #include <inet_addr_host.h>
 #include <sock_addr.h>
+#include <inet_proto.h>
 
 /* Global library. */
 
@@ -126,6 +127,7 @@ void    fset_master_ent(char *path)
 void    set_master_ent()
 {
     const char *myname = "set_master_ent";
+    char   *disable;
 
     if (master_fp != 0)
        msg_panic("%s: configuration file still open", myname);
@@ -136,7 +138,16 @@ void    set_master_ent()
     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 */
index 3e9b77861407ffdee3cd7f173e554885a42be0f6..898269f26b5cefe6582811bda4f678c50c8ca3bc 100644 (file)
@@ -57,7 +57,6 @@ void    master_vars_init(void)
 {
     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,
     };
index bf6a735b72ea76cd0ec1a8beaf6bb3ab716a912f..fa7f996ba79fdfb19d0a5adc8fc2b5af05c232ee 100644 (file)
@@ -72,6 +72,7 @@ postscreen.o: ../../include/dict.h
 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
index 6f2ae065e74de3161b35c123e7ab5017b6b35e5b..36a665bf17917ad0f1eb1195c490513b7fb791b4 100644 (file)
 #include <set_eugid.h>
 #include <vstream.h>
 #include <name_code.h>
+#include <inet_proto.h>
 
 /* Global library. */
 
@@ -592,6 +593,15 @@ static void psc_service(VSTREAM *smtp_client_stream,
     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.
index 44bb071096c096f2677fb9b3f3bb6a2172528d86..c180709cf35532a9289e8de766bd384d03545fe1 100644 (file)
@@ -63,6 +63,7 @@ qmqpd.o: ../../include/attr.h
 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
index e9c33e80f626ad254179d7853be4263ab08b790b..e64bc6ebfbbd633551510f5ced9f4b6b3b472b56 100644 (file)
 #include <vstream.h>
 #include <netstring.h>
 #include <dict.h>
+#include <inet_proto.h>
 
 /* Global library. */
 
@@ -720,6 +721,15 @@ static void qmqpd_service(VSTREAM *stream, char *unused_service, char **argv)
     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-
index 1d5ed3a6af71c70f90833977be485937d4714207..cc0aaf58e84b8940ba5a497d7e6a572398dc4025 100644 (file)
@@ -224,6 +224,7 @@ smtp_connect.o: ../../include/header_opts.h
 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
index 05d59c9f5440f71bb681c3f34643d18d07e1c3f7..2abb49ccb5fd4e9b83e53d742423a3483865b82b 100644 (file)
@@ -87,6 +87,7 @@
 #include <sane_connect.h>
 #include <myaddrinfo.h>
 #include <sock_addr.h>
+#include <inet_proto.h>
 
 /* Global library. */
 
@@ -682,10 +683,10 @@ static int smtp_reuse_session(SMTP_STATE *state, int lookup_mx,
     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;
@@ -695,6 +696,16 @@ static void smtp_connect_remote(SMTP_STATE *state, const char *nexthop,
     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.
@@ -1036,7 +1047,7 @@ int     smtp_connect(SMTP_STATE *state)
        } 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);
        }
     }
 
@@ -1049,7 +1060,7 @@ int     smtp_connect(SMTP_STATE *state)
      * 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);
     }
 
     /*
index 989c3c7caafb4838c8896ebd173978fe2590c8dd..f053b1679d23afa4460d7d5ac1bbf1dc768d6b25 100644 (file)
@@ -159,6 +159,7 @@ smtpd.o: ../../include/dsn_mask.h
 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
index 1b3f053c76cd869435d8f7bbc1ef098157d23f15..6e90bf10dbbc8419a1176cf6a236a99d5198a250 100644 (file)
 #include <iostuff.h>
 #include <split_at.h>
 #include <name_code.h>
+#include <inet_proto.h>
 
 /* Global library. */
 
@@ -4812,6 +4813,16 @@ static void smtpd_service(VSTREAM *stream, char *service, char **argv)
     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).
index 2d6c46c9250478b66bd39b76df5c5adc1875ec80..4001a81456581bbbfad71fe09c594e6332378921 100644 (file)
@@ -284,6 +284,9 @@ extern void smtpd_state_reset(SMTPD_STATE *);
   * 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)
 
index 3ea89946b470473ead3b5661726e8a391ae84027..330e07938a4cda27d874dbf77ef11f76963e2b6e 100644 (file)
@@ -372,8 +372,13 @@ void    smtpd_peer_init(SMTPD_STATE *state)
     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;
index fd082ed07fb64d936c0bcb2345c8a970c511f4b6..6b5cc4c2a2b54d2f281afe9be0657cef89873bfa 100644 (file)
@@ -56,7 +56,7 @@
 /*     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
@@ -65,9 +65,8 @@
 /* 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
@@ -186,46 +185,58 @@ INET_PROTO_INFO *inet_proto_init(const char *context, const char *protocols)
     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));
@@ -234,6 +245,13 @@ INET_PROTO_INFO *inet_proto_init(const char *context, const char *protocols)
        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);
     }
@@ -247,27 +265,58 @@ INET_PROTO_INFO *inet_proto_init(const char *context, const char *protocols)
  /*
   * 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);
 }