Ejemplo n.º 1
0
DNS_RR *smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why)
{
    DNS_RR *addr_list;

    dsb_reset(why);				/* Paranoia */

    /*
     * If the host is specified by numerical address, just convert the
     * address to internal form. Otherwise, the host is specified by name.
     */
#define PREF0	0
    addr_list = smtp_addr_one((DNS_RR *) 0, host, PREF0, why);
    if (addr_list
            && (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
            && smtp_find_self(addr_list) != 0) {
        dns_rr_free(addr_list);
        dsb_simple(why, "5.4.6", "mail for %s loops back to myself", host);
        return (0);
    }
    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_ADDR(misc_flags));
    }
    if (msg_verbose)
        smtp_print_addr(host, addr_list);
    return (addr_list);
}
Ejemplo n.º 2
0
static void psc_service(VSTREAM *smtp_client_stream,
			        char *unused_service,
			        char **unused_argv)
{

    /*
     * 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.
     * 
     * Note: instead of using VSTREAM-level timeouts, we enforce limits on the
     * total amount of time to receive a complete SMTP command line.
     */
    non_blocking(vstream_fileno(smtp_client_stream), NON_BLOCKING);

    /*
     * Look up the remote SMTP client address and port.
     */
    psc_endpt_lookup(smtp_client_stream, psc_endpt_lookup_done);
}
Ejemplo n.º 3
0
void    set_master_ent()
{
    const char *myname = "set_master_ent";
    char   *disable;

    if (master_fp != 0)
	msg_panic("%s: configuration file still open", myname);
    if (master_path == 0)
	msg_panic("%s: no configuration file specified", myname);
    if ((master_fp = vstream_fopen(master_path, O_RDONLY, 0)) == 0)
	msg_fatal("open %s: %m", master_path);
    master_line_last = 0;
    if (master_disable != 0)
	msg_panic("%s: service disable list still exists", myname);
    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);
}
Ejemplo n.º 4
0
void    smtpd_peer_init(SMTPD_STATE *state)
{

    /*
     * Initialize.
     */
    if (proto_info == 0)
	proto_info = inet_proto_info();

    /*
     * Prepare for partial initialization after error.
     */
    memset((void *) &(state->sockaddr), 0, sizeof(state->sockaddr));
    state->sockaddr_len = 0;
    state->name = 0;
    state->reverse_name = 0;
    state->addr = 0;
    state->namaddr = 0;
    state->rfc_addr = 0;
    state->port = 0;
    state->dest_addr = 0;
    state->dest_port = 0;

    /*
     * Determine the remote SMTP client address and port.
     * 
     * XXX In stand-alone mode, don't assume that the peer will be a local
     * process. That could introduce a gaping hole when the SMTP daemon is
     * hooked up to the network via inetd or some other super-server.
     */
    if (vstream_context(state->client) != 0) {
	smtpd_peer_from_pass_attr(state);
	if (*var_smtpd_uproxy_proto != 0)
	    msg_warn("ignoring non-empty %s setting behind postscreen",
		     VAR_SMTPD_UPROXY_PROTO);
    } else if (SMTPD_STAND_ALONE(state) || *var_smtpd_uproxy_proto == 0) {
	smtpd_peer_from_default(state);
    } else {
	smtpd_peer_from_proxy(state);
    }

    /*
     * Determine the remote SMTP client hostname. Note: some of the handlers
     * above provide surrogate endpoint information in case of error. In that
     * case, leave the surrogate information alone.
     */
    if (state->name == 0)
	smtpd_peer_sockaddr_to_hostname(state);

    /*
     * Do the name[addr]:port formatting for pretty reports.
     */
    state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr,
					     state->port);
}
Ejemplo n.º 5
0
DNS_RR *smtp_host_addr(const char *host, int misc_flags, DSN_BUF *why)
{
    DNS_RR *addr_list;
    int     res_opt = 0;
    const char *ahost;

    dsb_reset(why);				/* Paranoia */

    if (smtp_dns_support == SMTP_DNS_DNSSEC)
	res_opt |= RES_USE_DNSSEC;

    /*
     * IDNA support.
     */
#ifndef NO_EAI
    if (!allascii(host) && (ahost = midna_domain_to_ascii(host)) != 0) {
	if (msg_verbose)
	    msg_info("%s asciified to %s", host, ahost);
    } else
#endif
	ahost = host;

    /*
     * If the host is specified by numerical address, just convert the
     * address to internal form. Otherwise, the host is specified by name.
     */
#define PREF0	0
    addr_list = smtp_addr_one((DNS_RR *) 0, ahost, res_opt, PREF0, why);
    if (addr_list
	&& (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
	&& smtp_find_self(addr_list) != 0) {
	dns_rr_free(addr_list);
	dsb_simple(why, "5.4.6", "mail for %s loops back to myself", host);
	return (0);
    }
    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_ADDR(misc_flags));
    }
    if (msg_verbose)
	smtp_print_addr(host, addr_list);
    return (addr_list);
}
Ejemplo n.º 6
0
static void qmqpd_service(VSTREAM *stream, char *unused_service, char **argv)
{
    QMQPD_STATE *state;

    /*
     * Sanity check. This service takes no command-line arguments.
     */
    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-
     * specific state.
     */
    state = qmqpd_state_alloc(stream);

    /*
     * See if we need to turn on verbose logging for this client.
     */
    debug_peer_check(state->name, state->addr);

    /*
     * Provide the QMQP service.
     */
    msg_info("connect from %s", state->namaddr);
    qmqpd_proto(state);
    msg_info("disconnect from %s", state->namaddr);

    /*
     * After the client has gone away, clean up whatever we have set up at
     * connection time.
     */
    debug_peer_restore();
    qmqpd_state_free(state);
}
Ejemplo n.º 7
0
void    psc_endpt_lookup(VSTREAM *smtp_client_stream,
			         PSC_ENDPT_LOOKUP_FN notify)
{
    const PSC_ENDPT_LOOKUP_INFO *pp;

    if (proto_info == 0)
        proto_info = inet_proto_info();

    for (pp = psc_endpt_lookup_info; /* see below */ ; pp++) {
	if (pp->name == 0)
	    msg_fatal("unsupported %s value: %s",
		      VAR_PSC_UPROXY_PROTO, var_psc_uproxy_proto);
	if (strcmp(var_psc_uproxy_proto, pp->name) == 0) {
	    pp->endpt_lookup(smtp_client_stream, notify);
	    return;
	}
    }
}
Ejemplo n.º 8
0
static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
			              char *def_service)
{
    DELIVER_REQUEST *request = state->request;
    SMTP_ITERATOR *iter = state->iterator;
    ARGV   *sites;
    char   *dest;
    char  **cpp;
    int     non_fallback_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;
    }

    /*
     * Future proofing: do a null destination sanity check in case we allow
     * the primary destination to be a list (it could be just separators).
     */
    sites = argv_alloc(1);
    argv_add(sites, nexthop, (char *) 0);
    if (sites->argc == 0)
	msg_panic("null destination: \"%s\"", nexthop);
    non_fallback_sites = sites->argc;
    argv_split_append(sites, var_fallback_relay, CHARS_COMMA_SP);

    /*
     * Don't give up after a hard host lookup error until we have tried the
     * fallback relay servers.
     * 
     * Don't bounce mail after a host lookup problem with a relayhost or with a
     * fallback relay.
     * 
     * Don't give up after a qualifying soft error until we have tried all
     * qualifying backup mail servers.
     * 
     * All this means that error handling and error reporting depends on whether
     * the error qualifies for trying to deliver to a backup mail server, or
     * whether we're looking up a relayhost or fallback relay. The challenge
     * then is to build this into the pre-existing SMTP client without
     * getting lost in the complexity.
     */
