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