Beispiel #1
0
static int inet_addr_list_comp(const void *a, const void *b)
{

    /*
     * In case (struct *) != (void *).
     */
    return (sock_addr_cmp_addr(SOCK_ADDR_PTR(a), SOCK_ADDR_PTR(b)));
}
Beispiel #2
0
static int ial_procnet_ifinet6(INET_ADDR_LIST *addr_list,
			               INET_ADDR_LIST *mask_list)
{
    const char *myname = "inet_addr_local[procnet_ifinet6]";
    FILE   *fp;
    char    buf[BUFSIZ];
    unsigned plen;
    VSTRING *addrbuf;
    struct sockaddr_in6 addr;
    struct sockaddr_in6 mask;

    /*
     * Example: 00000000000000000000000000000001 01 80 10 80 lo
     * 
     * Fields: address, interface index, prefix length, scope value
     * (net/ipv6.h), interface flags (linux/rtnetlink.h), device name.
     * 
     * FIX 200501 The IPv6 patch used fscanf(), which will hang on unexpected
     * input. Use fgets() + sscanf() instead.
     */
    if ((fp = fopen(_PATH_PROCNET_IFINET6, "r")) != 0) {
	addrbuf = vstring_alloc(MAI_V6ADDR_BYTES + 1);
	memset((void *) &addr, 0, sizeof(addr));
	addr.sin6_family = AF_INET6;
#ifdef HAS_SA_LEN
	addr.sin6_len = sizeof(addr);
#endif
	mask = addr;
	while (fgets(buf, sizeof(buf), fp) != 0) {
	    /* 200501 hex_decode() is light-weight compared to getaddrinfo(). */
	    if (hex_decode(addrbuf, buf, MAI_V6ADDR_BYTES * 2) == 0
		|| sscanf(buf + MAI_V6ADDR_BYTES * 2, " %*x %x", &plen) != 1
		|| plen > MAI_V6ADDR_BITS) {
		msg_warn("unexpected data in %s - skipping IPv6 configuration",
			 _PATH_PROCNET_IFINET6);
		break;
	    }
	    /* vstring_str(addrbuf) has worst-case alignment. */
	    addr.sin6_addr = *(struct in6_addr *) vstring_str(addrbuf);
	    inet_addr_list_append(addr_list, SOCK_ADDR_PTR(&addr));

	    memset((void *) &mask.sin6_addr, ~0, sizeof(mask.sin6_addr));
	    mask_addr((unsigned char *) &mask.sin6_addr,
		      sizeof(mask.sin6_addr), plen);
	    inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask));
	}
	vstring_free(addrbuf);
	fclose(fp);				/* FIX 200501 */
    } else {
	msg_warn("can't open %s (%m) - skipping IPv6 configuration",
		 _PATH_PROCNET_IFINET6);
    }
    return (0);
}
Beispiel #3
0
int     main(int argc, char **argv)
{
    INET_ADDR_LIST list;
    struct sockaddr_storage *sa;
    MAI_HOSTADDR_STR hostaddr;
    INET_PROTO_INFO *proto_info;

    msg_vstream_init(argv[0], VSTREAM_ERR);

    if (argc < 3)
	msg_fatal("usage: %s protocols hostname...", argv[0]);

    proto_info = inet_proto_init(argv[0], argv[1]);
    argv += 1;

    while (--argc && *++argv) {
	inet_addr_list_init(&list);
	if (inet_addr_host(&list, *argv) == 0)
	    msg_fatal("not found: %s", *argv);

	for (sa = list.addrs; sa < list.addrs + list.used; sa++) {
	    SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
				 &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
	    vstream_printf("%s\t%s\n", *argv, hostaddr.buf);
	}
	vstream_fflush(VSTREAM_OUT);
	inet_addr_list_free(&list);
    }
    return (0);
}
static void inet_addr_list_print(INET_ADDR_LIST *list)
{
    MAI_HOSTADDR_STR hostaddr;
    struct sockaddr_storage *sa;

    for (sa = list->addrs; sa < list->addrs + list->used; sa++) {
	SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
			     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
	msg_info("%s", hostaddr.buf);
    }
}
Beispiel #5
0
int     main(int unused_argc, char **argv)
{
    INET_ADDR_LIST addr_list;
    INET_ADDR_LIST mask_list;
    MAI_HOSTADDR_STR hostaddr;
    MAI_HOSTADDR_STR hostmask;
    struct sockaddr *sa;
    int     i;
    INET_PROTO_INFO *proto_info;

    msg_vstream_init(argv[0], VSTREAM_ERR);
    msg_verbose = 1;

    proto_info = inet_proto_init(argv[0],
				 argv[1] ? argv[1] : INET_PROTO_NAME_ALL);
    inet_addr_list_init(&addr_list);
    inet_addr_list_init(&mask_list);
    inet_addr_local(&addr_list, &mask_list, proto_info->ai_family_list);

    if (addr_list.used == 0)
	msg_fatal("cannot find any active network interfaces");

    if (addr_list.used == 1)
	msg_warn("found only one active network interface");

    for (i = 0; i < addr_list.used; i++) {
	sa = SOCK_ADDR_PTR(addr_list.addrs + i);
	SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
			     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
	sa = SOCK_ADDR_PTR(mask_list.addrs + i);
	SOCKADDR_TO_HOSTADDR(SOCK_ADDR_PTR(sa), SOCK_ADDR_LEN(sa),
			     &hostmask, (MAI_SERVPORT_STR *) 0, 0);
	vstream_printf("%s/%s\n", hostaddr.buf, hostmask.buf);
	vstream_fflush(VSTREAM_OUT);
    }
    inet_addr_list_free(&addr_list);
    inet_addr_list_free(&mask_list);
    return (0);
}
Beispiel #6
0
static SMTP_SESSION *smtp_connect_addr(SMTP_ITERATOR *iter, DSN_BUF *why,
				               int sess_flags)
{
    const char *myname = "smtp_connect_addr";
    struct sockaddr_storage ss;		/* remote */
    struct sockaddr *sa = (struct sockaddr *) &ss;
    SOCKADDR_SIZE salen = sizeof(ss);
    MAI_HOSTADDR_STR hostaddr;
    DNS_RR *addr = iter->rr;
    unsigned port = iter->port;
    int     sock;
    char   *bind_addr;
    char   *bind_var;

    dsb_reset(why);				/* Paranoia */

    /*
     * Sanity checks.
     */
    if (dns_rr_to_sa(addr, port, sa, &salen) != 0) {
	msg_warn("%s: skip address type %s: %m",
		 myname, dns_strtype(addr->type));
	dsb_simple(why, "4.4.0", "network address conversion failed: %m");
	return (0);
    }

    /*
     * Initialize.
     */
    if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
	msg_fatal("%s: socket: %m", myname);

    if (inet_windowsize > 0)
	set_inet_windowsize(sock, inet_windowsize);

    /*
     * Allow the sysadmin to specify the source address, for example, as "-o
     * smtp_bind_address=x.x.x.x" in the master.cf file.
     */
#ifdef HAS_IPV6
    if (sa->sa_family == AF_INET6) {
	bind_addr = var_smtp_bind_addr6;
	bind_var = VAR_LMTP_SMTP(BIND_ADDR6);
    } else
#endif
    if (sa->sa_family == AF_INET) {
	bind_addr = var_smtp_bind_addr;
	bind_var = VAR_LMTP_SMTP(BIND_ADDR);
    } else
	bind_var = bind_addr = "";
    if (*bind_addr) {
	int     aierr;
	struct addrinfo *res0;

	if ((aierr = hostaddr_to_sockaddr(bind_addr, (char *) 0, 0, &res0)) != 0)
	    msg_fatal("%s: bad %s parameter: %s: %s",
		      myname, bind_var, bind_addr, MAI_STRERROR(aierr));
	if (bind(sock, res0->ai_addr, res0->ai_addrlen) < 0)
	    msg_warn("%s: bind %s: %m", myname, bind_addr);
	else if (msg_verbose)
	    msg_info("%s: bind %s", myname, bind_addr);
	freeaddrinfo(res0);
    }

    /*
     * When running as a virtual host, bind to the virtual interface so that
     * the mail appears to come from the "right" machine address.
     * 
     * XXX The IPv6 patch expands the null host (as client endpoint) and uses
     * the result as the loopback address list.
     */
    else {
	int     count = 0;
	struct sockaddr *own_addr = 0;
	INET_ADDR_LIST *addr_list = own_inet_addr_list();
	struct sockaddr_storage *s;

	for (s = addr_list->addrs; s < addr_list->addrs + addr_list->used; s++) {
	    if (SOCK_ADDR_FAMILY(s) == sa->sa_family) {
		if (count++ > 0)
		    break;
		own_addr = SOCK_ADDR_PTR(s);
	    }
	}
	if (count == 1 && !sock_addr_in_loopback(own_addr)) {
	    if (bind(sock, own_addr, SOCK_ADDR_LEN(own_addr)) < 0) {
		SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr),
				     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
		msg_warn("%s: bind %s: %m", myname, hostaddr.buf);
	    } else if (msg_verbose) {
		SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr),
				     &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
		msg_info("%s: bind %s", myname, hostaddr.buf);
	    }
	}
    }

    /*
     * Connect to the server.
     */
    if (msg_verbose)
	msg_info("%s: trying: %s[%s] port %d...",
		 myname, STR(iter->host), STR(iter->addr), ntohs(port));

    return (smtp_connect_sock(sock, sa, salen, iter, why, sess_flags));
}
Beispiel #7
0
static int ial_siocgif(INET_ADDR_LIST *addr_list,
		               INET_ADDR_LIST *mask_list,
		               int af)
{
    const char *myname = "inet_addr_local[siocgif]";
    struct in_addr addr;
    struct ifconf ifc;
    struct ifreq *ifr;
    struct ifreq *ifr_mask;
    struct ifreq *the_end;
    int     sock;
    VSTRING *buf;

    /*
     * Get the network interface list. XXX The socket API appears to have no
     * function that returns the number of network interfaces, so we have to
     * guess how much space is needed to store the result.
     * 
     * On BSD-derived systems, ioctl SIOCGIFCONF returns as much information as
     * possible, leaving it up to the application to repeat the request with
     * a larger buffer if the result caused a tight fit.
     * 
     * Other systems, such as Solaris 2.5, generate an EINVAL error when the
     * buffer is too small for the entire result. Workaround: ignore EINVAL
     * errors and repeat the request with a larger buffer. The downside is
     * that the program can run out of memory due to a non-memory problem,
     * making it more difficult than necessary to diagnose the real problem.
     */
    sock = ial_socket(af);
    if (sock < 0)
	return (0);
    buf = vstring_alloc(1024);
    for (;;) {
	ifc.ifc_len = vstring_avail(buf);
	ifc.ifc_buf = vstring_str(buf);
	if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
	    if (errno != EINVAL)
		msg_fatal("%s: ioctl SIOCGIFCONF: %m", myname);
	} else if (ifc.ifc_len < vstring_avail(buf) / 2)
	    break;
	VSTRING_SPACE(buf, vstring_avail(buf) * 2);
    }

    the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
    for (ifr = ifc.ifc_req; ifr < the_end;) {
	if (ifr->ifr_addr.sa_family != af) {
	    ifr = NEXT_INTERFACE(ifr);
	    continue;
	}
	if (af == AF_INET) {
	    addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
	    if (addr.s_addr != INADDR_ANY) {
		inet_addr_list_append(addr_list, &ifr->ifr_addr);
		if (mask_list) {
		    ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr));
		    memcpy((void *) ifr_mask, (void *) ifr, IFREQ_SIZE(ifr));
		    if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0)
			msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname);

		    /*
		     * Note that this SIOCGIFNETMASK has truly screwed up the
		     * contents of sa_len/sa_family. We must fix this
		     * manually to have correct addresses.   --dcs
		     */
		    ifr_mask->ifr_addr.sa_family = af;
