1 /*        $NetBSD: postscreen_endpt.c,v 1.5 2025/02/25 19:15: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_endpt_local_lookup - look up local system connection information */
116 
psc_endpt_local_lookup(VSTREAM * smtp_client_stream,PSC_ENDPT_LOOKUP_FN lookup_done)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 = sizeof(addr_storage);
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     /*
130      * Look up the remote SMTP client address and port.
131      */
132     if (getpeername(vstream_fileno(smtp_client_stream), (struct sockaddr *)
133                         &addr_storage, &addr_storage_len) < 0) {
134           msg_warn("getpeername: %m -- dropping this connection");
135           status = -1;
136     }
137 
138     /*
139      * Convert the remote SMTP client address and port to printable form for
140      * logging and access control.
141      */
142     else if ((aierr = sane_sockaddr_to_hostaddr(
143                                                     (struct sockaddr *) &addr_storage,
144                                                   addr_storage_len, &smtp_client_addr,
145                                             &smtp_client_port, SOCK_STREAM)) != 0) {
146           msg_warn("cannot convert client address/port to string: %s"
147                      " -- dropping this connection",
148                      MAI_STRERROR(aierr));
149           status = -1;
150     }
151 
152     /*
153      * Look up the local SMTP server address and port.
154      */
155     else if (getsockname(vstream_fileno(smtp_client_stream),
156                                (struct sockaddr *) &addr_storage,
157                                &addr_storage_len) < 0) {
158           msg_warn("getsockname: %m -- dropping this connection");
159           status = -1;
160     }
161 
162     /*
163      * Convert the local SMTP server address and port to printable form for
164      * logging.
165      */
166     else if ((aierr = sane_sockaddr_to_hostaddr(
167                                                     (struct sockaddr *) &addr_storage,
168                                                   addr_storage_len, &smtp_server_addr,
169                                             &smtp_server_port, SOCK_STREAM)) != 0) {
170           msg_warn("cannot convert server address/port to string: %s"
171                      " -- dropping this connection",
172                      MAI_STRERROR(aierr));
173           status = -1;
174     } else {
175           status = 0;
176     }
177     lookup_done(status, smtp_client_stream,
178                     &smtp_client_addr, &smtp_client_port,
179                     &smtp_server_addr, &smtp_server_port);
180 }
181 
182  /*
183   * Lookup table for available proxy protocols.
184   */
185 typedef struct {
186     const char *name;
187     void    (*endpt_lookup) (VSTREAM *, PSC_ENDPT_LOOKUP_FN);
188 } PSC_ENDPT_LOOKUP_INFO;
189 
190 static const PSC_ENDPT_LOOKUP_INFO psc_endpt_lookup_info[] = {
191     NOPROXY_PROTO_NAME, psc_endpt_local_lookup,
192     HAPROXY_PROTO_NAME, psc_endpt_haproxy_lookup,
193     0,
194 };
195 
196 /* psc_endpt_lookup - look up connection endpoint information */
197 
psc_endpt_lookup(VSTREAM * smtp_client_stream,PSC_ENDPT_LOOKUP_FN notify)198 void    psc_endpt_lookup(VSTREAM *smtp_client_stream,
199                                        PSC_ENDPT_LOOKUP_FN notify)
200 {
201     const PSC_ENDPT_LOOKUP_INFO *pp;
202 
203     if (proto_info == 0)
204           proto_info = inet_proto_info();
205 
206     for (pp = psc_endpt_lookup_info; /* see below */ ; pp++) {
207           if (pp->name == 0)
208               msg_fatal("unsupported %s value: %s",
209                           VAR_PSC_UPROXY_PROTO, var_psc_uproxy_proto);
210           if (strcmp(var_psc_uproxy_proto, pp->name) == 0) {
211               pp->endpt_lookup(smtp_client_stream, notify);
212               return;
213           }
214     }
215 }
216