xref: /netbsd-src/external/ibm-public/postfix/dist/src/postscreen/postscreen_endpt.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: postscreen_endpt.c,v 1.4 2022/10/08 16:12:48 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_sockaddr_to_hostaddr - transform endpoint address and port to string */
116 
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)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 
psc_endpt_local_lookup(VSTREAM * smtp_client_stream,PSC_ENDPT_LOOKUP_FN lookup_done)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 
psc_endpt_lookup(VSTREAM * smtp_client_stream,PSC_ENDPT_LOOKUP_FN notify)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