diff options
Diffstat (limited to 'src/postscreen/postscreen_endpt.c')
-rw-r--r-- | src/postscreen/postscreen_endpt.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/postscreen/postscreen_endpt.c b/src/postscreen/postscreen_endpt.c new file mode 100644 index 0000000..335c511 --- /dev/null +++ b/src/postscreen/postscreen_endpt.c @@ -0,0 +1,232 @@ +/*++ +/* NAME +/* postscreen_endpt 3 +/* SUMMARY +/* look up connection endpoint information +/* SYNOPSIS +/* #include <postscreen.h> +/* +/* void psc_endpt_lookup(smtp_client_stream, lookup_done) +/* VSTREAM *smtp_client_stream; +/* void (*lookup_done)(status, smtp_client_stream, +/* smtp_client_addr, smtp_client_port, +/* smtp_server_addr, smtp_server_port) +/* int status; +/* MAI_HOSTADDR_STR *smtp_client_addr; +/* MAI_SERVPORT_STR *smtp_client_port; +/* MAI_HOSTADDR_STR *smtp_server_addr; +/* MAI_SERVPORT_STR *smtp_server_port; +/* AUXILIARY METHODS +/* void psc_endpt_local_lookup(smtp_client_stream, lookup_done) +/* VSTREAM *smtp_client_stream; +/* void (*lookup_done)(status, smtp_client_stream, +/* smtp_client_addr, smtp_client_port, +/* smtp_server_addr, smtp_server_port) +/* int status; +/* MAI_HOSTADDR_STR *smtp_client_addr; +/* MAI_SERVPORT_STR *smtp_client_port; +/* MAI_HOSTADDR_STR *smtp_server_addr; +/* MAI_SERVPORT_STR *smtp_server_port; +/* DESCRIPTION +/* psc_endpt_lookup() looks up remote and local connection +/* endpoint information, either through local system calls, +/* or through an adapter for an up-stream proxy protocol. +/* +/* The following summarizes what the postscreen(8) server +/* expects from a proxy protocol adapter routine. +/* .IP \(bu +/* Accept the same arguments as psc_endpt_lookup(). +/* .IP \(bu +/* Call psc_endpt_local_lookup() to look up connection info +/* when the upstream proxy indicates that the connection is +/* not proxied (e.g., health check probe). +/* .IP \(bu +/* Validate protocol, address and port syntax. Permit only +/* protocols that are configured with the main.cf:inet_protocols +/* setting. +/* .IP \(bu +/* Convert IPv4-in-IPv6 address syntax to IPv4 syntax when +/* both IPv6 and IPv4 support are enabled with main.cf:inet_protocols. +/* .IP \(bu +/* Log a clear warning message that explains why a request +/* fails. +/* .IP \(bu +/* Never talk to the remote SMTP client. +/* .PP +/* Arguments: +/* .IP client_stream +/* A brand-new stream that is connected to the remote client. +/* This argument MUST be passed to psc_endpt_local_lookup() +/* if the up-stream proxy indicates that a connection is not +/* proxied. +/* .IP lookup +/* Call-back routine that reports the result status, address +/* and port information. The result status is -1 in case of +/* error, 0 in case of success. This MUST NOT be called directly +/* if the up-stream proxy indicates that a connection is not +/* proxied; instead this MUST be called indirectly by +/* psc_endpt_local_lookup(). +/* 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 +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <string.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <myaddrinfo.h> +#include <vstream.h> +#include <inet_proto.h> + +/* Global library. */ + +#include <mail_params.h> +#include <haproxy_srvr.h> + +/* Application-specific. */ + +#include <postscreen.h> +#include <postscreen_haproxy.h> + +static INET_PROTO_INFO *proto_info; + +/* psc_sockaddr_to_hostaddr - transform endpoint address and port to string */ + +static int psc_sockaddr_to_hostaddr(struct sockaddr *addr_storage, + SOCKADDR_SIZE addr_storage_len, + MAI_HOSTADDR_STR *addr_buf, + MAI_SERVPORT_STR *port_buf, + int socktype) +{ + int aierr; + + if ((aierr = sockaddr_to_hostaddr(addr_storage, addr_storage_len, + addr_buf, port_buf, socktype)) == 0 + && strncasecmp("::ffff:", addr_buf->buf, 7) == 0 + && strchr((char *) proto_info->sa_family_list, AF_INET) != 0) + memmove(addr_buf->buf, addr_buf->buf + 7, + sizeof(addr_buf->buf) - 7); + return (aierr); +} + +/* psc_endpt_local_lookup - look up local system connection information */ + +void psc_endpt_local_lookup(VSTREAM *smtp_client_stream, + PSC_ENDPT_LOOKUP_FN lookup_done) +{ + struct sockaddr_storage addr_storage; + SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage); + int status; + 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; + + /* + * 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"); + status = -1; + } + + /* + * Convert the remote SMTP client address and port to printable form for + * logging and access control. + */ + else if ((aierr = psc_sockaddr_to_hostaddr( + (struct sockaddr *) &addr_storage, + addr_storage_len, &smtp_client_addr, + &smtp_client_port, SOCK_STREAM)) != 0) { + msg_warn("cannot convert client address/port to string: %s" + " -- dropping this connection", + MAI_STRERROR(aierr)); + status = -1; + } + + /* + * Look up the local SMTP server address and port. + */ + else if (getsockname(vstream_fileno(smtp_client_stream), + (struct sockaddr *) &addr_storage, + &addr_storage_len) < 0) { + msg_warn("getsockname: %m -- dropping this connection"); + status = -1; + } + + /* + * Convert the local SMTP server address and port to printable form for + * logging. + */ + else if ((aierr = psc_sockaddr_to_hostaddr( + (struct sockaddr *) &addr_storage, + addr_storage_len, &smtp_server_addr, + &smtp_server_port, SOCK_STREAM)) != 0) { + msg_warn("cannot convert server address/port to string: %s" + " -- dropping this connection", + MAI_STRERROR(aierr)); + status = -1; + } else { + status = 0; + } + lookup_done(status, smtp_client_stream, + &smtp_client_addr, &smtp_client_port, + &smtp_server_addr, &smtp_server_port); +} + + /* + * Lookup table for available proxy protocols. + */ +typedef struct { + const char *name; + void (*endpt_lookup) (VSTREAM *, PSC_ENDPT_LOOKUP_FN); +} PSC_ENDPT_LOOKUP_INFO; + +static const PSC_ENDPT_LOOKUP_INFO psc_endpt_lookup_info[] = { + NOPROXY_PROTO_NAME, psc_endpt_local_lookup, + HAPROXY_PROTO_NAME, psc_endpt_haproxy_lookup, + 0, +}; + +/* psc_endpt_lookup - look up connection endpoint information */ + +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; + } + } +} |