Mstdlib-1.24.0
m_io_proxy_protocol.h
1/* The MIT License (MIT)
2 *
3 * Copyright (c) 2020 Monetra Technologies, LLC.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#ifndef __M_IO_PROXY_PROTOCOL_H__
25#define __M_IO_PROXY_PROTOCOL_H__
26
27#include <mstdlib/base/m_defs.h>
28#include <mstdlib/base/m_types.h>
29#include <mstdlib/io/m_io.h>
30#include <mstdlib/io/m_event.h>
31
32__BEGIN_DECLS
33
34/*! \addtogroup m_io_proxy_protocol Proxy Protocol
35 * \ingroup m_eventio_base_addon
36 *
37 * # Overview
38 *
39 * Inbound or outbound connection layer for handling The PROXY protocol
40 * as defined by HAProxy.
41 *
42 * Supports versions:
43 * - 1
44 * - 2
45 *
46 * Source is the client connecting to the system (Client). Destination is the
47 * server accepting the connection which will then relay using proxy protocol
48 * (proxy server). There can be multiple proxies in a chain between the source
49 * and the final server that is going to process the data. A such the destination
50 * address may not be the connection address for the final server's connection.
51 *
52 * # Examples
53 *
54 * ## Proxy Server
55 *
56 * This server accepts inbound connections, and sends the data to another
57 * system using the proxy protocol. The inbound client is not using proxy protocol.
58 * The server the proxy is relaying the data to is using proxy protocol.
59 *
60 * `client <-> proxy server example (sends proxy protocol) <-> final server (receives proxy protocol) `
61 *
62 * \code{.c}
63 * #include <mstdlib/mstdlib.h>
64 * #include <mstdlib/mstdlib_io.h>
65 *
66 * typedef struct {
67 * M_buf_t *source_to_dest_buf;
68 * M_buf_t *dest_to_source_buf;
69 * M_io_t *source_io;
70 * M_io_t *dest_io;
71 * } ldata_t;
72 *
73 * static M_dns_t *dns;
74 *
75 * static void destination_cb(M_event_t *el, M_event_type_t etype, M_io_t *io, void *thunk)
76 * {
77 * ldata_t *ldata = thunk;
78 * char error[256] = { 0 };
79 * M_bool clean = M_FALSE;
80 *
81 * switch (etype) {
82 * case M_EVENT_TYPE_CONNECTED:
83 * M_printf("CONNECTED TO SERVER: %s%s%s:%d\n",
84 * M_io_net_get_type(io)==M_IO_NET_IPV6?"[":"",
85 * M_io_net_get_ipaddr(io),
86 * M_io_net_get_type(io)==M_IO_NET_IPV6?"]":"",
87 * M_io_net_get_port(io));
88 * break;
89 * case M_EVENT_TYPE_READ:
90 * M_io_read_into_buf(io, ldata->dest_to_source_buf);
91 * if (M_buf_len(ldata->dest_to_source_buf) > 0) {
92 * M_io_write_from_buf(ldata->source_io, ldata->dest_to_source_buf);
93 * }
94 * break;
95 * case M_EVENT_TYPE_WRITE:
96 * if (M_buf_len(ldata->source_to_dest_buf) > 0) {
97 * M_io_write_from_buf(io, ldata->source_to_dest_buf);
98 * }
99 * break;
100 * case M_EVENT_TYPE_DISCONNECTED:
101 * case M_EVENT_TYPE_ACCEPT:
102 * case M_EVENT_TYPE_ERROR:
103 * case M_EVENT_TYPE_OTHER:
104 * if (etype == M_EVENT_TYPE_DISCONNECTED) {
105 * clean = M_TRUE;
106 * } else {
107 * M_io_get_error_string(io, error, sizeof(error));
108 * }
109 * M_printf("SERVER %s: %s%s%s:%d (%s%s%s)\n",
110 * etype == M_EVENT_TYPE_DISCONNECTED ? "DISCONNECTED" : "ABORT",
111 * M_io_net_get_type(io)==M_IO_NET_IPV6?"[":"",
112 * M_io_net_get_ipaddr(io),
113 * M_io_net_get_type(io)==M_IO_NET_IPV6?"]":"",
114 * M_io_net_get_port(io),
115 * clean?"clean":"unclean", clean?"":" - ", clean?"":error);
116 *
117 * M_io_disconnect(ldata->source_io);
118 * break;
119 * }
120 * }
121 *
122 * static void source_cb(M_event_t *el, M_event_type_t etype, M_io_t *io, void *thunk)
123 * {
124 * M_io_t *io_out = NULL;
125 * ldata_t *ldata = thunk;
126 * char error[256] = { 0 };
127 * M_bool clean = M_FALSE;
128 * M_io_error_t ioerr;
129 *
130 * switch (etype) {
131 * case M_EVENT_TYPE_CONNECTED:
132 * M_printf("CLIENT CONNECTED: %s%s%s:%d\n",
133 * M_io_net_get_type(io)==M_IO_NET_IPV6?"[":"",
134 * M_io_net_get_ipaddr(io),
135 * M_io_net_get_type(io)==M_IO_NET_IPV6?"]":"",
136 * M_io_net_get_port(io));
137 *
138 * // Create a connetion to the destination echo server.
139 * ioerr = M_io_net_client_create(&io_out, dns, "localhost", 8999, M_IO_NET_ANY);
140 * if (ioerr != M_IO_ERROR_SUCCESS) {
141 * M_printf("Could not create client: %s\n", M_io_error_string(ioerr));
142 * M_io_destroy(io);
143 * }
144 * // Add the proxy protocol to the destination connection so the
145 * // source information will be relayed to the echo server.
146 * M_io_proxy_protocol_outbound_add(io_out, NULL, M_IO_PROXY_PROTOCOL_FLAG_NONE);
147 * M_io_proxy_protocol_set_source_endpoints(io_out, M_io_net_get_ipaddr(io), M_io_net_get_server_ipaddr(io), M_io_net_get_ephemeral_port(io), M_io_net_get_port(io));
148 *
149 * // Store the echo server's io object so we can communicate with it.
150 * ldata->dest_io = io_out;
151 *
152 * M_event_add(el, io_out, destination_cb, ldata);
153 * break;
154 * case M_EVENT_TYPE_READ:
155 * M_io_read_into_buf(io, ldata->source_to_dest_buf);
156 * if (M_buf_len(ldata->source_to_dest_buf) > 0) {
157 * M_io_write_from_buf(ldata->dest_io, ldata->source_to_dest_buf);
158 * }
159 * break;
160 * case M_EVENT_TYPE_WRITE:
161 * if (M_buf_len(ldata->dest_to_source_buf) > 0) {
162 * M_io_write_from_buf(io, ldata->dest_to_source_buf);
163 * }
164 * break;
165 * case M_EVENT_TYPE_DISCONNECTED:
166 * case M_EVENT_TYPE_ACCEPT:
167 * case M_EVENT_TYPE_ERROR:
168 * case M_EVENT_TYPE_OTHER:
169 * if (etype == M_EVENT_TYPE_DISCONNECTED) {
170 * clean = M_TRUE;
171 * } else {
172 * M_io_get_error_string(io, error, sizeof(error));
173 * }
174 * M_printf("CLIENT %s: %s%s%s:%d (%s%s%s)\n",
175 * etype == M_EVENT_TYPE_DISCONNECTED ? "DISCONNECTED" : "ABORT",
176 * M_io_net_get_type(io)==M_IO_NET_IPV6?"[":"",
177 * M_io_net_get_ipaddr(io),
178 * M_io_net_get_type(io)==M_IO_NET_IPV6?"]":"",
179 * M_io_net_get_port(io),
180 * clean?"clean":"unclean", clean?"":" - ", clean?"":error);
181 *
182 * M_io_destroy(ldata->dest_io);
183 * M_io_destroy(io);
184 * M_buf_cancel(ldata->source_to_dest_buf);
185 * M_buf_cancel(ldata->dest_to_source_buf);
186 * M_free(ldata);
187 * break;
188 * }
189 * }
190 *
191 * static void source_listen_cb(M_event_t *el, M_event_type_t etype, M_io_t *io, void *thunk)
192 * {
193 * M_io_t *io_out = NULL;
194 * ldata_t *ldata;
195 * M_io_error_t ioerr;
196 * char error[256] = { 0 };
197 *
198 * (void)thunk;
199 *
200 * switch (etype) {
201 * case M_EVENT_TYPE_ACCEPT:
202 * // Accept connection form source and create an io object to communicate with it.
203 * ioerr = M_io_accept(&io_out, io);
204 * if (ioerr == M_IO_ERROR_WOULDBLOCK) {
205 * return;
206 * } else if (ioerr != M_IO_ERROR_SUCCESS || io_out == NULL) {
207 * M_io_get_error_string(io, error, sizeof(error));
208 * M_printf("ACCEPT FAILURE: %s\n", error);
209 * M_io_destroy(io_out);
210 * }
211 *
212 * ldata = M_malloc_zero(sizeof(*ldata));
213 * ldata->source_to_dest_buf = M_buf_create();
214 * ldata->dest_to_source_buf = M_buf_create();
215 * ldata->source_io = io_out;
216 *
217 * M_event_add(el, io_out, source_cb, ldata);
218 * break;
219 * case M_EVENT_TYPE_CONNECTED:
220 * case M_EVENT_TYPE_READ:
221 * case M_EVENT_TYPE_WRITE:
222 * break;
223 * case M_EVENT_TYPE_DISCONNECTED:
224 * case M_EVENT_TYPE_ERROR:
225 * case M_EVENT_TYPE_OTHER:
226 * M_io_destroy(io);
227 * break;
228 * }
229 * }
230 *
231 * int main(int argc, char **argv)
232 * {
233 * M_event_t *el;
234 * M_io_t *io_source = NULL;
235 * M_io_error_t ioerr;
236 *
237 * dns = M_dns_create();
238 *
239 * // Setup our listening server which will listen for source connections.
240 * ioerr = M_io_net_server_create(&io_source, 8998, NULL, M_IO_NET_ANY);
241 * if (ioerr != M_IO_ERROR_SUCCESS) {
242 * M_printf("Could not start server: %s\n", M_io_error_string(ioerr));
243 * return 0;
244 * }
245 *
246 * el = M_event_create(M_EVENT_FLAG_NONE);
247 *
248 * M_event_add(el, io_source, source_listen_cb, NULL);
249 * M_event_loop(el, M_TIMEOUT_INF);
250 *
251 * M_event_destroy(el);
252 * M_dns_destroy(dns);
253 * return 0;
254 * }
255 * \endcode
256 *
257 * ## Echo Server (accepting proxy protocol)
258 *
259 * This is a basic echo server where any data received is echoed back
260 * out. The server only accepts connections that use proxy protocol.
261 *
262 * \code{.c}
263 * #include <mstdlib/mstdlib.h>
264 * #include <mstdlib/mstdlib_io.h>
265 *
266 * // Echo server states.
267 * typedef enum {
268 * STATE_CHECK = 1,
269 * STATE_ECHO,
270 * STATE_EXIT
271 * } states_t;
272 *
273 * typedef struct {
274 * M_buf_t *write_buf;
275 * M_parser_t *read_parser;
276 * M_io_t *io;
277 * M_event_t *el;
278 * M_state_machine_t *sm;
279 * } ldata_t;
280 *
281 * static void do_trace(void *cb_arg, M_io_trace_type_t type, M_event_type_t event_type, const unsigned char *data, size_t data_len)
282 * {
283 * char *out;
284 *
285 * switch (type) {
286 * case M_IO_TRACE_TYPE_READ:
287 * M_printf("READ:\n");
288 * break;
289 * case M_IO_TRACE_TYPE_WRITE:
290 * M_printf("WRITE:\n");
291 * break;
292 * default:
293 * return;
294 * }
295 * out = M_str_hexdump(M_STR_HEXDUMP_HEADER, 0, "\t", data, data_len);
296 * M_printf("%s\n", out);
297 * M_free(out);
298 * }
299 *
300 * static M_state_machine_status_t state_check(void *data, M_uint64 *next)
301 * {
302 * ldata_t *ldata = data;
303 *
304 * (void)next;
305 *
306 * // Check for new line which indicates full message to echo.
307 * M_parser_mark(ldata->read_parser);
308 * if (M_parser_len(ldata->read_parser) == 0 || M_parser_consume_until(ldata->read_parser, (const unsigned char *)"\n", 1, M_TRUE) == 0) {
309 * M_parser_mark_rewind(ldata->read_parser);
310 * return M_STATE_MACHINE_STATUS_WAIT;
311 * }
312 *
313 * return M_STATE_MACHINE_STATUS_NEXT;
314 * }
315 *
316 * static M_state_machine_status_t state_echo(void *data, M_uint64 *next)
317 * {
318 * ldata_t *ldata = data;
319 * char *out;
320 *
321 * // Echo the data.
322 * out = M_parser_read_strdup_mark(ldata->read_parser);
323 * M_buf_add_str(ldata->write_buf, out);
324 * M_io_write_from_buf(ldata->io, ldata->write_buf);
325 *
326 * // Check for exit command.
327 * if (!M_str_eq(out, "EXIT\r\n") && !M_str_eq(out, "EXIT\n"))
328 * *next = STATE_CHECK;
329 *
330 * M_free(out);
331 * return M_STATE_MACHINE_STATUS_NEXT;
332 * }
333 *
334 * static M_state_machine_status_t state_exit(void *data, M_uint64 *next)
335 * {
336 * ldata_t *ldata = data;
337 * (void)next;
338 * // Exit the server.
339 * M_event_done_with_disconnect(ldata->el, 0, 1000);
340 * return M_STATE_MACHINE_STATUS_NEXT;
341 * }
342 *
343 * static void connection_cb(M_event_t *el, M_event_type_t etype, M_io_t *io, void *thunk)
344 * {
345 * ldata_t *ldata = thunk;
346 * char error[256] = { 0 };
347 * M_bool clean = M_FALSE;
348 * M_state_machine_status_t status;
349 *
350 * switch (etype) {
351 * case M_EVENT_TYPE_CONNECTED:
352 * M_printf("CLIENT CONNECTED: %s%s%s:%d\n",
353 * M_io_net_get_type(io)==M_IO_NET_IPV6?"[":"",
354 * M_io_net_get_ipaddr(io),
355 * M_io_net_get_type(io)==M_IO_NET_IPV6?"]":"",
356 * M_io_net_get_port(io));
357 * M_printf("SERVER IP: %s%s%s\n",
358 * M_io_net_get_type(io)==M_IO_NET_IPV6?"[":"",
359 * M_io_net_get_server_ipaddr(io),
360 * M_io_net_get_type(io)==M_IO_NET_IPV6?"]":"");
361 * M_printf("PROXYED SOURCE: %s%s%s:%d\n",
362 * M_io_proxy_protocol_proxied_type(io)==M_IO_NET_IPV6?"[":"",
363 * M_io_proxy_protocol_source_ipaddr(io),
364 * M_io_proxy_protocol_proxied_type(io)==M_IO_NET_IPV6?"]":"",
365 * M_io_proxy_protocol_source_port(io));
366 * M_printf("PROXYED DEST: %s%s%s:%d\n",
367 * M_io_proxy_protocol_proxied_type(io)==M_IO_NET_IPV6?"[":"",
368 * M_io_proxy_protocol_dest_ipaddr(io),
369 * M_io_proxy_protocol_proxied_type(io)==M_IO_NET_IPV6?"]":"",
370 * M_io_proxy_protocol_dest_port(io));
371 * break;
372 * case M_EVENT_TYPE_READ:
373 * if (M_io_read_into_parser(io, ldata->read_parser) == M_IO_ERROR_SUCCESS) {
374 * status = M_state_machine_run(ldata->sm, ldata);
375 * if (status != M_STATE_MACHINE_STATUS_WAIT) {
376 * M_io_disconnect(io);
377 * }
378 * }
379 * break;
380 * case M_EVENT_TYPE_WRITE:
381 * if (M_buf_len(ldata->write_buf) > 0) {
382 * M_io_write_from_buf(io, ldata->write_buf);
383 * }
384 * break;
385 * case M_EVENT_TYPE_DISCONNECTED:
386 * case M_EVENT_TYPE_ACCEPT:
387 * case M_EVENT_TYPE_ERROR:
388 * case M_EVENT_TYPE_OTHER:
389 * if (etype == M_EVENT_TYPE_DISCONNECTED) {
390 * clean = M_TRUE;
391 * } else {
392 * M_io_get_error_string(io, error, sizeof(error));
393 * }
394 * M_printf("CLIENT %s: %s%s%s:%d (%s%s%s)\n",
395 * etype == M_EVENT_TYPE_DISCONNECTED ? "DISCONNECTED" : "ABORT",
396 * M_io_net_get_type(io)==M_IO_NET_IPV6?"[":"",
397 * M_io_net_get_ipaddr(io),
398 * M_io_net_get_type(io)==M_IO_NET_IPV6?"]":"",
399 * M_io_net_get_port(io),
400 * clean?"clean":"unclean", clean?"":" - ", clean?"":error);
401 *
402 * M_io_destroy(io);
403 * M_state_machine_destroy(ldata->sm);
404 * M_buf_cancel(ldata->write_buf);
405 * M_parser_destroy(ldata->read_parser);
406 * M_free(ldata);
407 * break;
408 * }
409 * }
410 *
411 * static void listen_cb(M_event_t *el, M_event_type_t etype, M_io_t *io, void *thunk)
412 * {
413 * M_io_t *io_out = NULL;
414 * ldata_t *ldata;
415 * M_io_error_t ioerr;
416 * char error[256] = { 0 };
417 *
418 * (void)thunk;
419 *
420 * switch (etype) {
421 * case M_EVENT_TYPE_ACCEPT:
422 * ioerr = M_io_accept(&io_out, io);
423 * if (ioerr == M_IO_ERROR_WOULDBLOCK) {
424 * return;
425 * } else if (ioerr != M_IO_ERROR_SUCCESS || io_out == NULL) {
426 * M_io_get_error_string(io, error, sizeof(error));
427 * M_printf("ACCEPT FAILURE: %s\n", error);
428 * M_io_destroy(io_out);
429 * break;
430 * }
431 *
432 * // If tracing, adding before the proxy protocol will output the proxy
433 * // protocol in the trace data. Putting after will not show the proxy
434 * // protocol data as it would have been eaten by the proxy protocol
435 * // layer, prior to being sent to the trace layer.
436 * //M_io_add_trace(io_out, NULL, do_trace, NULL, NULL, NULL);
437 *
438 * ldata = M_malloc_zero(sizeof(*ldata));
439 * ldata->el = el;
440 * ldata->write_buf = M_buf_create();
441 * ldata->read_parser = M_parser_create(M_PARSER_FLAG_NONE);
442 * ldata->io = io_out;
443 * ldata->sm = M_state_machine_create(0, NULL, M_STATE_MACHINE_NONE);
444 * M_state_machine_insert_state(ldata->sm, STATE_CHECK, 0, NULL, state_check, NULL, NULL);
445 * M_state_machine_insert_state(ldata->sm, STATE_ECHO, 0, NULL, state_echo, NULL, NULL);
446 * M_state_machine_insert_state(ldata->sm, STATE_EXIT, 0, NULL, state_exit, NULL, NULL);
447 *
448 * M_event_add(el, io_out, connection_cb, ldata);
449 * break;
450 * case M_EVENT_TYPE_CONNECTED:
451 * case M_EVENT_TYPE_READ:
452 * case M_EVENT_TYPE_WRITE:
453 * break;
454 * case M_EVENT_TYPE_DISCONNECTED:
455 * case M_EVENT_TYPE_ERROR:
456 * case M_EVENT_TYPE_OTHER:
457 * M_io_destroy(io);
458 * break;
459 * }
460 * }
461 *
462 * int main(int argc, char **argv)
463 * {
464 * M_event_t *el;
465 * M_io_t *io = NULL;
466 * M_io_error_t ioerr;
467 *
468 * ioerr = M_io_net_server_create(&io, 8999, NULL, M_IO_NET_ANY);
469 * if (ioerr != M_IO_ERROR_SUCCESS) {
470 * M_printf("Could not start server: %s\n", M_io_error_string(ioerr));
471 * return 0;
472 * }
473 *
474 * ioerr = M_io_proxy_protocol_inbound_add(io_out, NULL, M_IO_PROXY_PROTOCOL_FLAG_NONE);
475 * if (ioerr != M_IO_ERROR_SUCCESS) {
476 * M_printf("Could not add proxy protocol layer: %s\n", M_io_error_string(ioerr));
477 * M_io_destroy(io);
478 * return 0;
479 * }
480 *
481 * el = M_event_create(M_EVENT_FLAG_NONE);
482 *
483 * M_event_add(el, io, listen_cb, NULL);
484 * M_event_loop(el, M_TIMEOUT_INF);
485 *
486 * M_event_destroy(el);
487 * return 0;
488 * }
489 * \endcode
490 *
491 * ## Using Proxy Server and Echo Server Examples
492 *
493 * 1. Compile the proxy server
494 * 2. Compile the echo server
495 * 3. Start proxy server
496 * 4. Start echo server
497 * 5. Use something like telnet to connect to the proxy server
498 * 6. You should see:
499 * - Proxy server shows connection from telnet
500 * - Proxy server shows it connected to echo server
501 * - Echo server shows a connection from proxy server
502 * - Echo server shows proxied information for the _first_ (in cases where the chain
503 * has been expanded to include multiple) proxy server(s) and the telnet client.
504 *
505 * @{
506 */
507
508
509/*! Flags controlling behavior. */
510typedef enum {
511 M_IO_PROXY_PROTOCOL_FLAG_NONE = 0, /*!< Default operation. Support both V1 and V2 in inbound configuration.
512 Send V2 in client configuration. */
513 M_IO_PROXY_PROTOCOL_FLAG_V1 = 1 << 0, /*!< Only allow V1 connections for inbound configuration. Receiving V2
514 is an error condition. Send V1 format for outbound connections.
515 Specifying with V2 flag negates this flag operation. */
516 M_IO_PROXY_PROTOCOL_FLAG_V2 = 1 << 1 /*!< Only allow V2 connections for inbound configuration. Receiving V1
517 is an error condition. Send V2 format for outbound connections.
518 Specifying with V1 flag negates this flag operation. */
520
521
522/*! Add an inbound handler for proxy protocol connections.
523 *
524 * The system will look for the PROXY protocol data upon connect.
525 * If Proxy protocol data is not present this is considered an error
526 * condition per the proxy protocol spec. An error event will be
527 * generated instead of a connect event in this situation.
528 *
529 * This should be added to an `io` object created by `M_io_accept`
530 * during a server `M_EVENT_TYPE_ACCEPT` event. It should not be
531 * added to the server `io` object created by `M_io_net_server_create`.
532 *
533 * The proxy protocol data will be parsed and accessible
534 * though the relevant helper functions.
535 *
536 * \param[in] io io object.
537 * \param[out] layer_id Layer id this is added at.
538 * \param[in] flags M_io_proxy_protocol_flags_t flags.
539 *
540 * \return Result.
541 */
542M_API M_io_error_t M_io_proxy_protocol_inbound_add(M_io_t *io, size_t *layer_id, M_uint32 flags);
543
544
545/*! Add an outbound handler for proxy protocol connections.
546 *
547 * Information about the proxyed endpoints (source and destination) need to
548 * be set before the connect event. If endpoints are not set the connection
549 * is assumed to be local where any data is being sent by the proxy itself
550 * and not being relayed on behalf of another client.
551 *
552 * \param[in] io io object.
553 * \param[out] layer_id Layer id this is added at.
554 * \param[in] flags M_io_proxy_protocol_flags_t flags.
555 *
556 * \return Result.
557 *
558 * \see M_io_proxy_protocol_set_source_endpoints
559 */
560M_API M_io_error_t M_io_proxy_protocol_outbound_add(M_io_t *io, size_t *layer_id, M_uint32 flags);
561
562
563/*! Whether data is being is being relayed via a proxy.
564 *
565 * A connection is relayed when the data is being sent on behalf of another
566 * system (proxied). When it is not relayed it is a local connection that has
567 * been established by the proxy for the proxy's own communication with the system.
568 * Typically, this is used for health checking.
569 *
570 * return M_TRUE if relayed. Otherwise, M_FALSE.
571 */
573
574
575/*! Source IP address.
576 *
577 * IP address of the client that connected to the proxy.
578 *
579 * \param[in] io io object.
580 *
581 * \return IP address as string.
582 */
584
585
586/*! Destination IP address.
587 *
588 * IP address of the proxy server that is relaying the client's (source) data.
589 *
590 * \param[in] io io object.
591 *
592 * \return IP address as string.
593 */
595
596
597/*! Source port.
598 *
599 * Ephemeral port the client is connecting out on.
600 *
601 * \param[in] io io object.
602 *
603 * \return Port
604 */
606
607
608/*! Destination port.
609 *
610 * Destination port the client is connecting to.
611 *
612 * \param[in] io io object.
613 *
614 * \return Port
615 */
617
618
619/*! Connection type that was used between source and destination.
620 *
621 * \param[in] io io object.
622 *
623 * \return Type
624 */
626
627
628/*! Get the IP address of the client falling back to the network connection.
629 *
630 * When using proxy protocol this should be used instead of `M_io_net_get_ipaddr`
631 * in most instances. This can be used even when proxy protocol is not in use.
632 * This is especially useful when using an internal IP based blacklist for denying
633 * connections to a client as part of an intrusion prevention system (IPS).
634 *
635 * This function is the equivalent of checking `M_io_proxy_protocol_relayed`
636 * and then calling either `M_io_proxy_protocol_source_ipaddr` or `M_io_net_get_ipaddr`
637 * based on whether the connection is relayed.
638 *
639 * This is a conscience especially for instances where proxy protocol could be used.
640 * For example, a configuration option or when some but not all connections will
641 * use the protocol. This function allows for use in both scenerios and will always
642 * return the correct IP address for the client, whether proxied for not.
643 *
644 * param[in] io io object.
645 *
646 * \return String
647 */
649
650
651/*! Set connect timeout.
652 *
653 * This is the timeout to wait for a connection to receive
654 * all proxy protocol data. This timeout applies after the net
655 * connect timeout.
656 *
657 * Proxy protocol is designed for all data to fit within a
658 * single TCP frame. Meaning, the data should not buffer between
659 * multiple events. As such the default timeout is 500 ms. This
660 * function can be used to increase that timeout for obscenely slow
661 * connections.
662 *
663 * Connect timeout applies to both inbound and outbound (receiving
664 * and writing), the proxy data.
665 *
666 * param[in] io io object.
667 * param[in] timeout_ms Timeout in milliseconds.
668 *
669 * \return M_TRUE when proxy protocol in use. Otherwise, M_FALSE.
670 */
671M_API M_bool M_io_proxy_protocol_set_connect_timeout_ms(M_io_t *io, M_uint64 timeout_ms);
672
673
674/*! Source and destination information that will be sent on connect.
675 *
676 * Only applies to outbound connections.
677 *
678 * The source and destination IP address must be the same address family (IPv4/IPv6).
679 * If IP addresses are `NULL` the connection is assumed to be local (not proxied data).
680 *
681 * This can be called multiple times setting or clearing proxy client information. However,
682 * the information is only sent on connect. Multiple inbound connections cannot be multiplexed
683 * on the same outbound connection. If changing endpoint information the outbound connection
684 * needs to disconnect first.
685 *
686 * This should be called using an inbound network connection to determine the connection information.
687 *
688 * \code{.c}
689 * M_io_proxy_protocol_set_source_endpoints(io_out,
690 * M_io_net_get_ipaddr(io_in),
691 * M_io_net_get_server_ipaddr(io_in),
692 * M_io_net_get_ephemeral_port(io_in),
693 * M_io_net_get_port(io_in));
694 * \endcode
695 *
696 * \param[in] io io object.
697 * \param[in] source_ipaddr Source ipaddress
698 * \param[in] dest_ipaddr Destination ipaddress
699 * \param[in] source_port Source port
700 * \param[in] dest_port Destination port
701 *
702 */
703M_API M_bool M_io_proxy_protocol_set_source_endpoints(M_io_t *io, const char *source_ipaddr, const char *dest_ipaddr, M_uint16 source_port, M_uint16 dest_port);
704
705/*! @} */
706
707__END_DECLS
708
709#endif
enum M_io_net_type M_io_net_type_t
Definition: m_io_net.h:340
M_io_proxy_protocol_flags_t
Definition: m_io_proxy_protocol.h:510
M_bool M_io_proxy_protocol_set_source_endpoints(M_io_t *io, const char *source_ipaddr, const char *dest_ipaddr, M_uint16 source_port, M_uint16 dest_port)
M_io_net_type_t M_io_proxy_protocol_proxied_type(M_io_t *io)
M_bool M_io_proxy_protocol_set_connect_timeout_ms(M_io_t *io, M_uint64 timeout_ms)
const char * M_io_proxy_protocol_source_ipaddr(M_io_t *io)
const char * M_io_proxy_protocol_get_ipaddr(M_io_t *io)
M_bool M_io_proxy_protocol_relayed(M_io_t *io)
M_uint16 M_io_proxy_protocol_dest_port(M_io_t *io)
M_io_error_t M_io_proxy_protocol_outbound_add(M_io_t *io, size_t *layer_id, M_uint32 flags)
const char * M_io_proxy_protocol_dest_ipaddr(M_io_t *io)
M_io_error_t M_io_proxy_protocol_inbound_add(M_io_t *io, size_t *layer_id, M_uint32 flags)
M_uint16 M_io_proxy_protocol_source_port(M_io_t *io)
@ M_IO_PROXY_PROTOCOL_FLAG_NONE
Definition: m_io_proxy_protocol.h:511
@ M_IO_PROXY_PROTOCOL_FLAG_V1
Definition: m_io_proxy_protocol.h:513
@ M_IO_PROXY_PROTOCOL_FLAG_V2
Definition: m_io_proxy_protocol.h:516
enum M_io_error M_io_error_t
Definition: m_io.h:93
struct M_io M_io_t
Definition: m_io.h:59