Postfix3.3.1
postscreen_haproxy.c
[詳解]
1 /*++
2 /* NAME
3 /* postscreen_haproxy 3
4 /* SUMMARY
5 /* haproxy protocol adapter
6 /* SYNOPSIS
7 /* #include <postscreen_haproxy.h>
8 /*
9 /* void psc_endpt_haproxy_lookup(smtp_client_stream, lookup_done)
10 /* VSTRING *smtp_client_stream;
11 /* void (*lookup_done)(status, smtp_client_stream,
12 /* smtp_client_addr, smtp_client_port,
13 /* smtp_server_addr, smtp_server_port)
14 /* int status;
15 /* MAI_HOSTADDR_STR *smtp_client_addr;
16 /* MAI_SERVPORT_STR *smtp_client_port;
17 /* MAI_HOSTADDR_STR *smtp_server_addr;
18 /* MAI_SERVPORT_STR *smtp_server_port;
19 /* DESCRIPTION
20 /* psc_endpt_haproxy_lookup() looks up connection endpoint
21 /* information via the haproxy protocol. Arguments and results
22 /* conform to the postscreen_endpt(3) API.
23 /* LICENSE
24 /* .ad
25 /* .fi
26 /* The Secure Mailer license must be distributed with this software.
27 /* AUTHOR(S)
28 /* Wietse Venema
29 /* IBM T.J. Watson Research
30 /* P.O. Box 704
31 /* Yorktown Heights, NY 10598, USA
32 /*
33 /* Wietse Venema
34 /* Google, Inc.
35 /* 111 8th Avenue
36 /* New York, NY 10011, USA
37 /*--*/
38 
39 /* System library. */
40 
41 #include <sys_defs.h>
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 
46 /* Utility library. */
47 
48 #include <msg.h>
49 #include <mymalloc.h>
50 #include <events.h>
51 #include <myaddrinfo.h>
52 #include <vstream.h>
53 #include <vstring.h>
54 #include <stringops.h>
55 
56 /* Global library. */
57 
58 #include <haproxy_srvr.h>
59 #include <mail_params.h>
60 
61 /* Application-specific. */
62 
63 #include <postscreen.h>
64 #include <postscreen_haproxy.h>
65 
66  /*
67  * Per-session state.
68  */
69 typedef struct {
74 
75 /* psc_endpt_haproxy_event - read or time event */
76 
77 static void psc_endpt_haproxy_event(int event, void *context)
78 {
79  const char *myname = "psc_endpt_haproxy_event";
80  PSC_HAPROXY_STATE *state = (PSC_HAPROXY_STATE *) context;
81  int status = 0;
82  MAI_HOSTADDR_STR smtp_client_addr;
83  MAI_SERVPORT_STR smtp_client_port;
84  MAI_HOSTADDR_STR smtp_server_addr;
85  MAI_SERVPORT_STR smtp_server_port;
86  int last_char = 0;
87  const char *err;
88  VSTRING *escape_buf;
89  char read_buf[HAPROXY_MAX_LEN];
90  ssize_t read_len;
91  char *cp;
92 
93  /*
94  * We must not read(2) past the <CR><LF> that terminates the haproxy
95  * line. For efficiency reasons we read the entire haproxy line in one
96  * read(2) call when we know that the line is unfragmented. In the rare
97  * case that the line is fragmented, we fall back and read(2) it one
98  * character at a time.
99  */
100  switch (event) {
101  case EVENT_TIME:
102  msg_warn("haproxy read: time limit exceeded");
103  status = -1;
104  break;
105  case EVENT_READ:
106  /* Determine the initial VSTREAM read(2) buffer size. */
107  if (VSTRING_LEN(state->buffer) == 0) {
108  if ((read_len = recv(vstream_fileno(state->stream),
109  read_buf, sizeof(read_buf) - 1, MSG_PEEK)) > 0
110  && ((cp = memchr(read_buf, '\n', read_len)) != 0)) {
111  read_len = cp - read_buf + 1;
112  } else {
113  read_len = 1;
114  }
117  }
118  /* Drain the VSTREAM buffer, otherwise this pseudo-thread will hang. */
119  do {
120  if ((last_char = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) {
121  if (vstream_ferror(state->stream))
122  msg_warn("haproxy read: %m");
123  else
124  msg_warn("haproxy read: lost connection");
125  status = -1;
126  break;
127  }
128  if (VSTRING_LEN(state->buffer) >= HAPROXY_MAX_LEN) {
129  msg_warn("haproxy read: line too long");
130  status = -1;
131  break;
132  }
133  VSTRING_ADDCH(state->buffer, last_char);
134  } while (vstream_peek(state->stream) > 0);
135  break;
136  }
137 
138  /*
139  * Parse the haproxy line. Note: the haproxy_srvr_parse() routine
140  * performs address protocol checks, address and port syntax checks, and
141  * converts IPv4-in-IPv6 address string syntax (::ffff:1.2.3.4) to IPv4
142  * syntax where permitted by the main.cf:inet_protocols setting.
143  */
144  if (status == 0 && last_char == '\n') {
145  VSTRING_TERMINATE(state->buffer);
146  if ((err = haproxy_srvr_parse(vstring_str(state->buffer),
147  &smtp_client_addr, &smtp_client_port,
148  &smtp_server_addr, &smtp_server_port)) != 0) {
149  escape_buf = vstring_alloc(HAPROXY_MAX_LEN + 2);
150  escape(escape_buf, vstring_str(state->buffer),
151  VSTRING_LEN(state->buffer));
152  msg_warn("haproxy read: %s: %s", err, vstring_str(escape_buf));
153  status = -1;
154  vstring_free(escape_buf);
155  }
156  }
157 
158  /*
159  * Are we done yet?
160  */
161  if (status < 0 || last_char == '\n') {
163  psc_endpt_haproxy_event, context);
164  vstream_control(state->stream,
167  state->notify(status, state->stream,
168  &smtp_client_addr, &smtp_client_port,
169  &smtp_server_addr, &smtp_server_port);
170  /* Note: the stream may be closed at this point. */
171  vstring_free(state->buffer);
172  myfree((void *) state);
173  }
174 }
175 
176 /* psc_endpt_haproxy_lookup - event-driven haproxy client */
177 
179  PSC_ENDPT_LOOKUP_FN notify)
180 {
181  const char *myname = "psc_endpt_haproxy_lookup";
182  PSC_HAPROXY_STATE *state;
183 
184  /*
185  * Prepare the per-session state. XXX To improve overload behavior,
186  * maintain a pool of these so that we can reduce memory allocator
187  * activity.
188  */
189  state = (PSC_HAPROXY_STATE *) mymalloc(sizeof(*state));
190  state->stream = stream;
191  state->notify = notify;
192  state->buffer = vstring_alloc(100);
193 
194  /*
195  * Read the haproxy line.
196  */
197  PSC_READ_EVENT_REQUEST(vstream_fileno(stream), psc_endpt_haproxy_event,
198  (void *) state, var_psc_uproxy_tmout);
199 }
#define VSTREAM_EOF
Definition: vstream.h:110
void myfree(void *ptr)
Definition: mymalloc.c:207
#define vstring_str(vp)
Definition: vstring.h:71
#define PSC_CLEAR_EVENT_REQUEST(fd, time_act, context)
Definition: postscreen.h:341
#define VSTREAM_GETC(vp)
Definition: vstream.h:108
VSTRING * escape(VSTRING *, const char *, ssize_t)
Definition: unescape.c:133
void(* PSC_ENDPT_LOOKUP_FN)(int, VSTREAM *, MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *, MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *)
Definition: postscreen.h:561
#define VSTRING_LEN(vp)
Definition: vstring.h:72
const char * haproxy_srvr_parse(const char *str, MAI_HOSTADDR_STR *smtp_client_addr, MAI_SERVPORT_STR *smtp_client_port, MAI_HOSTADDR_STR *smtp_server_addr, MAI_SERVPORT_STR *smtp_server_port)
Definition: haproxy_srvr.c:160
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
PSC_ENDPT_LOOKUP_FN notify
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
void psc_endpt_haproxy_lookup(VSTREAM *stream, PSC_ENDPT_LOOKUP_FN notify)
#define PSC_READ_EVENT_REQUEST(fd, action, context, timeout)
Definition: postscreen.h:325
#define CA_VSTREAM_CTL_BUFSIZE(v)
Definition: vstream.h:169
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define EVENT_READ
Definition: events.h:40
#define VSTREAM_BUFSIZE
Definition: vstream.h:92
#define vstream_peek(vp)
Definition: vstream.h:232
#define EVENT_TIME
Definition: events.h:43
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define vstream_fileno(vp)
Definition: vstream.h:115
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
#define vstream_ferror(vp)
Definition: vstream.h:120
#define HAPROXY_MAX_LEN
Definition: haproxy_srvr.h:27
int var_psc_uproxy_tmout
Definition: postscreen.c:522
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150