#ifdef HAS_SA_LEN
		    ifr_mask->ifr_addr.sa_len = sizeof(struct sockaddr_in);
#endif
		    inet_addr_list_append(mask_list, &ifr_mask->ifr_addr);
		    myfree((void *) ifr_mask);
		}
	    }
	}
#ifdef HAS_IPV6
	else if (af == AF_INET6) {
	    struct sockaddr *sa;

	    sa = SOCK_ADDR_PTR(&ifr->ifr_addr);
	    if (!(IN6_IS_ADDR_UNSPECIFIED(&SOCK_ADDR_IN6_ADDR(sa)))) {
		inet_addr_list_append(addr_list, sa);
		if (mask_list) {
		    /* XXX Assume /128 for everything */
		    struct sockaddr_in6 mask6;

		    mask6 = *SOCK_ADDR_IN6_PTR(sa);
		    memset((void *) &mask6.sin6_addr, ~0,
			   sizeof(mask6.sin6_addr));
		    inet_addr_list_append(mask_list, SOCK_ADDR_PTR(&mask6));
		}
	    }
	}
#endif
	ifr = NEXT_INTERFACE(ifr);
    }
    vstring_free(buf);
    (void) close(sock);
    return (0);
}
Beispiel #8
0
void    master_listen_init(MASTER_SERV *serv)
{
    const char *myname = "master_listen_init";
    char   *end_point;
    int     n;
    MAI_HOSTADDR_STR hostaddr;
    struct sockaddr *sa;

    /*
     * Find out what transport we should use, then create one or more
     * listener sockets. Make the listener sockets non-blocking, so that
     * child processes don't block in accept() when multiple processes are
     * selecting on the same socket and only one of them gets the connection.
     */
    switch (serv->type) {

	/*
	 * UNIX-domain or stream listener endpoints always come as singlets.
	 */
    case MASTER_SERV_TYPE_UNIX:
	set_eugid(var_owner_uid, var_owner_gid);
	serv->listen_fd[0] =
	    LOCAL_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
			 serv->max_proc : var_proc_limit, NON_BLOCKING);
	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
	set_ugid(getuid(), getgid());
	break;

	/*
	 * FIFO listener endpoints always come as singlets.
	 */
    case MASTER_SERV_TYPE_FIFO:
	set_eugid(var_owner_uid, var_owner_gid);
	serv->listen_fd[0] = fifo_listen(serv->name, 0622, NON_BLOCKING);
	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
	set_ugid(getuid(), getgid());
	break;

	/*
	 * INET-domain listener endpoints can be wildcarded (the default) or
	 * bound to specific interface addresses.
	 * 
	 * With dual-stack IPv4/6 systems it does not matter, we have to specify
	 * the addresses anyway, either explicit or wild-card.
	 */
    case MASTER_SERV_TYPE_INET:
	for (n = 0; n < serv->listen_fd_count; n++) {
	    sa = SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv)->addrs + n);
	    SOCKADDR_TO_HOSTADDR(sa, SOCK_ADDR_LEN(sa), &hostaddr,
				 (MAI_SERVPORT_STR *) 0, 0);
	    end_point = concatenate(hostaddr.buf,
				    ":", MASTER_INET_PORT(serv), (char *) 0);
	    serv->listen_fd[n]
		= inet_listen(end_point, serv->max_proc > var_proc_limit ?
			      serv->max_proc : var_proc_limit, NON_BLOCKING);
	    close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC);
	    myfree(end_point);
	}
	break;

	/*
	 * Descriptor passing endpoints always come as singlets.
	 */
