1 /* $NetBSD: postscreen_endpt.c,v 1.3 2020/03/18 19:05:19 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* postscreen_endpt 3 6 /* SUMMARY 7 /* look up connection endpoint information 8 /* SYNOPSIS 9 /* #include <postscreen.h> 10 /* 11 /* void psc_endpt_lookup(smtp_client_stream, lookup_done) 12 /* VSTREAM *smtp_client_stream; 13 /* void (*lookup_done)(status, smtp_client_stream, 14 /* smtp_client_addr, smtp_client_port, 15 /* smtp_server_addr, smtp_server_port) 16 /* int status; 17 /* MAI_HOSTADDR_STR *smtp_client_addr; 18 /* MAI_SERVPORT_STR *smtp_client_port; 19 /* MAI_HOSTADDR_STR *smtp_server_addr; 20 /* MAI_SERVPORT_STR *smtp_server_port; 21 /* AUXILIARY METHODS 22 /* void psc_endpt_local_lookup(smtp_client_stream, lookup_done) 23 /* VSTREAM *smtp_client_stream; 24 /* void (*lookup_done)(status, smtp_client_stream, 25 /* smtp_client_addr, smtp_client_port, 26 /* smtp_server_addr, smtp_server_port) 27 /* int status; 28 /* MAI_HOSTADDR_STR *smtp_client_addr; 29 /* MAI_SERVPORT_STR *smtp_client_port; 30 /* MAI_HOSTADDR_STR *smtp_server_addr; 31 /* MAI_SERVPORT_STR *smtp_server_port; 32 /* DESCRIPTION 33 /* psc_endpt_lookup() looks up remote and local connection 34 /* endpoint information, either through local system calls, 35 /* or through an adapter for an up-stream proxy protocol. 36 /* 37 /* The following summarizes what the postscreen(8) server 38 /* expects from a proxy protocol adapter routine. 39 /* .IP \(bu 40 /* Accept the same arguments as psc_endpt_lookup(). 41 /* .IP \(bu 42 /* Call psc_endpt_local_lookup() to look up connection info 43 /* when the upstream proxy indicates that the connection is 44 /* not proxied (e.g., health check probe). 45 /* .IP \(bu 46 /* Validate protocol, address and port syntax. Permit only 47 /* protocols that are configured with the main.cf:inet_protocols 48 /* setting. 49 /* .IP \(bu 50 /* Convert IPv4-in-IPv6 address syntax to IPv4 syntax when 51 /* both IPv6 and IPv4 support are enabled with main.cf:inet_protocols. 52 /* .IP \(bu 53 /* Log a clear warning message that explains why a request 54 /* fails. 55 /* .IP \(bu 56 /* Never talk to the remote SMTP client. 57 /* .PP 58 /* Arguments: 59 /* .IP client_stream 60 /* A brand-new stream that is connected to the remote client. 61 /* This argument MUST be passed to psc_endpt_local_lookup() 62 /* if the up-stream proxy indicates that a connection is not 63 /* proxied. 64 /* .IP lookup 65 /* Call-back routine that reports the result status, address 66 /* and port information. The result status is -1 in case of 67 /* error, 0 in case of success. This MUST NOT be called directly 68 /* if the up-stream proxy indicates that a connection is not 69 /* proxied; instead this MUST be called indirectly by 70 /* psc_endpt_local_lookup(). 71 /* LICENSE 72 /* .ad 73 /* .fi 74 /* The Secure Mailer license must be distributed with this software. 75 /* AUTHOR(S) 76 /* Wietse Venema 77 /* IBM T.J. Watson Research 78 /* P.O. Box 704 79 /* Yorktown Heights, NY 10598, USA 80 /* 81 /* Wietse Venema 82 /* Google, Inc. 83 /* 111 8th Avenue 84 /* New York, NY 10011, USA 85 /*--*/ 86 87 /* System library. */ 88 89 #include <sys_defs.h> 90 #include <string.h> 91 92 #ifdef STRCASECMP_IN_STRINGS_H 93 #include <strings.h> 94 #endif 95 96 /* Utility library. */ 97 98 #include <msg.h> 99 #include <myaddrinfo.h> 100 #include <vstream.h> 101 #include <inet_proto.h> 102 103 /* Global library. */ 104 105 #include <mail_params.h> 106 #include <haproxy_srvr.h> 107 108 /* Application-specific. */ 109 110 #include <postscreen.h> 111 #include <postscreen_haproxy.h> 112 113 static INET_PROTO_INFO *proto_info; 114 115 /* psc_sockaddr_to_hostaddr - transform endpoint address and port to string */ 116 117 static int psc_sockaddr_to_hostaddr(struct sockaddr *addr_storage, 118 SOCKADDR_SIZE addr_storage_len, 119 MAI_HOSTADDR_STR *addr_buf, 120 MAI_SERVPORT_STR *port_buf, 121 int socktype) 122 { 123 int aierr; 124 125 if ((aierr = sockaddr_to_hostaddr(addr_storage, addr_storage_len, 126 addr_buf, port_buf, socktype)) == 0 127 && strncasecmp("::ffff:", addr_buf->buf, 7) == 0 128 && strchr((char *) proto_info->sa_family_list, AF_INET) != 0) 129 memmove(addr_buf->buf, addr_buf->buf + 7, 130 sizeof(addr_buf->buf) - 7); 131 return (aierr); 132 } 133 134 /* psc_endpt_local_lookup - look up local system connection information */ 135 136 void psc_endpt_local_lookup(VSTREAM *smtp_client_stream, 137 PSC_ENDPT_LOOKUP_FN lookup_done) 138 { 139 struct sockaddr_storage addr_storage; 140 SOCKADDR_SIZE addr_storage_len = sizeof(addr_storage); 141 int status; 142 MAI_HOSTADDR_STR smtp_client_addr; 143 MAI_SERVPORT_STR smtp_client_port; 144 MAI_HOSTADDR_STR smtp_server_addr; 145 MAI_SERVPORT_STR smtp_server_port; 146 int aierr; 147 148 /* 149 * Look up the remote SMTP client address and port. 150 */ 151 if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *) 152 &addr_storage, &addr_storage_len) < 0) { 153 msg_warn("getpeername: %m -- dropping this connection"); 154 status = -1; 155 } 156 157 /* 158 * Convert the remote SMTP client address and port to printable form for 159 * logging and access control. 160 */ 161 else if ((aierr = psc_sockaddr_to_hostaddr( 162 (struct sockaddr *) &addr_storage, 163 addr_storage_len, &smtp_client_addr, 164 &smtp_client_port, SOCK_STREAM)) != 0) { 165 msg_warn("cannot convert client address/port to string: %s" 166 " -- dropping this connection", 167 MAI_STRERROR(aierr)); 168 status = -1; 169 } 170 171 /* 172 * Look up the local SMTP server address and port. 173 */ 174 else if (getsockname(vstream_fileno(smtp_client_stream), 175 (struct sockaddr *) &addr_storage, 176 &addr_storage_len) < 0) { 177 msg_warn("getsockname: %m -- dropping this connection"); 178 status = -1; 179 } 180 181 /* 182 * Convert the local SMTP server address and port to printable form for 183 * logging. 184 */ 185 else if ((aierr = psc_sockaddr_to_hostaddr( 186 (struct sockaddr *) &addr_storage, 187 addr_storage_len, &smtp_server_addr, 188 &smtp_server_port, SOCK_STREAM)) != 0) { 189 msg_warn("cannot convert server address/port to string: %s" 190 " -- dropping this connection", 191 MAI_STRERROR(aierr)); 192 status = -1; 193 } else { 194 status = 0; 195 } 196 lookup_done(status, smtp_client_stream, 197 &smtp_client_addr, &smtp_client_port, 198 &smtp_server_addr, &smtp_server_port); 199 } 200 201 /* 202 * Lookup table for available proxy protocols. 203 */ 204 typedef struct { 205 const char *name; 206 void (*endpt_lookup) (VSTREAM *, PSC_ENDPT_LOOKUP_FN); 207 } PSC_ENDPT_LOOKUP_INFO; 208 209 static const PSC_ENDPT_LOOKUP_INFO psc_endpt_lookup_info[] = { 210 NOPROXY_PROTO_NAME, psc_endpt_local_lookup, 211 HAPROXY_PROTO_NAME, psc_endpt_haproxy_lookup, 212 0, 213 }; 214 215 /* psc_endpt_lookup - look up connection endpoint information */ 216 217 void psc_endpt_lookup(VSTREAM *smtp_client_stream, 218 PSC_ENDPT_LOOKUP_FN notify) 219 { 220 const PSC_ENDPT_LOOKUP_INFO *pp; 221 222 if (proto_info == 0) 223 proto_info = inet_proto_info(); 224 225 for (pp = psc_endpt_lookup_info; /* see below */ ; pp++) { 226 if (pp->name == 0) 227 msg_fatal("unsupported %s value: %s", 228 VAR_PSC_UPROXY_PROTO, var_psc_uproxy_proto); 229 if (strcmp(var_psc_uproxy_proto, pp->name) == 0) { 230 pp->endpt_lookup(smtp_client_stream, notify); 231 return; 232 } 233 } 234 } 235