xref: /netbsd-src/external/ibm-public/postfix/dist/src/postscreen/postscreen_endpt.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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