#ifdef MASTER_SERV_TYPE_PASS
    case MASTER_SERV_TYPE_PASS:
	set_eugid(var_owner_uid, var_owner_gid);
	serv->listen_fd[0] =
	    PASS_LISTEN(serv->name, serv->max_proc > var_proc_limit ?
			serv->max_proc : var_proc_limit, NON_BLOCKING);
	close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
	set_ugid(getuid(), getgid());
	break;
#endif
    default:
	msg_panic("%s: unknown service type: %d", myname, serv->type);
    }
}
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);
    }
}
Beispiel #10
0
MASTER_SERV *get_master_ent()
{
    VSTRING *buf = vstring_alloc(100);
    VSTRING *junk = vstring_alloc(100);
    MASTER_SERV *serv;
    char   *cp;
    char   *name;
    char   *host = 0;
    char   *port = 0;
    char   *transport;
    int     private;
    int     unprivileged;		/* passed on to child */
    int     chroot;			/* passed on to child */
    char   *command;
    int     n;
    char   *bufp;
    char   *atmp;
    const char *parse_err;
    static char *saved_interfaces = 0;
    char   *err;

    if (master_fp == 0)
	msg_panic("get_master_ent: config file not open");
    if (master_disable == 0)
	msg_panic("get_master_ent: no service disable list");

    /*
     * XXX We cannot change the inet_interfaces setting for a running master
     * process. Listening sockets are inherited by child processes so that
     * closing and reopening those sockets in the master does not work.
     * 
     * Another problem is that library routines still cache results that are
     * based on the old inet_interfaces setting. It is too much trouble to
     * recompute everything.
     * 
     * In order to keep our data structures consistent we ignore changes in
     * inet_interfaces settings, and issue a warning instead.
     */
    if (saved_interfaces == 0)
	saved_interfaces = mystrdup(var_inet_interfaces);

    /*
     * Skip blank lines and comment lines.
     */
    for (;;) {
	if (readllines(buf, master_fp, &master_line_last, &master_line) == 0) {
	    vstring_free(buf);
	    vstring_free(junk);
	    return (0);
	}
	bufp = vstring_str(buf);
	if ((cp = mystrtok(&bufp, master_blanks)) == 0)
	    continue;
	name = cp;
	transport = get_str_ent(&bufp, "transport type", (char *) 0);
	vstring_sprintf(junk, "%s/%s", name, transport);
	if (match_service_match(master_disable, vstring_str(junk)) == 0)
	    break;
    }

    /*
     * Parse one logical line from the configuration file. Initialize service
     * structure members in order.
     */
    serv = (MASTER_SERV *) mymalloc(sizeof(MASTER_SERV));
    serv->next = 0;

    /*
     * Flags member.
     */
    serv->flags = 0;

    /*
     * All servers busy warning timer.
     */
    serv->busy_warn_time = 0;

    /*
     * Service name. Syntax is transport-specific.
     */
    serv->ext_name = mystrdup(name);

    /*
     * Transport type: inet (wild-card listen or virtual) or unix.
     */
#define STR_SAME	!strcmp

    if (STR_SAME(transport, MASTER_XPORT_NAME_INET)) {
	if (!STR_SAME(saved_interfaces, var_inet_interfaces)) {
	    msg_warn("service %s: ignoring %s change",
		     serv->ext_name, VAR_INET_INTERFACES);
	    msg_warn("to change %s, stop and start Postfix",
		     VAR_INET_INTERFACES);
	}
	serv->type = MASTER_SERV_TYPE_INET;
	atmp = mystrdup(name);
	if ((parse_err = host_port(atmp, &host, "", &port, (char *) 0)) != 0)
	    fatal_with_context("%s in \"%s\"", parse_err, name);
	if (*host) {
	    serv->flags |= MASTER_FLAG_INETHOST;/* host:port */
	    MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *)
		mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv)));
	    inet_addr_list_init(MASTER_INET_ADDRLIST(serv));
	    if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0)
		fatal_with_context("bad hostname or network address: %s", name);
	    inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
	    serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
	} else {
	    MASTER_INET_ADDRLIST(serv) =
		strcasecmp(saved_interfaces, INET_INTERFACES_ALL) ?
		own_inet_addr_list() :		/* virtual */
		wildcard_inet_addr_list();	/* wild-card */
	    inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv));
	    serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used;
	}
	MASTER_INET_PORT(serv) = mystrdup(port);
	for (n = 0; /* see below */ ; n++) {
	    if (n >= MASTER_INET_ADDRLIST(serv)->used) {
		serv->flags |= MASTER_FLAG_LOCAL_ONLY;
		break;
	    }
	    if (!sock_addr_in_loopback(SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv)->addrs + n)))
		break;
	}
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_UNIX)) {
	serv->type = MASTER_SERV_TYPE_UNIX;
	serv->listen_fd_count = 1;
	serv->flags |= MASTER_FLAG_LOCAL_ONLY;
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_UXDG)) {
	serv->type = MASTER_SERV_TYPE_UXDG;
	serv->listen_fd_count = 1;
	serv->flags |= MASTER_FLAG_LOCAL_ONLY;
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_FIFO)) {
	serv->type = MASTER_SERV_TYPE_FIFO;
	serv->listen_fd_count = 1;
	serv->flags |= MASTER_FLAG_LOCAL_ONLY;
#ifdef MASTER_SERV_TYPE_PASS
    } else if (STR_SAME(transport, MASTER_XPORT_NAME_PASS)) {
	serv->type = MASTER_SERV_TYPE_PASS;
	serv->listen_fd_count = 1;
	/* If this is a connection screener, remote clients are likely. */
#endif
    } else {
	fatal_with_context("bad transport type: %s", transport);
    }

    /*
     * Service class: public or private.
     */
    private = get_bool_ent(&bufp, "private", "y");