blob: 957deb4d91bc2627fc77dfaddc3d88fa5f1d9054 [file] [log] [blame]
Emeric Brun3835c0d2020-07-07 09:46:09 +02001/*
2 * AF_CUST_UDP/AF_CUST_UDP6 UDP protocol layer
3 *
4 * Copyright 2019 HAProxy Technologies, Frédéric Lécaille <flecaille@haproxy.com>
5 *
6 * Partial merge by Emeric Brun <ebrun@haproxy.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 */
14
15#include <ctype.h>
16#include <errno.h>
17#include <fcntl.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <time.h>
22
23#include <sys/param.h>
24#include <sys/socket.h>
25#include <sys/types.h>
26
27#include <netinet/udp.h>
28#include <netinet/in.h>
29
30#include <haproxy/fd.h>
31#include <haproxy/listener.h>
32#include <haproxy/log.h>
33#include <haproxy/namespace.h>
34#include <haproxy/port_range.h>
35#include <haproxy/protocol.h>
36#include <haproxy/proto_udp.h>
37#include <haproxy/proxy.h>
38#include <haproxy/server.h>
Willy Tarreau18b7df72020-08-28 12:07:22 +020039#include <haproxy/sock.h>
Willy Tarreauf1725582020-08-28 15:30:11 +020040#include <haproxy/sock_inet.h>
Emeric Brun3835c0d2020-07-07 09:46:09 +020041#include <haproxy/task.h>
42
Emeric Brun3835c0d2020-07-07 09:46:09 +020043static int udp_bind_listener(struct listener *listener, char *errmsg, int errlen);
44static void udp4_add_listener(struct listener *listener, int port);
45static void udp6_add_listener(struct listener *listener, int port);
46
47/* Note: must not be declared <const> as its list will be overwritten */
48static struct protocol proto_udp4 = {
49 .name = "udp4",
50 .sock_domain = AF_CUST_UDP4,
51 .sock_type = SOCK_DGRAM,
52 .sock_prot = IPPROTO_UDP,
53 .sock_family = AF_INET,
54 .sock_addrlen = sizeof(struct sockaddr_in),
55 .l3_addrlen = 32/8,
56 .accept = NULL,
57 .connect = NULL,
Willy Tarreaud69ce1f2020-09-01 14:18:04 +020058 .bind = sock_inet_bind_receiver,
Willy Tarreaub3580b12020-09-01 10:26:22 +020059 .listen = udp_bind_listener,
Emeric Brun3835c0d2020-07-07 09:46:09 +020060 .enable_all = enable_all_listeners,
61 .get_src = udp_get_src,
62 .get_dst = udp_get_dst,
63 .pause = udp_pause_listener,
64 .add = udp4_add_listener,
Willy Tarreauf1725582020-08-28 15:30:11 +020065 .addrcmp = sock_inet4_addrcmp,
Emeric Brun3835c0d2020-07-07 09:46:09 +020066 .listeners = LIST_HEAD_INIT(proto_udp4.listeners),
67 .nb_listeners = 0,
68};
69
70INITCALL1(STG_REGISTER, protocol_register, &proto_udp4);
71
72/* Note: must not be declared <const> as its list will be overwritten */
73static struct protocol proto_udp6 = {
74 .name = "udp6",
75 .sock_domain = AF_CUST_UDP6,
76 .sock_type = SOCK_DGRAM,
77 .sock_prot = IPPROTO_UDP,
78 .sock_family = AF_INET6,
79 .sock_addrlen = sizeof(struct sockaddr_in6),
80 .l3_addrlen = 128/8,
81 .accept = NULL,
82 .connect = NULL,
Willy Tarreaud69ce1f2020-09-01 14:18:04 +020083 .bind = sock_inet_bind_receiver,
Willy Tarreaub3580b12020-09-01 10:26:22 +020084 .listen = udp_bind_listener,
Emeric Brun3835c0d2020-07-07 09:46:09 +020085 .enable_all = enable_all_listeners,
Willy Tarreau18b7df72020-08-28 12:07:22 +020086 .get_src = udp6_get_src,
Willy Tarreauc5a94c92020-08-28 15:19:45 +020087 .get_dst = udp6_get_dst,
Emeric Brun3835c0d2020-07-07 09:46:09 +020088 .pause = udp_pause_listener,
89 .add = udp6_add_listener,
Willy Tarreauf1725582020-08-28 15:30:11 +020090 .addrcmp = sock_inet6_addrcmp,
Emeric Brun3835c0d2020-07-07 09:46:09 +020091 .listeners = LIST_HEAD_INIT(proto_udp6.listeners),
92 .nb_listeners = 0,
93};
94
95INITCALL1(STG_REGISTER, protocol_register, &proto_udp6);
96
97/*
98 * Retrieves the source address for the socket <fd>, with <dir> indicating
99 * if we're a listener (=0) or an initiator (!=0). It returns 0 in case of
100 * success, -1 in case of error. The socket's source address is stored in
101 * <sa> for <salen> bytes.
102 */
103int udp_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir)
104{
105 int ret;
106
Willy Tarreau18b7df72020-08-28 12:07:22 +0200107 ret = sock_get_src(fd, sa, salen, dir);
108 if (!ret)
109 sa->sa_family = AF_CUST_UDP4;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200110
111 return ret;
112}
113
Willy Tarreau18b7df72020-08-28 12:07:22 +0200114/*
115 * Retrieves the source address for the socket <fd>, with <dir> indicating
116 * if we're a listener (=0) or an initiator (!=0). It returns 0 in case of
117 * success, -1 in case of error. The socket's source address is stored in
118 * <sa> for <salen> bytes.
119 */
120int udp6_get_src(int fd, struct sockaddr *sa, socklen_t salen, int dir)
121{
122 int ret;
123
124 ret = sock_get_src(fd, sa, salen, dir);
125 if (!ret)
126 sa->sa_family = AF_CUST_UDP6;
127
128 return ret;
129}
Emeric Brun3835c0d2020-07-07 09:46:09 +0200130
131/*
132 * Retrieves the original destination address for the socket <fd>, with <dir>
133 * indicating if we're a listener (=0) or an initiator (!=0). In the case of a
134 * listener, if the original destination address was translated, the original
135 * address is retrieved. It returns 0 in case of success, -1 in case of error.
136 * The socket's source address is stored in <sa> for <salen> bytes.
137 */
138int udp_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir)
139{
140 int ret;
141
Willy Tarreauc5a94c92020-08-28 15:19:45 +0200142 ret = sock_inet_get_dst(fd, sa, salen, dir);
143 if (!ret)
144 sa->sa_family = AF_CUST_UDP4;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200145
Willy Tarreauc5a94c92020-08-28 15:19:45 +0200146 return ret;
147}
Emeric Brun3835c0d2020-07-07 09:46:09 +0200148
Willy Tarreauc5a94c92020-08-28 15:19:45 +0200149/*
150 * Retrieves the original destination address for the socket <fd>, with <dir>
151 * indicating if we're a listener (=0) or an initiator (!=0). In the case of a
152 * listener, if the original destination address was translated, the original
153 * address is retrieved. It returns 0 in case of success, -1 in case of error.
154 * The socket's source address is stored in <sa> for <salen> bytes.
155 */
156int udp6_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir)
157{
158 int ret;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200159
Willy Tarreauc5a94c92020-08-28 15:19:45 +0200160 ret = sock_get_dst(fd, sa, salen, dir);
161 if (!ret)
162 sa->sa_family = AF_CUST_UDP6;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200163
164 return ret;
165}
166
167/* This function tries to bind a UDPv4/v6 listener. It may return a warning or
168 * an error message in <errmsg> if the message is at most <errlen> bytes long
169 * (including '\0'). Note that <errmsg> may be NULL if <errlen> is also zero.
170 * The return value is composed from ERR_ABORT, ERR_WARN,
171 * ERR_ALERT, ERR_RETRYABLE and ERR_FATAL. ERR_NONE indicates that everything
172 * was alright and that no message was returned. ERR_RETRYABLE means that an
173 * error occurred but that it may vanish after a retry (eg: port in use), and
174 * ERR_FATAL indicates a non-fixable error. ERR_WARN and ERR_ALERT do not alter
175 * the meaning of the error, but just indicate that a message is present which
176 * should be displayed with the respective level. Last, ERR_ABORT indicates
177 * that it's pointless to try to start other listeners. No error message is
178 * returned if errlen is NULL.
179 */
180int udp_bind_listener(struct listener *listener, char *errmsg, int errlen)
181{
Willy Tarreau2f7687d2020-09-01 16:23:29 +0200182 int err = ERR_NONE;
183 void *handler = NULL;
184 char *msg = NULL;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200185
186 /* ensure we never return garbage */
187 if (errlen)
188 *errmsg = 0;
189
190 if (listener->state != LI_ASSIGNED)
191 return ERR_NONE; /* already bound */
192
Willy Tarreau2f7687d2020-09-01 16:23:29 +0200193 switch (listener->bind_conf->frontend->mode) {
194 case PR_MODE_SYSLOG:
195 handler = syslog_fd_handler;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200196 break;
Willy Tarreau2f7687d2020-09-01 16:23:29 +0200197 default:
198 err |= ERR_FATAL | ERR_ALERT;
199 msg = "UDP is not yet supported on this proxy mode";
200 goto udp_return;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200201 }
202
Willy Tarreau2f7687d2020-09-01 16:23:29 +0200203 err = sock_inet_bind_receiver(&listener->rx, handler, &msg);
Emeric Brun3835c0d2020-07-07 09:46:09 +0200204
Willy Tarreau2f7687d2020-09-01 16:23:29 +0200205 if (err != ERR_NONE) {
206 snprintf(errmsg, errlen, "%s", msg);
207 free(msg); msg = NULL;
208 return err;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200209 }
Emeric Brun3835c0d2020-07-07 09:46:09 +0200210 listener->state = LI_LISTEN;
211
Emeric Brun3835c0d2020-07-07 09:46:09 +0200212 udp_return:
213 if (msg && errlen) {
214 char pn[INET6_ADDRSTRLEN];
215
Willy Tarreau2f7687d2020-09-01 16:23:29 +0200216 addr_to_str(&listener->rx.addr, pn, sizeof(pn));
217 snprintf(errmsg, errlen, "%s [%s:%d]", msg, pn, get_host_port(&listener->rx.addr));
Emeric Brun3835c0d2020-07-07 09:46:09 +0200218 }
219 return err;
Emeric Brun3835c0d2020-07-07 09:46:09 +0200220}
221
Emeric Brun3835c0d2020-07-07 09:46:09 +0200222/* Add <listener> to the list of udp4 listeners, on port <port>. The
223 * listener's state is automatically updated from LI_INIT to LI_ASSIGNED.
224 * The number of listeners for the protocol is updated.
225 */
226static void udp4_add_listener(struct listener *listener, int port)
227{
228 if (listener->state != LI_INIT)
229 return;
230 listener->state = LI_ASSIGNED;
Willy Tarreaub7436612020-08-28 19:51:44 +0200231 listener->rx.proto = &proto_udp4;
Willy Tarreau37159062020-08-27 07:48:42 +0200232 ((struct sockaddr_in *)(&listener->rx.addr))->sin_port = htons(port);
Willy Tarreaub7436612020-08-28 19:51:44 +0200233 LIST_ADDQ(&proto_udp4.listeners, &listener->rx.proto_list);
Emeric Brun3835c0d2020-07-07 09:46:09 +0200234 proto_udp4.nb_listeners++;
235}
236
237/* Add <listener> to the list of udp6 listeners, on port <port>. The
238 * listener's state is automatically updated from LI_INIT to LI_ASSIGNED.
239 * The number of listeners for the protocol is updated.
240 */
241static void udp6_add_listener(struct listener *listener, int port)
242{
243 if (listener->state != LI_INIT)
244 return;
245 listener->state = LI_ASSIGNED;
Willy Tarreaub7436612020-08-28 19:51:44 +0200246 listener->rx.proto = &proto_udp6;
Willy Tarreau37159062020-08-27 07:48:42 +0200247 ((struct sockaddr_in *)(&listener->rx.addr))->sin_port = htons(port);
Willy Tarreaub7436612020-08-28 19:51:44 +0200248 LIST_ADDQ(&proto_udp6.listeners, &listener->rx.proto_list);
Emeric Brun3835c0d2020-07-07 09:46:09 +0200249 proto_udp6.nb_listeners++;
250}
251
252/* Pause a listener. Returns < 0 in case of failure, 0 if the listener
253 * was totally stopped, or > 0 if correctly paused.
254 */
255int udp_pause_listener(struct listener *l)
256{
257 /* we don't support pausing on UDP */
258 return -1;
259}
260
261/*
262 * Local variables:
263 * c-indent-level: 8
264 * c-basic-offset: 8
265 * End:
266 */