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