#define IS_FALLBACK_RELAY(cpp, sites, non_fallback_sites) \
	    (*(cpp) && (cpp) >= (sites)->argv + (non_fallback_sites))

    for (cpp = sites->argv, (state->misc_flags |= SMTP_MISC_FLAG_FIRST_NEXTHOP);
	 SMTP_RCPT_LEFT(state) > 0 && (dest = *cpp) != 0;
	 cpp++, (state->misc_flags &= ~SMTP_MISC_FLAG_FIRST_NEXTHOP)) {
	char   *dest_buf;
	char   *domain;
	unsigned port;
	DNS_RR *addr_list;
	DNS_RR *addr;
	DNS_RR *next;
	int     addr_count;
	int     sess_count;
	SMTP_SESSION *session;
	int     lookup_mx;
	unsigned domain_best_pref;
	MAI_HOSTADDR_STR hostaddr;

	if (cpp[1] == 0)
	    state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;

	/*
	 * Parse the destination. If no TCP port is specified, use the port
	 * that is reserved for the protocol (SMTP or LMTP).
	 */
	dest_buf = smtp_parse_destination(dest, def_service, &domain, &port);
	if (var_helpful_warnings && var_smtp_tls_wrappermode == 0
	    && ntohs(port) == 465) {
	    msg_info("SMTPS wrappermode (TCP port 465) requires setting "
		     "\"%s = yes\", and \"%s = encrypt\" (or stronger)",
		     VAR_LMTP_SMTP(TLS_WRAPPER), VAR_LMTP_SMTP(TLS_LEVEL));
	}
#define NO_HOST	""				/* safety */
#define NO_ADDR	""				/* safety */

	SMTP_ITER_INIT(iter, dest, NO_HOST, NO_ADDR, port, state);

	/*
	 * Resolve an SMTP or LMTP server. In the case of SMTP, skip mail
	 * exchanger lookups when a quoted host is specified or when DNS
	 * lookups are disabled.
	 */
	if (msg_verbose)
	    msg_info("connecting to %s port %d", domain, ntohs(port));
	if (smtp_mode) {
	    if (ntohs(port) == IPPORT_SMTP)
		state->misc_flags |= SMTP_MISC_FLAG_LOOP_DETECT;
	    else
		state->misc_flags &= ~SMTP_MISC_FLAG_LOOP_DETECT;
	    lookup_mx = (smtp_dns_support != SMTP_DNS_DISABLED && *dest != '[');
	} else
	    lookup_mx = 0;
	if (!lookup_mx) {
	    addr_list = smtp_host_addr(domain, state->misc_flags, why);
	    /* XXX We could be an MX host for this destination... */
	} else {
	    int     i_am_mx = 0;

	    addr_list = smtp_domain_addr(domain, &iter->mx, state->misc_flags,
					 why, &i_am_mx);
	    /* If we're MX host, don't connect to non-MX backups. */
	    if (i_am_mx)
		state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;
	}

	/*
	 * Don't try fall-back hosts if mail loops to myself. That would just
	 * make the problem worse.
	 */
	if (addr_list == 0 && SMTP_HAS_LOOP_DSN(why))
	    state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;

	/*
	 * No early loop exit or we have a memory leak with dest_buf.
	 */
	if (addr_list)
	    domain_best_pref = addr_list->pref;

	/*
	 * When session caching is enabled, store the first good session for
	 * this delivery request under the next-hop destination name. All
	 * good sessions will be stored under their specific server IP
	 * address.
	 * 
	 * XXX smtp_session_cache_destinations specifies domain names without
	 * :port, because : is already used for maptype:mapname. Because of
	 * this limitation we use the bare domain without the optional [] or
	 * non-default TCP port.
	 * 
	 * Opportunistic (a.k.a. on-demand) session caching on request by the
	 * queue manager. This is turned temporarily when a destination has a
	 * high volume of mail in the active queue. When the surge reaches
	 * its end, the queue manager requests that connections be retrieved
	 * but not stored.
	 */
	if (addr_list && (state->misc_flags & SMTP_MISC_FLAG_FIRST_NEXTHOP)) {
	    smtp_cache_policy(state, domain);
	    if (state->misc_flags & SMTP_MISC_FLAG_CONN_CACHE_MASK)
		SET_NEXTHOP_STATE(state, dest);
	}

	/*
	 * Delete visited cached hosts from the address list.
	 * 
	 * Optionally search the connection cache by domain name or by primary
	 * MX address before we try to create new connections.
	 * 
	 * Enforce the MX session and MX address counts per next-hop or
	 * fall-back destination. smtp_reuse_session() will truncate the
	 * address list when either limit is reached.
	 */
	if (addr_list && (state->misc_flags & SMTP_MISC_FLAG_CONN_LOAD)) {
	    if (state->cache_used->used > 0)
		smtp_scrub_addr_list(state->cache_used, &addr_list);
	    sess_count = addr_count =
		smtp_reuse_session(state, &addr_list, domain_best_pref);
	} else
	    sess_count = addr_count = 0;

	/*
	 * Connect to an SMTP server: create primary MX connections, and
	 * reuse or create backup MX connections.
	 * 
	 * At the start of an SMTP session, all recipients are unmarked. In the
	 * course of an SMTP session, recipients are marked as KEEP (deliver
	 * to alternate mail server) or DROP (remove from recipient list). At
	 * the end of an SMTP session, weed out the recipient list. Unmark
	 * any left-over recipients and try to deliver them to a backup mail
	 * server.
	 * 
	 * Cache the first good session under the next-hop destination name.
	 * Cache all good sessions under their physical endpoint.
	 * 
	 * Don't query the session cache for primary MX hosts. We already did
	 * that in smtp_reuse_session(), and if any were found in the cache,
	 * they were already deleted from the address list.
	 * 
	 * Currently, we use smtp_reuse_addr() only for SASL-unauthenticated
	 * connections. Furthermore, we rely on smtp_reuse_addr() to look up
	 * an existing SASL-unauthenticated connection only when a new
	 * connection would be guaranteed not to require SASL authentication.
	 * 
	 * In addition, we rely on smtp_reuse_addr() to look up an existing
	 * plaintext connection only when a new connection would be
	 * guaranteed not to use TLS.
	 */
	for (addr = addr_list; SMTP_RCPT_LEFT(state) > 0 && addr; addr = next) {
	    next = addr->next;
	    if (++addr_count == var_smtp_mxaddr_limit)
		next = 0;
	    if (dns_rr_to_pa(addr, &hostaddr) == 0) {
		msg_warn("cannot convert type %s record to printable address",
			 dns_strtype(addr->type));
		/* XXX Assume there is no code at the end of this loop. */
		continue;
	    }
	    vstring_strcpy(iter->addr, hostaddr.buf);
	    vstring_strcpy(iter->host, SMTP_HNAME(addr));
	    iter->rr = addr;
#ifdef USE_TLS
	    if (!smtp_tls_policy_cache_query(why, state->tls, iter)) {
		msg_warn("TLS policy lookup for %s/%s: %s",
			 STR(iter->dest), STR(iter->host), STR(why->reason));
		continue;
		/* XXX Assume there is no code at the end of this loop. */
	    }
	    if (var_smtp_tls_wrappermode
		&& state->tls->level < TLS_LEV_ENCRYPT) {
		msg_warn("%s requires \"%s = encrypt\" (or stronger)",
		      VAR_LMTP_SMTP(TLS_WRAPPER), VAR_LMTP_SMTP(TLS_LEVEL));
		continue;
		/* XXX Assume there is no code at the end of this loop. */
	    }
	    /* Disable TLS when retrying after a handshake failure */
	    if (retry_plain) {
		state->tls->level = TLS_LEV_NONE;
		retry_plain = 0;
	    }
#endif
	    if ((state->misc_flags & SMTP_MISC_FLAG_CONN_LOAD) == 0
		|| addr->pref == domain_best_pref
		|| !(session = smtp_reuse_addr(state,
					  SMTP_KEY_MASK_SCACHE_ENDP_LABEL)))
		session = smtp_connect_addr(iter, why, state->misc_flags);
	    if ((state->session = session) != 0) {
		session->state = state;
#ifdef USE_TLS
		session->tls_nexthop = domain;
#endif
		if (addr->pref == domain_best_pref)
		    session->features |= SMTP_FEATURE_BEST_MX;
		/* Don't count handshake errors towards the session limit. */
		if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
		    && next == 0)
		    state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER;
		if ((session->features & SMTP_FEATURE_FROM_CACHE) == 0
		    && smtp_helo(state) != 0) {
#ifdef USE_TLS

		    /*
		     * When an opportunistic TLS handshake fails, try the
		     * same address again, with TLS disabled. See also the
		     * RETRY_AS_PLAINTEXT macro.
		     */
		    if ((retry_plain = session->tls_retry_plain) != 0) {
			--addr_count;
			next = addr;
		    }
#endif

		    /*
		     * When a TLS handshake fails, the stream is marked
		     * "dead" to avoid further I/O over a broken channel.
		     */
		    if (!THIS_SESSION_IS_FORBIDDEN
			&& vstream_ferror(session->stream) == 0
			&& vstream_feof(session->stream) == 0)
			smtp_quit(state);
		} else {
		    /* Do count delivery errors towards the session limit. */
		    if (++sess_count == var_smtp_mxsess_limit)
			next = 0;
		    if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
			&& next == 0)
			state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER;
		    smtp_xfer(state);
#ifdef USE_TLS

		    /*
		     * When opportunistic TLS fails after the STARTTLS
		     * handshake, try the same address again, with TLS
		     * disabled. See also the RETRY_AS_PLAINTEXT macro.
		     */
		    if ((retry_plain = session->tls_retry_plain) != 0) {
			--sess_count;
			--addr_count;
			next = addr;
		    }
#endif
		}
		smtp_cleanup_session(state);
	    } else {
		/* The reason already includes the IP address and TCP port. */
		msg_info("%s", STR(why->reason));
	    }
	    /* XXX Code above assumes there is no code at this loop ending. */
	}
	dns_rr_free(addr_list);
	if (iter->mx) {
	    dns_rr_free(iter->mx);
	    iter->mx = 0;			/* Just in case */
	}
	myfree(dest_buf);
	if (state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
	    break;
    }

    /*
     * We still need to deliver, bounce or defer some left-over recipients:
     * either mail loops or some backup mail server was unavailable.
     */
    if (SMTP_RCPT_LEFT(state) > 0) {

	/*
	 * In case of a "no error" indication we make up an excuse: we did
	 * find the host address, but we did not attempt to connect to it.
	 * This can happen when the fall-back relay was already tried via a
	 * cached connection, so that the address list scrubber left behind
	 * an empty list.
	 */
	if (!SMTP_HAS_DSN(why)) {
	    dsb_simple(why, "4.3.0",
		       "server unavailable or unable to receive mail");
	}

	/*
	 * Pay attention to what could be configuration problems, and pretend
	 * that these are recoverable rather than bouncing the mail.
	 */
	else if (!SMTP_HAS_SOFT_DSN(why)) {

	    /*
	     * The fall-back destination did not resolve as expected, or it
	     * is refusing to talk to us, or mail for it loops back to us.
	     */
	    if (IS_FALLBACK_RELAY(cpp, sites, non_fallback_sites)) {
		msg_warn("%s configuration problem", VAR_SMTP_FALLBACK);
		vstring_strcpy(why->status, "4.3.5");
		/* XXX Keep the diagnostic code and MTA. */
	    }

	    /*
	     * The next-hop relayhost did not resolve as expected, or it is
	     * refusing to talk to us, or mail for it loops back to us.
	     * 
	     * XXX There is no equivalent safety net for mis-configured
	     * sender-dependent relay hosts. The trivial-rewrite resolver
	     * would have to flag the result, and the queue manager would
	     * have to provide that information to delivery agents.
	     */
	    else if (smtp_mode && strcmp(sites->argv[0], var_relayhost) == 0) {
		msg_warn("%s configuration problem", VAR_RELAYHOST);
		vstring_strcpy(why->status, "4.3.5");
		/* XXX Keep the diagnostic code and MTA. */
	    }

	    /*
	     * Mail for the next-hop destination loops back to myself. Pass
	     * the mail to the best_mx_transport or bounce it.
	     */
	    else if (smtp_mode && SMTP_HAS_LOOP_DSN(why) && *var_bestmx_transp) {
		dsb_reset(why);			/* XXX */
		state->status = deliver_pass_all(MAIL_CLASS_PRIVATE,
						 var_bestmx_transp,
						 request);
		SMTP_RCPT_LEFT(state) = 0;	/* XXX */
	    }
	}
    }

    /*
     * Cleanup.
     */
    if (HAVE_NEXTHOP_STATE(state))
	FREE_NEXTHOP_STATE(state);
    argv_free(sites);
}
Ejemplo n.º 9
0
int     inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname)
{
    const char *myname = "inet_addr_host";
    int     sock;
    struct addrinfo *res0;
    struct addrinfo *res;
    int     aierr;
    ssize_t hostnamelen;
    const char *hname;
    const char *serv;
    int     initial_count = addr_list->used;
    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 {
	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((void *) hname);

    return (addr_list->used - initial_count);
}
Ejemplo n.º 10
0
void    smtpd_peer_init(SMTPD_STATE *state)
{
    const char *myname = "smtpd_peer_init";
    SOCKADDR_SIZE sa_length;
    struct sockaddr *sa;
    INET_PROTO_INFO *proto_info = inet_proto_info();

    sa = (struct sockaddr *) & (state->sockaddr);
    sa_length = sizeof(state->sockaddr);

    /*
     * Look up the peer address information.
     * 
     * XXX If we make local endpoint (getsockname) information available to
     * Milter applications as {if_name} and {if_addr}, then we also must be
     * able to provide this via the XCLIENT command for Milter testing.
     * 
     * XXX If we make local or remote port information available to policy
     * servers or Milter applications, then we must also make this testable
     * with the XCLIENT command, otherwise there will be confusion.
     * 
     * XXX If we make local or remote port information available via logging,
     * then we must also support these attributes with the XFORWARD command.
     * 
     * XXX If support were to be added for Milter applications in down-stream
     * MTAs, then consistency demands that we propagate a lot of Sendmail
     * macro information via the XFORWARD command. Otherwise we could end up
     * with a very confusing situation.
     */
    if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
	errno = 0;
    }

    /*
     * If peer went away, give up.
     */
    if (errno != 0 && errno != ENOTSOCK) {
	state->name = mystrdup(CLIENT_NAME_UNKNOWN);
	state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
	state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
	state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
	state->addr_family = AF_UNSPEC;
	state->name_status = SMTPD_PEER_CODE_PERM;
	state->reverse_name_status = SMTPD_PEER_CODE_PERM;
	state->port = mystrdup(CLIENT_PORT_UNKNOWN);
    }

    /*
     * Convert the client address to printable address and hostname.
     * 
     * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
     * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
     * else clause, pretend the origin is localhost[127.0.0.1], and become an
     * open relay).
     */
    else if (errno == 0
	     && (sa->sa_family == AF_INET
#ifdef AF_INET6
		 || sa->sa_family == AF_INET6
#endif
		 )) {
	MAI_HOSTNAME_STR client_name;
	MAI_HOSTADDR_STR client_addr;
	MAI_SERVPORT_STR client_port;
	int     aierr;
	char   *colonp;

	/*
	 * Sanity check: we can't use sockets that we're not configured for.
	 */
	if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0)
	    msg_fatal("cannot handle socket type %s with \"%s = %s\"",
#ifdef AF_INET6
		      sa->sa_family == AF_INET6 ? "AF_INET6" :
#endif
		      sa->sa_family == AF_INET ? "AF_INET" :
		      "other", VAR_INET_PROTOCOLS, var_inet_protocols);

	/*
	 * Sorry, but there are some things that we just cannot do while
	 * connected to the network.
	 */
	if (geteuid() != var_owner_uid || getuid() != var_owner_uid) {
	    msg_error("incorrect SMTP server privileges: uid=%lu euid=%lu",
		      (unsigned long) getuid(), (unsigned long) geteuid());
	    msg_fatal("the Postfix SMTP server must run with $%s privileges",
		      VAR_MAIL_OWNER);
	}

	/*
	 * Convert the client address to printable form.
	 */
	if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
					  &client_port, 0)) != 0)
	    msg_fatal("%s: cannot convert client address/port to string: %s",
		      myname, MAI_STRERROR(aierr));
	state->port = mystrdup(client_port.buf);

	/*
	 * XXX Strip off the IPv6 datalink suffix to avoid false alarms with
	 * strict address syntax checks.
	 */
