diff options
Diffstat (limited to '')
-rw-r--r-- | src/global/own_inet_addr.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/src/global/own_inet_addr.c b/src/global/own_inet_addr.c new file mode 100644 index 0000000..d164a20 --- /dev/null +++ b/src/global/own_inet_addr.c @@ -0,0 +1,315 @@ +/*++ +/* NAME +/* own_inet_addr 3 +/* SUMMARY +/* determine if IP address belongs to this mail system instance +/* SYNOPSIS +/* #include <own_inet_addr.h> +/* +/* int own_inet_addr(addr) +/* struct sockaddr *addr; +/* +/* INET_ADDR_LIST *own_inet_addr_list() +/* +/* INET_ADDR_LIST *own_inet_mask_list() +/* +/* int proxy_inet_addr(addr) +/* struct in_addr *addr; +/* +/* INET_ADDR_LIST *proxy_inet_addr_list() +/* DESCRIPTION +/* own_inet_addr() determines if the specified IP address belongs +/* to this mail system instance, i.e. if this mail system instance +/* is supposed to be listening on this specific IP address. +/* +/* own_inet_addr_list() returns the list of all addresses that +/* belong to this mail system instance. +/* +/* own_inet_mask_list() returns the list of all corresponding +/* netmasks. +/* +/* proxy_inet_addr() determines if the specified IP address is +/* listed with the proxy_interfaces configuration parameter. +/* +/* proxy_inet_addr_list() returns the list of all addresses that +/* belong to proxy network interfaces. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <inet_addr_list.h> +#include <inet_addr_local.h> +#include <inet_addr_host.h> +#include <stringops.h> +#include <myaddrinfo.h> +#include <sock_addr.h> +#include <inet_proto.h> + +/* Global library. */ + +#include <mail_params.h> +#include <own_inet_addr.h> + +/* Application-specific. */ + +static INET_ADDR_LIST saved_addr_list; +static INET_ADDR_LIST saved_mask_list; +static INET_ADDR_LIST saved_proxy_list; + +/* own_inet_addr_init - initialize my own address list */ + +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); + + /* + * 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. + */ + 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); + } +} + +/* own_inet_addr - is this my own internet address */ + +int own_inet_addr(struct sockaddr * addr) +{ + int i; + + if (saved_addr_list.used == 0) + own_inet_addr_init(&saved_addr_list, &saved_mask_list); + + for (i = 0; i < saved_addr_list.used; i++) + if (SOCK_ADDR_EQ_ADDR(addr, saved_addr_list.addrs + i)) + return (1); + return (0); +} + +/* own_inet_addr_list - return list of addresses */ + +INET_ADDR_LIST *own_inet_addr_list(void) +{ + if (saved_addr_list.used == 0) + own_inet_addr_init(&saved_addr_list, &saved_mask_list); + + return (&saved_addr_list); +} + +/* own_inet_mask_list - return list of addresses */ + +INET_ADDR_LIST *own_inet_mask_list(void) +{ + if (saved_addr_list.used == 0) + own_inet_addr_init(&saved_addr_list, &saved_mask_list); + + return (&saved_mask_list); +} + +/* proxy_inet_addr_init - initialize my proxy interface list */ + +static void proxy_inet_addr_init(INET_ADDR_LIST *addr_list) +{ + char *hosts; + char *host; + const char *sep = " \t,"; + char *bufp; + + /* + * Parse the proxy_interfaces parameter, and expand any symbolic + * hostnames into IP addresses. + */ + inet_addr_list_init(addr_list); + bufp = hosts = mystrdup(var_proxy_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_PROXY_INTERFACES, host); + myfree(hosts); + + /* + * Weed out duplicate IP addresses. + */ + inet_addr_list_uniq(addr_list); +} + +/* proxy_inet_addr - is this my proxy internet address */ + +int proxy_inet_addr(struct sockaddr * addr) +{ + int i; + + if (*var_proxy_interfaces == 0) + return (0); + + if (saved_proxy_list.used == 0) + proxy_inet_addr_init(&saved_proxy_list); + + for (i = 0; i < saved_proxy_list.used; i++) + if (SOCK_ADDR_EQ_ADDR(addr, saved_proxy_list.addrs + i)) + return (1); + return (0); +} + +/* proxy_inet_addr_list - return list of addresses */ + +INET_ADDR_LIST *proxy_inet_addr_list(void) +{ + if (*var_proxy_interfaces != 0 && saved_proxy_list.used == 0) + proxy_inet_addr_init(&saved_proxy_list); + + return (&saved_proxy_list); +} + +#ifdef TEST +#include <inet_proto.h> + +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); + } +} + +char *var_inet_interfaces; + +int main(int argc, char **argv) +{ + INET_PROTO_INFO *proto_info; + INET_ADDR_LIST *list; + + if (argc != 3) + msg_fatal("usage: %s protocols interface_list (e.g. \"all all\")", + argv[0]); + msg_verbose = 10; + proto_info = inet_proto_init(argv[0], argv[1]); + var_inet_interfaces = argv[2]; + list = own_inet_addr_list(); + inet_addr_list_print(list); + return (0); +} + +#endif |