blob: d753e64e5a387ca57ba0541fde024faa4dddc8fa [file] [log] [blame]
Willy Tarreaude70ca52020-08-28 11:49:31 +02001/*
2 * Configuration parsing for TCP (bind and server keywords)
3 *
4 * Copyright 2000-2020 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
Willy Tarreaude70ca52020-08-28 11:49:31 +020015#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <time.h>
19
20#include <sys/param.h>
21#include <sys/socket.h>
22#include <sys/types.h>
23
24#include <netinet/tcp.h>
25#include <netinet/in.h>
26
27#include <haproxy/api.h>
28#include <haproxy/arg.h>
29#include <haproxy/errors.h>
30#include <haproxy/list.h>
31#include <haproxy/listener.h>
32#include <haproxy/namespace.h>
33#include <haproxy/proxy-t.h>
34#include <haproxy/server.h>
35#include <haproxy/tools.h>
36
37
38#ifdef IPV6_V6ONLY
39/* parse the "v4v6" bind keyword */
40static int bind_parse_v4v6(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
41{
Willy Tarreau3fd3bdc2020-09-01 15:12:08 +020042 conf->settings.options |= RX_O_V4V6;
Willy Tarreaude70ca52020-08-28 11:49:31 +020043 return 0;
44}
45
46/* parse the "v6only" bind keyword */
47static int bind_parse_v6only(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
48{
Willy Tarreau3fd3bdc2020-09-01 15:12:08 +020049 conf->settings.options |= RX_O_V6ONLY;
Willy Tarreaude70ca52020-08-28 11:49:31 +020050 return 0;
51}
52#endif
53
54#ifdef CONFIG_HAP_TRANSPARENT
55/* parse the "transparent" bind keyword */
56static int bind_parse_transparent(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
57{
Willy Tarreau3fd3bdc2020-09-01 15:12:08 +020058 conf->settings.options |= RX_O_FOREIGN;
Willy Tarreaude70ca52020-08-28 11:49:31 +020059 return 0;
60}
61#endif
62
David Carlier1eb595b2021-02-06 12:11:11 +000063#if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER)
Willy Tarreaude70ca52020-08-28 11:49:31 +020064/* parse the "defer-accept" bind keyword */
65static int bind_parse_defer_accept(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
66{
Willy Tarreaud9b4d212023-01-12 19:42:48 +010067 conf->options |= BC_O_DEF_ACCEPT;
Willy Tarreaude70ca52020-08-28 11:49:31 +020068 return 0;
69}
70#endif
71
72#ifdef TCP_FASTOPEN
73/* parse the "tfo" bind keyword */
74static int bind_parse_tfo(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
75{
Willy Tarreauc492f1b2023-01-12 19:45:58 +010076 conf->options |= BC_O_TCP_FO;
Willy Tarreaude70ca52020-08-28 11:49:31 +020077 return 0;
78}
79#endif
80
81#ifdef TCP_MAXSEG
82/* parse the "mss" bind keyword */
83static int bind_parse_mss(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
84{
Willy Tarreaude70ca52020-08-28 11:49:31 +020085 int mss;
86
87 if (!*args[cur_arg + 1]) {
88 memprintf(err, "'%s' : missing MSS value", args[cur_arg]);
89 return ERR_ALERT | ERR_FATAL;
90 }
91
92 mss = atoi(args[cur_arg + 1]);
93 if (!mss || abs(mss) > 65535) {
94 memprintf(err, "'%s' : expects an MSS with and absolute value between 1 and 65535", args[cur_arg]);
95 return ERR_ALERT | ERR_FATAL;
96 }
97
Willy Tarreauee378162023-01-12 18:42:49 +010098 conf->maxseg = mss;
Willy Tarreaude70ca52020-08-28 11:49:31 +020099 return 0;
100}
101#endif
102
103#ifdef TCP_USER_TIMEOUT
104/* parse the "tcp-ut" bind keyword */
105static int bind_parse_tcp_ut(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
106{
107 const char *ptr = NULL;
Willy Tarreaude70ca52020-08-28 11:49:31 +0200108 unsigned int timeout;
109
110 if (!*args[cur_arg + 1]) {
111 memprintf(err, "'%s' : missing TCP User Timeout value", args[cur_arg]);
112 return ERR_ALERT | ERR_FATAL;
113 }
114
115 ptr = parse_time_err(args[cur_arg + 1], &timeout, TIME_UNIT_MS);
116 if (ptr == PARSE_TIME_OVER) {
117 memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
118 args[cur_arg+1], args[cur_arg]);
119 return ERR_ALERT | ERR_FATAL;
120 }
121 else if (ptr == PARSE_TIME_UNDER) {
122 memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
123 args[cur_arg+1], args[cur_arg]);
124 return ERR_ALERT | ERR_FATAL;
125 }
126 else if (ptr) {
127 memprintf(err, "'%s' : expects a positive delay in milliseconds", args[cur_arg]);
128 return ERR_ALERT | ERR_FATAL;
129 }
130
Willy Tarreauee378162023-01-12 18:42:49 +0100131 conf->tcp_ut = timeout;
Willy Tarreaude70ca52020-08-28 11:49:31 +0200132 return 0;
133}
134#endif
135
136#ifdef SO_BINDTODEVICE
137/* parse the "interface" bind keyword */
138static int bind_parse_interface(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
139{
Willy Tarreaude70ca52020-08-28 11:49:31 +0200140 if (!*args[cur_arg + 1]) {
141 memprintf(err, "'%s' : missing interface name", args[cur_arg]);
142 return ERR_ALERT | ERR_FATAL;
143 }
144
Willy Tarreau7e307212020-09-03 07:23:34 +0200145 conf->settings.interface = strdup(args[cur_arg + 1]);
Willy Tarreaude70ca52020-08-28 11:49:31 +0200146 return 0;
147}
148#endif
149
150#ifdef USE_NS
151/* parse the "namespace" bind keyword */
152static int bind_parse_namespace(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
153{
Willy Tarreaude70ca52020-08-28 11:49:31 +0200154 char *namespace = NULL;
155
156 if (!*args[cur_arg + 1]) {
157 memprintf(err, "'%s' : missing namespace id", args[cur_arg]);
158 return ERR_ALERT | ERR_FATAL;
159 }
160 namespace = args[cur_arg + 1];
161
Willy Tarreaube56c102020-09-03 07:27:34 +0200162 conf->settings.netns = netns_store_lookup(namespace, strlen(namespace));
Willy Tarreaude70ca52020-08-28 11:49:31 +0200163
Willy Tarreaube56c102020-09-03 07:27:34 +0200164 if (conf->settings.netns == NULL)
165 conf->settings.netns = netns_store_insert(namespace);
Willy Tarreaude70ca52020-08-28 11:49:31 +0200166
Willy Tarreaube56c102020-09-03 07:27:34 +0200167 if (conf->settings.netns == NULL) {
168 ha_alert("Cannot open namespace '%s'.\n", args[cur_arg + 1]);
169 return ERR_ALERT | ERR_FATAL;
Willy Tarreaude70ca52020-08-28 11:49:31 +0200170 }
171 return 0;
172}
173#endif
174
175#ifdef TCP_USER_TIMEOUT
176/* parse the "tcp-ut" server keyword */
177static int srv_parse_tcp_ut(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
178{
179 const char *ptr = NULL;
180 unsigned int timeout;
181
182 if (!*args[*cur_arg + 1]) {
183 memprintf(err, "'%s' : missing TCP User Timeout value", args[*cur_arg]);
184 return ERR_ALERT | ERR_FATAL;
185 }
186
187 ptr = parse_time_err(args[*cur_arg + 1], &timeout, TIME_UNIT_MS);
188 if (ptr == PARSE_TIME_OVER) {
189 memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
190 args[*cur_arg+1], args[*cur_arg]);
191 return ERR_ALERT | ERR_FATAL;
192 }
193 else if (ptr == PARSE_TIME_UNDER) {
194 memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
195 args[*cur_arg+1], args[*cur_arg]);
196 return ERR_ALERT | ERR_FATAL;
197 }
198 else if (ptr) {
199 memprintf(err, "'%s' : expects a positive delay in milliseconds", args[*cur_arg]);
200 return ERR_ALERT | ERR_FATAL;
201 }
202
203 if (newsrv->addr.ss_family == AF_INET || newsrv->addr.ss_family == AF_INET6)
204 newsrv->tcp_ut = timeout;
205
206 return 0;
207}
208#endif
209
210
211/************************************************************************/
212/* All supported bind keywords must be declared here. */
213/************************************************************************/
214
215/* Note: must not be declared <const> as its list will be overwritten.
216 * Please take care of keeping this list alphabetically sorted, doing so helps
217 * all code contributors.
218 * Optional keywords are also declared with a NULL ->parse() function so that
219 * the config parser can report an appropriate error when a known keyword was
220 * not enabled.
221 */
222static struct bind_kw_list bind_kws = { "TCP", { }, {
David Carlier1eb595b2021-02-06 12:11:11 +0000223#if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER)
Willy Tarreaude70ca52020-08-28 11:49:31 +0200224 { "defer-accept", bind_parse_defer_accept, 0 }, /* wait for some data for 1 second max before doing accept */
225#endif
226#ifdef SO_BINDTODEVICE
227 { "interface", bind_parse_interface, 1 }, /* specifically bind to this interface */
228#endif
229#ifdef TCP_MAXSEG
230 { "mss", bind_parse_mss, 1 }, /* set MSS of listening socket */
231#endif
232#ifdef TCP_USER_TIMEOUT
233 { "tcp-ut", bind_parse_tcp_ut, 1 }, /* set User Timeout on listening socket */
234#endif
235#ifdef TCP_FASTOPEN
236 { "tfo", bind_parse_tfo, 0 }, /* enable TCP_FASTOPEN of listening socket */
237#endif
238#ifdef CONFIG_HAP_TRANSPARENT
239 { "transparent", bind_parse_transparent, 0 }, /* transparently bind to the specified addresses */
240#endif
241#ifdef IPV6_V6ONLY
242 { "v4v6", bind_parse_v4v6, 0 }, /* force socket to bind to IPv4+IPv6 */
243 { "v6only", bind_parse_v6only, 0 }, /* force socket to bind to IPv6 only */
244#endif
245#ifdef USE_NS
246 { "namespace", bind_parse_namespace, 1 },
247#endif
248 /* the versions with the NULL parse function*/
249 { "defer-accept", NULL, 0 },
250 { "interface", NULL, 1 },
251 { "mss", NULL, 1 },
252 { "transparent", NULL, 0 },
253 { "v4v6", NULL, 0 },
254 { "v6only", NULL, 0 },
255 { NULL, NULL, 0 },
256}};
257
258INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
259
260static struct srv_kw_list srv_kws = { "TCP", { }, {
261#ifdef TCP_USER_TIMEOUT
Amaury Denoyelle76e10e72021-03-08 17:08:01 +0100262 { "tcp-ut", srv_parse_tcp_ut, 1, 1, 0 }, /* set TCP user timeout on server */
Willy Tarreaude70ca52020-08-28 11:49:31 +0200263#endif
264 { NULL, NULL, 0 },
265}};
266
267INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
268
Willy Tarreaude70ca52020-08-28 11:49:31 +0200269/*
270 * Local variables:
271 * c-indent-level: 8
272 * c-basic-offset: 8
273 * End:
274 */