#ifdef HAS_IPV6
	(void) split_at(client_addr.buf, '%');
#endif

	/*
	 * 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);
		state->addr_family = AF_INET;
		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_length = res0->ai_addrlen;
		if (sa_length > sizeof(state->sockaddr))
		    sa_length = sizeof(state->sockaddr);
		memcpy((char *) sa, res0->ai_addr, sa_length);
		freeaddrinfo(res0);		/* 200412 */
	    }

	    /*
	     * 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);
		state->addr_family = sa->sa_family;
	    }
	}

	/*
	 * An IPv4 address is in dotted quad decimal form.
	 */
	else
#endif
	{
	    state->addr = mystrdup(client_addr.buf);
	    state->rfc_addr = mystrdup(client_addr.buf);
	    state->addr_family = sa->sa_family;
	}

	/*
	 * 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->name_status = code; \
    }

	if (var_smtpd_peername_lookup == 0) {
	    state->name = mystrdup(CLIENT_NAME_UNKNOWN);
	    state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
	    state->name_status = SMTPD_PEER_CODE_PERM;
	    state->reverse_name_status = SMTPD_PEER_CODE_PERM;
	} else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
					 (MAI_SERVNAME_STR *) 0, 0)) != 0) {
	    state->name = mystrdup(CLIENT_NAME_UNKNOWN);
	    state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
	    state->name_status = (TEMP_AI_ERROR(aierr) ?
			       SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM);
	    state->reverse_name_status = (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->reverse_name = mystrdup(client_name.buf);
	    state->name_status = SMTPD_PEER_CODE_OK;
	    state->reverse_name_status = SMTPD_PEER_CODE_OK;

	    /*
	     * Reject the hostname if it does not list the peer address.
	     * Without further validation or qualification, such information
	     * must not be allowed to enter the audit trail, as people would
	     * draw false conclusions.
	     */
	    aierr = hostname_to_sockaddr_pf(state->name, state->addr_family,
					    (char *) 0, 0, &res0);
	    if (aierr) {
		msg_warn("%s: hostname %s verification failed: %s",
			 state->addr, state->name, MAI_STRERROR(aierr));
		REJECT_PEER_NAME(state, (TEMP_AI_ERROR(aierr) ?
			    SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_FORGED));
	    } else {
		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_FORGED);
			break;
		    }
		    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);
	    }
	}
    }

    /*
     * If it's not Internet, assume the client is local, and avoid using the
     * naming service because that can hang when the machine is disconnected.
     */
    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. */
	state->addr_family = AF_UNSPEC;
	state->name_status = SMTPD_PEER_CODE_OK;
	state->reverse_name_status = SMTPD_PEER_CODE_OK;
	state->port = mystrdup("0");		/* XXX bogus. */
    }

    /*
     * Do the name[addr]:port formatting for pretty reports.
     */
    state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr,
					     state->port);
}
Ejemplo n.º 11
0
static void psc_service(VSTREAM *smtp_client_stream,
			        char *unused_service,
			        char **unused_argv)
{
    const char *myname = "psc_service";
    PSC_STATE *state;
    struct sockaddr_storage addr_storage;
    SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage);
    MAI_HOSTADDR_STR smtp_client_addr;
    MAI_SERVPORT_STR smtp_client_port;
    MAI_HOSTADDR_STR smtp_server_addr;
    MAI_SERVPORT_STR smtp_server_port;
    int     aierr;
    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.
     * 
     * Note: instead of using VSTREAM-level timeouts, we enforce limits on the
     * total amount of time to receive a complete SMTP command line.
     */
    non_blocking(vstream_fileno(smtp_client_stream), NON_BLOCKING);

    /*
     * We use the event_server framework. This means we get already-accepted
     * connections so we have to invoke getpeername() to find out the remote
     * address and port.
     */

    /* Best effort - if this non-blocking write(2) fails, so be it. */
