1 /* $NetBSD: postscreen_endpt.c,v 1.6 2026/05/09 18:49: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 const INET_PROTO_INFO *proto_info; 114 115 /* psc_endpt_local_lookup - look up local system connection information */ 116 117 void psc_endpt_local_lookup(VSTREAM *smtp_client_stream, 118 PSC_ENDPT_LOOKUP_FN lookup_done) 119 { 120 struct sockaddr_storage addr_storage; 121 SOCKADDR_SIZE addr_storage_len; 122 int status; 123 MAI_HOSTADDR_STR smtp_client_addr; 124 MAI_SERVPORT_STR smtp_client_port; 125 MAI_HOSTADDR_STR smtp_server_addr; 126 MAI_SERVPORT_STR smtp_server_port; 127 int aierr; 128 129 #define RESET_ADDR_STORAGE_LEN() (addr_storage_len = sizeof(addr_storage)) 130 131 /* 132 * Look up the remote SMTP client address and port. 133 */ 134 if (RESET_ADDR_STORAGE_LEN(), 135 getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *) 136 &addr_storage, &addr_storage_len) < 0) { 137 msg_warn("getpeername: %m -- dropping this connection"); 138 status = -1; 139 } 140 141 /* 142 * Convert the remote SMTP client address and port to printable form for 143 * logging and access control. Note: this may change addr_storage and 144 * addr_storage_len. 145 */ 146 else if ((aierr = sane_sockaddr_to_hostaddr( 147 (struct sockaddr *) &addr_storage, 148 &addr_storage_len, &smtp_client_addr, 149 &smtp_client_port, SOCK_STREAM)) != 0) { 150 msg_warn("cannot convert client address/port to string: %s" 151 " -- dropping this connection", 152 MAI_STRERROR(aierr)); 153 status = -1; 154 } 155 156 /* 157 * Look up the local SMTP server address and port. Be sure to reset the 158 * addr_storage_len value. 159 */ 160 else if (RESET_ADDR_STORAGE_LEN(), 161 getsockname(vstream_fileno(smtp_client_stream), 162 (struct sockaddr *) &addr_storage, 163 &addr_storage_len) < 0) { 164 msg_warn("getsockname: %m -- dropping this connection"); 165 status = -1; 166 } 167 168 /* 169 * Convert the local SMTP server address and port to printable form for 170 * logging. This may also change addr_storage and addr_storage_len, but 171 * those variables are dead. 172 */ 173 else if ((aierr = sane_sockaddr_to_hostaddr( 174 (struct sockaddr *) &addr_storage, 175 &addr_storage_len, &smtp_server_addr, 176 &smtp_server_port, SOCK_STREAM)) != 0) { 177 msg_warn("cannot convert server address/port to string: %s" 178 " -- dropping this connection", 179 MAI_STRERROR(aierr)); 180 status = -1; 181 } else { 182 status = 0; 183 } 184 lookup_done(status, smtp_client_stream, 185 &smtp_client_addr, &smtp_client_port, 186 &smtp_server_addr, &smtp_server_port); 187 } 188 189 /* 190 * Lookup table for available proxy protocols. 191 */ 192 typedef struct { 193 const char *name; 194 void (*endpt_lookup) (VSTREAM *, PSC_ENDPT_LOOKUP_FN); 195 } PSC_ENDPT_LOOKUP_INFO; 196 197 static const PSC_ENDPT_LOOKUP_INFO psc_endpt_lookup_info[] = { 198 NOPROXY_PROTO_NAME, psc_endpt_local_lookup, 199 HAPROXY_PROTO_NAME, psc_endpt_haproxy_lookup, 200 0, 201 }; 202 203 /* psc_endpt_lookup - look up connection endpoint information */ 204 205 void psc_endpt_lookup(VSTREAM *smtp_client_stream, 206 PSC_ENDPT_LOOKUP_FN notify) 207 { 208 const PSC_ENDPT_LOOKUP_INFO *pp; 209 210 if (proto_info == 0) 211 proto_info = inet_proto_info(); 212 213 for (pp = psc_endpt_lookup_info; /* see below */ ; pp++) { 214 if (pp->name == 0) 215 msg_fatal("unsupported %s value: %s", 216 VAR_PSC_UPROXY_PROTO, var_psc_uproxy_proto); 217 if (strcmp(var_psc_uproxy_proto, pp->name) == 0) { 218 pp->endpt_lookup(smtp_client_stream, notify); 219 return; 220 } 221 } 222 } 223