#define PSC_SERVICE_DISCONNECT_AND_RETURN(stream) do { \
	(void) write(vstream_fileno(stream), \
		     "421 4.3.2 No system resources\r\n", \
		     sizeof("421 4.3.2 No system resources\r\n") - 1); \
	event_server_disconnect(stream); \
	return; \
    } while (0);

    /*
     * Look up the remote SMTP client address and port.
     */
    if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
		    & addr_storage, &addr_storage_len) < 0) {
	msg_warn("getpeername: %m -- dropping this connection");
	PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
    }

    /*
     * Convert the remote SMTP client address and port to printable form for
     * logging and access control.
     */
    if ((aierr = sockaddr_to_hostaddr((struct sockaddr *) & addr_storage,
				      addr_storage_len, &smtp_client_addr,
				      &smtp_client_port, 0)) != 0) {
	msg_warn("cannot convert client address/port to string: %s"
		 " -- dropping this connection",
		 MAI_STRERROR(aierr));
	PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
    }
    if (strncasecmp("::ffff:", smtp_client_addr.buf, 7) == 0)
	memmove(smtp_client_addr.buf, smtp_client_addr.buf + 7,
		sizeof(smtp_client_addr.buf) - 7);
    if (msg_verbose > 1)
	msg_info("%s: sq=%d cq=%d connect from [%s]:%s",
		 myname, psc_post_queue_length, psc_check_queue_length,
		 smtp_client_addr.buf, smtp_client_port.buf);

    /*
     * Look up the local SMTP server address and port.
     */
    if (getsockname(vstream_fileno(smtp_client_stream), (struct sockaddr *)
		    & addr_storage, &addr_storage_len) < 0) {
	msg_warn("getsockname: %m -- dropping this connection");
	PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
    }

    /*
     * Convert the local SMTP server address and port to printable form for
     * logging and access control.
     */
    if ((aierr = sockaddr_to_hostaddr((struct sockaddr *) & addr_storage,
				      addr_storage_len, &smtp_server_addr,
				      &smtp_server_port, 0)) != 0) {
	msg_warn("cannot convert server address/port to string: %s"
		 " -- dropping this connection",
		 MAI_STRERROR(aierr));
	PSC_SERVICE_DISCONNECT_AND_RETURN(smtp_client_stream);
    }
    if (strncasecmp("::ffff:", smtp_server_addr.buf, 7) == 0)
	memmove(smtp_server_addr.buf, smtp_server_addr.buf + 7,
		sizeof(smtp_server_addr.buf) - 7);

    msg_info("CONNECT from [%s]:%s to [%s]:%s",
	     smtp_client_addr.buf, smtp_client_port.buf,
	     smtp_server_addr.buf, smtp_server_port.buf);

    /*
     * Bundle up all the loose session pieces. This zeroes all flags and time
     * stamps.
     */
    state = psc_new_session_state(smtp_client_stream, smtp_client_addr.buf,
				  smtp_client_port.buf);

    /*
     * Reply with 421 when the client has too many open connections.
     */
    if (var_psc_cconn_limit > 0
	&& state->client_concurrency > var_psc_cconn_limit) {
	msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: too many connections",
		 state->smtp_client_addr, state->smtp_client_port);
	PSC_DROP_SESSION_STATE(state,
			       "421 4.7.0 Error: too many connections\r\n");
	return;
    }

    /*
     * Reply with 421 when we can't forward more connections.
     */
    if (var_psc_post_queue_limit > 0
	&& psc_post_queue_length >= var_psc_post_queue_limit) {
	msg_info("NOQUEUE: reject: CONNECT from [%s]:%s: all server ports busy",
		 state->smtp_client_addr, state->smtp_client_port);
	PSC_DROP_SESSION_STATE(state,
			       "421 4.3.2 All server ports are busy\r\n");
	return;
    }

    /*
     * The permanent white/blacklist has highest precedence.
     */
    if (psc_acl != 0) {
	switch (psc_acl_eval(state, psc_acl, VAR_PSC_ACL)) {

	    /*
	     * Permanently blacklisted.
	     */
	case PSC_ACL_ACT_BLACKLIST:
	    msg_info("BLACKLISTED [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
	    PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_BLIST_FAIL);
	    switch (psc_blist_action) {
	    case PSC_ACT_DROP:
		PSC_DROP_SESSION_STATE(state,
			     "521 5.3.2 Service currently unavailable\r\n");
		return;
	    case PSC_ACT_ENFORCE:
		PSC_ENFORCE_SESSION_STATE(state,
			     "550 5.3.2 Service currently unavailable\r\n");
		break;
	    case PSC_ACT_IGNORE:
		PSC_UNFAIL_SESSION_STATE(state, PSC_STATE_FLAG_BLIST_FAIL);

		/*
		 * Not: PSC_PASS_SESSION_STATE. Repeat this test the next
		 * time.
		 */
		break;
	    default:
		msg_panic("%s: unknown blacklist action value %d",
			  myname, psc_blist_action);
	    }
	    break;

	    /*
	     * Permanently whitelisted.
	     */
	case PSC_ACL_ACT_WHITELIST:
	    msg_info("WHITELISTED [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
	    psc_conclude(state);
	    return;

	    /*
	     * Other: dunno (don't know) or error.
	     */
	default:
	    break;
	}
    }

    /*
     * The temporary whitelist (i.e. the postscreen cache) has the lowest
     * precedence. This cache contains information about the results of prior
     * tests. Whitelist the client when all enabled test results are still
     * valid.
     */
    if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0
	&& psc_cache_map != 0
	&& (stamp_str = psc_cache_lookup(psc_cache_map, state->smtp_client_addr)) != 0) {
	saved_flags = state->flags;
	psc_parse_tests(state, stamp_str, event_time());
	state->flags |= saved_flags;
	if (msg_verbose)
	    msg_info("%s: cached + recent flags: %s",
		     myname, psc_print_state_flags(state->flags, myname));
	if ((state->flags & PSC_STATE_MASK_ANY_TODO_FAIL) == 0) {
	    msg_info("PASS OLD [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
	    psc_conclude(state);
	    return;
	}
    } else {
	saved_flags = state->flags;
	psc_new_tests(state);
	state->flags |= saved_flags;
	if (msg_verbose)
	    msg_info("%s: new + recent flags: %s",
		     myname, psc_print_state_flags(state->flags, myname));
    }

    /*
     * Don't whitelist clients that connect to backup MX addresses. Fail
     * "closed" on error.
     */
    if (addr_match_list_match(psc_wlist_if, smtp_server_addr.buf) == 0) {
	state->flags |= (PSC_STATE_FLAG_WLIST_FAIL | PSC_STATE_FLAG_NOFORWARD);
	msg_info("WHITELIST VETO [%s]:%s", PSC_CLIENT_ADDR_PORT(state));
    }

    /*
     * Reply with 421 when we can't analyze more connections. That also means
     * no deep protocol tests when the noforward flag is raised.
     */
    if (var_psc_pre_queue_limit > 0
	&& psc_check_queue_length - psc_post_queue_length
	>= var_psc_pre_queue_limit) {
	msg_info("reject: connect from [%s]:%s: all screening ports busy",
		 state->smtp_client_addr, state->smtp_client_port);
	PSC_DROP_SESSION_STATE(state,
			       "421 4.3.2 All screening ports are busy\r\n");
	return;
    }

    /*
     * If the client has no up-to-date results for some tests, do those tests
     * first. Otherwise, skip the tests and hand off the connection.
     */
    if (state->flags & PSC_STATE_MASK_EARLY_TODO)
	psc_early_tests(state);
    else if (state->flags & (PSC_STATE_MASK_SMTPD_TODO | PSC_STATE_FLAG_NOFORWARD))
	psc_smtpd_tests(state);
    else
	psc_conclude(state);
}
Ejemplo n.º 12
0
static DNS_RR *smtp_addr_one(DNS_RR *addr_list, const char *host,
                             unsigned pref, DSN_BUF *why)
{
    const char *myname = "smtp_addr_one";
    DNS_RR *addr = 0;
    DNS_RR *rr;
    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 (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.
     *
     * XXX A soft error dominates past and future hard errors. Therefore we
     * should not clobber a soft error text and status code.
     */
    if (smtp_host_lookup_mask & SMTP_HOST_FLAG_DNS) {
        switch (dns_lookup_v(host, smtp_dns_res_opt, &addr, (VSTRING *) 0,
                             why->reason, DNS_REQ_FLAG_NONE,
                             proto_info->dns_atype_list)) {
        case DNS_OK:
            for (rr = addr; rr; rr = rr->next)
                rr->pref = pref;
            addr_list = dns_rr_append(addr_list, addr);
            return (addr_list);
        default:
            dsb_status(why, "4.4.3");
            return (addr_list);
        case DNS_FAIL:
            dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.3" : "5.4.3");
            return (addr_list);
        case DNS_INVAL:
            dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4");
            return (addr_list);
        case DNS_NOTFOUND:
            dsb_status(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4");
            /* maybe native naming service will succeed */
            break;
        }
    }

    /*
     * Use the native name service which also looks in /etc/hosts.
     *
     * XXX A soft error dominates past and future hard errors. Therefore we
     * should not clobber a soft error text and status code.
     */
#define RETRY_AI_ERROR(e) \
        ((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
#ifdef EAI_NODATA
#define DSN_NOHOST(e) \
	((e) == EAI_AGAIN || (e) == EAI_NODATA || (e) == EAI_NONAME)
#else
#define DSN_NOHOST(e) \
	((e) == EAI_AGAIN || (e) == EAI_NONAME)
#endif

    if (smtp_host_lookup_mask & SMTP_HOST_FLAG_NATIVE) {
        if ((aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0)) != 0) {
            dsb_simple(why, (SMTP_HAS_SOFT_DSN(why) || RETRY_AI_ERROR(aierr)) ?
                       (DSN_NOHOST(aierr) ? "4.4.4" : "4.3.0") :
                       (DSN_NOHOST(aierr) ? "5.4.4" : "5.3.0"),
                       "unable to look up host %s: %s",
                       host, MAI_STRERROR(aierr));
        } else {
            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) {
                dsb_simple(why, SMTP_HAS_SOFT_DSN(why) ? "4.4.4" : "5.4.4",
                           "%s: host not found", host);
            }
            return (addr_list);
        }
    }

    /*
     * No further alternatives for host lookup.
     */
    return (addr_list);
}
Ejemplo n.º 13
0
static void own_inet_addr_init(INET_ADDR_LIST *addr_list,
			               INET_ADDR_LIST *mask_list)
{
    INET_ADDR_LIST local_addrs;
    INET_ADDR_LIST local_masks;
    char   *hosts;
    char   *host;
    const char *sep = " \t,";
    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 (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");
    }

    /*
     * 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);
    }

    /*
     * If we are supposed to be listening only on specific interface
     * addresses (virtual hosting), look up the addresses of those
     * interfaces.
     */
    else {
	bufp = hosts = mystrdup(var_inet_interfaces);
	while ((host = mystrtok(&bufp, sep)) != 0)
	    if (inet_addr_host(addr_list, host) == 0)
		msg_fatal("config variable %s: host not found: %s",
			  VAR_INET_INTERFACES, host);
	myfree(hosts);

	/*
	 * Weed out duplicate IP addresses. Duplicates happen when the same
	 * IP address is listed under multiple hostnames. If we don't weed
	 * out duplicates, Postfix can suddenly stop working after the DNS is
	 * changed.
	 */
	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,
			    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) {
		    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, 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;
		}
	    }
	}
	inet_addr_list_free(&local_addrs);
	inet_addr_list_free(&local_masks);
    }
}
Ejemplo n.º 14
0
static void smtp_connect_inet(SMTP_STATE *state, const char *nexthop,
			              char *def_service)
{
    DELIVER_REQUEST *request = state->request;
    ARGV   *sites;
    char   *dest;
    char  **cpp;
    int     non_fallback_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.
     * 
     * Future proofing: do a null destination sanity check in case we allow the
     * primary destination to be a list (it could be just separators).
     */
    sites = argv_alloc(1);
    argv_add(sites, nexthop, (char *) 0);
    if (sites->argc == 0)
	msg_panic("null destination: \"%s\"", nexthop);
    non_fallback_sites = sites->argc;
    if ((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0)
	argv_split_append(sites, var_fallback_relay, ", \t\r\n");

    /*
     * Don't give up after a hard host lookup error until we have tried the
     * fallback relay servers.
     * 
     * Don't bounce mail after a host lookup problem with a relayhost or with a
     * fallback relay.
     * 
     * Don't give up after a qualifying soft error until we have tried all
     * qualifying backup mail servers.
     * 
     * All this means that error handling and error reporting depends on whether
     * the error qualifies for trying to deliver to a backup mail server, or
     * whether we're looking up a relayhost or fallback relay. The challenge
     * then is to build this into the pre-existing SMTP client without
     * getting lost in the complexity.
     */
#define IS_FALLBACK_RELAY(cpp, sites, non_fallback_sites) \
	    (*(cpp) && (cpp) >= (sites)->argv + (non_fallback_sites))

    for (cpp = sites->argv, (state->misc_flags |= SMTP_MISC_FLAG_FIRST_NEXTHOP);
	 SMTP_RCPT_LEFT(state) > 0 && (dest = *cpp) != 0;
	 cpp++, (state->misc_flags &= ~SMTP_MISC_FLAG_FIRST_NEXTHOP)) {
	char   *dest_buf;
	char   *domain;
	unsigned port;
	DNS_RR *addr_list;
	DNS_RR *addr;
	DNS_RR *next;
	int     addr_count;
	int     sess_count;
	SMTP_SESSION *session;
	int     lookup_mx;
	unsigned domain_best_pref;
	MAI_HOSTADDR_STR hostaddr;

	if (cpp[1] == 0)
	    state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;

	/*
	 * Parse the destination. Default is to use the SMTP port. Look up
	 * the address instead of the mail exchanger when a quoted host is
	 * specified, or when DNS lookups are disabled.
	 */
	dest_buf = smtp_parse_destination(dest, def_service, &domain, &port);
	if (var_helpful_warnings && ntohs(port) == 465) {
	    msg_info("CLIENT wrappermode (port smtps/465) is unimplemented");
	    msg_info("instead, send to (port submission/587) with STARTTLS");
	}

	/*
	 * Resolve an SMTP server. Skip mail exchanger lookups when a quoted
	 * host is specified, or when DNS lookups are disabled.
	 */
	if (msg_verbose)
	    msg_info("connecting to %s port %d", domain, ntohs(port));
	if ((state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {
	    if (ntohs(port) == IPPORT_SMTP)
		state->misc_flags |= SMTP_MISC_FLAG_LOOP_DETECT;
	    else
		state->misc_flags &= ~SMTP_MISC_FLAG_LOOP_DETECT;
	    lookup_mx = (var_disable_dns == 0 && *dest != '[');
	} else
	    lookup_mx = 0;
	if (!lookup_mx) {
	    addr_list = smtp_host_addr(domain, state->misc_flags, why);
	    /* XXX We could be an MX host for this destination... */
	} else {
	    int     i_am_mx = 0;

	    addr_list = smtp_domain_addr(domain, state->misc_flags,
					 why, &i_am_mx);
	    /* If we're MX host, don't connect to non-MX backups. */
	    if (i_am_mx)
		state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;
	}

	/*
	 * Don't try fall-back hosts if mail loops to myself. That would just
	 * make the problem worse.
	 */
	if (addr_list == 0 && SMTP_HAS_LOOP_DSN(why))
	    state->misc_flags |= SMTP_MISC_FLAG_FINAL_NEXTHOP;

	/*
	 * No early loop exit or we have a memory leak with dest_buf.
	 */
	if (addr_list)
	    domain_best_pref = addr_list->pref;

	/*
	 * When session caching is enabled, store the first good session for
	 * this delivery request under the next-hop destination name. All
	 * good sessions will be stored under their specific server IP
	 * address.
	 * 
	 * XXX Replace sites->argv by (lookup_mx, domain, port) triples so we
	 * don't have to make clumsy ad-hoc copies and keep track of who
	 * free()s the memory.
	 * 
	 * XXX smtp_session_cache_destinations specifies domain names without
	 * :port, because : is already used for maptype:mapname. Because of
	 * this limitation we use the bare domain without the optional [] or
	 * non-default TCP port.
	 * 
	 * Opportunistic (a.k.a. on-demand) session caching on request by the
	 * queue manager. This is turned temporarily when a destination has a
	 * high volume of mail in the active queue.
	 * 
	 * XXX Disable connection caching when sender-dependent authentication
	 * is enabled. We must not send someone elses mail over an
	 * authenticated connection, and we must not send mail that requires
	 * authentication over a connection that wasn't authenticated.
	 */
	if (addr_list && (state->misc_flags & SMTP_MISC_FLAG_FIRST_NEXTHOP)) {
	    smtp_cache_policy(state, domain);
	    if (state->misc_flags & SMTP_MISC_FLAG_CONN_STORE)
		SET_NEXTHOP_STATE(state, lookup_mx, domain, port);
	}

	/*
	 * Delete visited cached hosts from the address list.
	 * 
	 * Optionally search the connection cache by domain name or by primary
	 * MX address before we try to create new connections.
	 * 
	 * Enforce the MX session and MX address counts per next-hop or
	 * fall-back destination. smtp_reuse_session() will truncate the
	 * address list when either limit is reached.
	 */
	if (addr_list && (state->misc_flags & SMTP_MISC_FLAG_CONN_LOAD)) {
	    if (state->cache_used->used > 0)
		smtp_scrub_addr_list(state->cache_used, &addr_list);
	    sess_count = addr_count =
		smtp_reuse_session(state, lookup_mx, domain, port,
				   &addr_list, domain_best_pref);
	} else
	    sess_count = addr_count = 0;

	/*
	 * Connect to an SMTP server: create primary MX connections, and
	 * reuse or create backup MX connections.
	 * 
	 * At the start of an SMTP session, all recipients are unmarked. In the
	 * course of an SMTP session, recipients are marked as KEEP (deliver
	 * to alternate mail server) or DROP (remove from recipient list). At
	 * the end of an SMTP session, weed out the recipient list. Unmark
	 * any left-over recipients and try to deliver them to a backup mail
	 * server.
	 * 
	 * Cache the first good session under the next-hop destination name.
	 * Cache all good sessions under their physical endpoint.
	 * 
	 * Don't query the session cache for primary MX hosts. We already did
	 * that in smtp_reuse_session(), and if any were found in the cache,
	 * they were already deleted from the address list.
	 */
	for (addr = addr_list; SMTP_RCPT_LEFT(state) > 0 && addr; addr = next) {
	    next = addr->next;
	    if (++addr_count == var_smtp_mxaddr_limit)
		next = 0;
	    if ((state->misc_flags & SMTP_MISC_FLAG_CONN_LOAD) == 0
		|| addr->pref == domain_best_pref
		|| dns_rr_to_pa(addr, &hostaddr) == 0
		|| !(session = smtp_reuse_addr(state, hostaddr.buf, port)))
		session = smtp_connect_addr(dest, addr, port, why,
					    state->misc_flags);
	    if ((state->session = session) != 0) {
		session->state = state;
		if (addr->pref == domain_best_pref)
		    session->features |= SMTP_FEATURE_BEST_MX;
		/* Don't count handshake errors towards the session limit. */
		if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
		    && next == 0)
		    state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER;
#ifdef USE_TLS
		/* Disable TLS when retrying after a handshake failure */
		if (retry_plain) {
		    if (session->tls_level >= TLS_LEV_ENCRYPT)
			msg_panic("Plain-text retry wrong for mandatory TLS");
		    session->tls_level = TLS_LEV_NONE;
		    retry_plain = 0;
		}
		session->tls_nexthop = domain;	/* for TLS_LEV_SECURE */
#endif
		if ((session->features & SMTP_FEATURE_FROM_CACHE) == 0
		    && smtp_helo(state) != 0) {
#ifdef USE_TLS

		    /*
		     * When an opportunistic TLS handshake fails, try the
		     * same address again, with TLS disabled. See also the
		     * RETRY_AS_PLAINTEXT macro.
		     */
		    if ((retry_plain = session->tls_retry_plain) != 0) {
			--addr_count;
			next = addr;
		    }
#endif

		    /*
		     * When a TLS handshake fails, the stream is marked
		     * "dead" to avoid further I/O over a broken channel.
		     */
		    if (!THIS_SESSION_IS_DEAD
			&& vstream_ferror(session->stream) == 0
			&& vstream_feof(session->stream) == 0)
			smtp_quit(state);
		} else {
		    /* Do count delivery errors towards the session limit. */
		    if (++sess_count == var_smtp_mxsess_limit)
			next = 0;
		    if ((state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
			&& next == 0)
			state->misc_flags |= SMTP_MISC_FLAG_FINAL_SERVER;
		    smtp_xfer(state);
		}
		smtp_cleanup_session(state);
	    } else {
		/* The reason already includes the IP address and TCP port. */
		msg_info("%s", STR(why->reason));
	    }
	    /* Insert: test if we must skip the remaining MX hosts. */
	}
	dns_rr_free(addr_list);
	myfree(dest_buf);
	if (state->misc_flags & SMTP_MISC_FLAG_FINAL_NEXTHOP)
	    break;
    }

    /*
     * We still need to deliver, bounce or defer some left-over recipients:
     * either mail loops or some backup mail server was unavailable.
     */
    if (SMTP_RCPT_LEFT(state) > 0) {

	/*
	 * In case of a "no error" indication we make up an excuse: we did
	 * find the host address, but we did not attempt to connect to it.
	 * This can happen when the fall-back relay was already tried via a
	 * cached connection, so that the address list scrubber left behind
	 * an empty list.
	 */
	if (!SMTP_HAS_DSN(why)) {
	    dsb_simple(why, "4.3.0",
		       "server unavailable or unable to receive mail");
	}

	/*
	 * Pay attention to what could be configuration problems, and pretend
	 * that these are recoverable rather than bouncing the mail.
	 */
	else if (!SMTP_HAS_SOFT_DSN(why)
		 && (state->misc_flags & SMTP_MISC_FLAG_USE_LMTP) == 0) {

	    /*
	     * The fall-back destination did not resolve as expected, or it
	     * is refusing to talk to us, or mail for it loops back to us.
	     */
	    if (IS_FALLBACK_RELAY(cpp, sites, non_fallback_sites)) {
		msg_warn("%s configuration problem", VAR_SMTP_FALLBACK);
		vstring_strcpy(why->status, "4.3.5");
		/* XXX Keep the diagnostic code and MTA. */
	    }

	    /*
	     * The next-hop relayhost did not resolve as expected, or it is
	     * refusing to talk to us, or mail for it loops back to us.
	     */
	    else if (strcmp(sites->argv[0], var_relayhost) == 0) {
		msg_warn("%s configuration problem", VAR_RELAYHOST);
		vstring_strcpy(why->status, "4.3.5");
		/* XXX Keep the diagnostic code and MTA. */
	    }

	    /*
	     * Mail for the next-hop destination loops back to myself. Pass
	     * the mail to the best_mx_transport or bounce it.
	     */
	    else if (SMTP_HAS_LOOP_DSN(why) && *var_bestmx_transp) {
		dsb_reset(why);			/* XXX */
		state->status = deliver_pass_all(MAIL_CLASS_PRIVATE,
						 var_bestmx_transp,
						 request);
		SMTP_RCPT_LEFT(state) = 0;	/* XXX */
	    }
	}
    }

    /*
     * Cleanup.
     */
    if (HAVE_NEXTHOP_STATE(state))
	FREE_NEXTHOP_STATE(state);
    argv_free(sites);
}
Ejemplo n.º 15
0
void    qmqpd_peer_init(QMQPD_STATE *state)
{
    const char *myname = "qmqpd_peer_init";
    struct sockaddr_storage ss;
    struct sockaddr *sa;
    SOCKADDR_SIZE sa_length;
    INET_PROTO_INFO *proto_info = inet_proto_info();

    sa = (struct sockaddr *) & ss;
    sa_length = sizeof(ss);

    /*
     * Look up the peer address information.
     */
    if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
	errno = 0;
    }

    /*
     * If peer went away, give up.
     */
    if (errno != 0 && errno != ENOTSOCK) {
	state->name = mystrdup(CLIENT_NAME_UNKNOWN);
	state->addr = mystrdup(CLIENT_ADDR_UNKNOWN);
	state->rfc_addr = mystrdup(CLIENT_ADDR_UNKNOWN);
	state->addr_family = AF_UNSPEC;
	state->port = mystrdup(CLIENT_PORT_UNKNOWN);
    }

    /*
     * Convert the client address to printable address and hostname.
     * 
     * XXX If we're given an IPv6 (or IPv4) connection from, e.g., inetd, while
     * Postfix IPv6 (or IPv4) support is turned off, don't (skip to the final
     * else clause, pretend the origin is localhost[127.0.0.1], and become an
     * open relay).
     */
    else if (errno == 0
	     && (sa->sa_family == AF_INET
#ifdef AF_INET6
		 || sa->sa_family == AF_INET6
#endif
		 )) {
	MAI_HOSTNAME_STR client_name;
	MAI_HOSTADDR_STR client_addr;
	MAI_SERVPORT_STR client_port;
	int     aierr;
	char   *colonp;

	/*
	 * Sanity check: we can't use sockets that we're not configured for.
	 */
	if (strchr((char *) proto_info->sa_family_list, sa->sa_family) == 0)
	    msg_fatal("cannot handle socket type %s with \"%s = %s\"",
#ifdef AF_INET6
		      sa->sa_family == AF_INET6 ? "AF_INET6" :
#endif
		      sa->sa_family == AF_INET ? "AF_INET" :
		      "other", VAR_INET_PROTOCOLS, var_inet_protocols);

	/*
	 * Sorry, but there are some things that we just cannot do while
	 * connected to the network.
	 */
	if (geteuid() != var_owner_uid || getuid() != var_owner_uid) {
	    msg_error("incorrect QMQP server privileges: uid=%lu euid=%lu",
		      (unsigned long) getuid(), (unsigned long) geteuid());
	    msg_fatal("the Postfix QMQP server must run with $%s privileges",
		      VAR_MAIL_OWNER);
	}

	/*
	 * Convert the client address to printable form.
	 */
	if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
					  &client_port, 0)) != 0)
	    msg_fatal("%s: cannot convert client address/port to string: %s",
		      myname, MAI_STRERROR(aierr));
	state->port = mystrdup(client_port.buf);

	/*
	 * XXX Require that the infrastructure strips off the IPv6 datalink
	 * suffix to avoid false alarms with strict address syntax checks.
	 */
#ifdef HAS_IPV6
	if (strchr(client_addr.buf, '%') != 0)
	    msg_panic("%s: address %s has datalink suffix",
		      myname, client_addr.buf);
#endif

	/*
	 * 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);
		state->addr_family = AF_INET;
		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_length = res0->ai_addrlen;
		if (sa_length > sizeof(ss))
		    sa_length = sizeof(ss);
		memcpy((char *) sa, res0->ai_addr, sa_length);
		freeaddrinfo(res0);
	    }

	    /*
	     * 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);
		state->addr_family = sa->sa_family;
	    }
	}

	/*
	 * An IPv4 address is in dotted quad decimal form.
	 */
	else
#endif
	{
	    state->addr = mystrdup(client_addr.buf);
	    state->rfc_addr = mystrdup(client_addr.buf);
	    state->addr_family = sa->sa_family;
	}

	/*
	 * 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_NAME_UNKNOWN); \
    }

	if ((aierr = sockaddr_to_hostname(sa, sa_length, &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_pf(state->name, state->addr_family,
					    (char *) 0, 0, &res0);
	    if (aierr) {
		msg_warn("hostname %s does not resolve to address %s: %s",
			 state->name, state->addr, MAI_STRERROR(aierr));
		REJECT_PEER_NAME(state);
	    } else {
		for (res = res0; /* void */ ; res = res->ai_next) {
		    if (res == 0) {
			msg_warn("hostname %s does not resolve to address %s",
				 state->addr, state->name);
			REJECT_PEER_NAME(state);
			break;
		    }
		    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);
	    }
	}
    }

    /*
     * If it's not Internet, assume the client is local, and avoid using the
     * naming service because that can hang when the machine is disconnected.
     */
    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->addr_family = AF_UNSPEC;
	state->port = mystrdup("0");		/* XXX bogus. */
    }

    /*
     * Do the name[addr]:port formatting for pretty reports.
     */
    state->namaddr =
	concatenate(state->name, "[", state->addr, "]",
		    var_qmqpd_client_port_log ? ":" : (char *) 0,
		    state->port, (char *) 0);
}