blob: 9483e8972fa1c13e3b7c196b1a7ee1465823f5f8 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Server management functions.
3 *
Willy Tarreau21faa912012-10-10 08:27:36 +02004 * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +01005 * Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
Willy Tarreaubaaee002006-06-26 02:48:02 +02006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
Willy Tarreau0a4b0ab2020-06-11 11:22:44 +020014#include <sys/types.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020015#include <netinet/tcp.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020016#include <ctype.h>
Baptiste Assmanne11cfcd2015-08-19 16:44:03 +020017#include <errno.h>
Willy Tarreau272adea2014-03-31 10:39:59 +020018
Willy Tarreau260f3242021-10-06 18:30:04 +020019#include <import/ebmbtree.h>
20
Willy Tarreaub2551052020-06-09 09:07:15 +020021#include <haproxy/api.h>
Willy Tarreau3f0f82e2020-06-04 19:42:41 +020022#include <haproxy/applet-t.h>
Willy Tarreau49801602020-06-04 22:50:02 +020023#include <haproxy/backend.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020024#include <haproxy/cfgparse.h>
Willy Tarreau4aa573d2020-06-04 18:21:56 +020025#include <haproxy/check.h>
Willy Tarreau83487a82020-06-04 20:19:54 +020026#include <haproxy/cli.h>
Willy Tarreau7ea393d2020-06-04 18:02:10 +020027#include <haproxy/connection.h>
Willy Tarreau3afc4c42020-06-03 18:23:19 +020028#include <haproxy/dict-t.h>
Willy Tarreau8d366972020-05-27 16:10:29 +020029#include <haproxy/errors.h>
Willy Tarreauf268ee82020-06-04 17:05:57 +020030#include <haproxy/global.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020031#include <haproxy/log.h>
Willy Tarreaucee013e2020-06-05 11:40:38 +020032#include <haproxy/mailers.h>
Willy Tarreau7a00efb2020-06-02 17:02:59 +020033#include <haproxy/namespace.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020034#include <haproxy/port_range.h>
35#include <haproxy/protocol.h>
Willy Tarreaub00a8e32021-05-08 20:18:59 +020036#include <haproxy/proxy.h>
Willy Tarreaua55c4542020-06-04 22:59:39 +020037#include <haproxy/queue.h>
Emeric Brunc9437992021-02-12 19:42:55 +010038#include <haproxy/resolvers.h>
Willy Tarreaue6ce10b2020-06-04 15:33:47 +020039#include <haproxy/sample.h>
Willy Tarreau5edca2f2022-05-27 09:25:10 +020040#include <haproxy/sc_strm.h>
Willy Tarreau1e56f922020-06-04 23:20:13 +020041#include <haproxy/server.h>
Amaury Denoyellef99f77a2021-03-08 17:13:32 +010042#include <haproxy/stats.h>
Willy Tarreaucb086c62022-05-27 09:47:12 +020043#include <haproxy/stconn.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020044#include <haproxy/stream.h>
Willy Tarreaucea0e1b2020-06-04 17:25:40 +020045#include <haproxy/task.h>
Willy Tarreau51cd5952020-06-05 12:25:38 +020046#include <haproxy/tcpcheck.h>
Willy Tarreau92b4f132020-06-01 11:05:15 +020047#include <haproxy/time.h>
Willy Tarreauba6300e2021-05-08 14:09:40 +020048#include <haproxy/tools.h>
Tim Duesterhusd5fc8fc2021-09-11 17:51:13 +020049#include <haproxy/xxhash.h>
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +010050#include <haproxy/event_hdl.h>
Krzysztof Oledzki85130942007-10-22 16:21:10 +020051
Baptiste Assmannda29fe22019-06-13 13:24:29 +020052
Willy Tarreau3ff577e2018-08-02 11:48:52 +020053static void srv_update_status(struct server *s);
Baptiste Assmann83cbaa52016-11-02 15:34:05 +010054static int srv_apply_lastaddr(struct server *srv, int *err_code);
William Dauchy6318d332020-05-02 21:52:36 +020055static void srv_cleanup_connections(struct server *srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +020056
Amaury Denoyelle587b71e2021-03-10 16:36:02 +010057/* extra keywords used as value for other arguments. They are used as
58 * suggestions for mistyped words.
Willy Tarreau49c2b452021-03-12 09:58:04 +010059 */
Amaury Denoyelle587b71e2021-03-10 16:36:02 +010060static const char *extra_kw_list[] = {
61 "ipv4", "ipv6", "legacy", "octet-count",
Amaury Denoyelle3b89c112021-03-12 16:04:00 +010062 "fail-check", "sudden-death", "mark-down",
Willy Tarreau49c2b452021-03-12 09:58:04 +010063 NULL /* must be last */
64};
65
Willy Tarreau21faa912012-10-10 08:27:36 +020066/* List head of all known server keywords */
Willy Tarreauca1acd62022-03-29 15:02:44 +020067struct srv_kw_list srv_keywords = {
Willy Tarreau21faa912012-10-10 08:27:36 +020068 .list = LIST_HEAD_INIT(srv_keywords.list)
69};
Krzysztof Oledzki85130942007-10-22 16:21:10 +020070
Willy Tarreauaf613e82020-06-05 08:40:51 +020071__decl_thread(HA_SPINLOCK_T idle_conn_srv_lock);
Olivier Houchard9ea5d362019-02-14 18:29:09 +010072struct eb_root idle_conn_srv = EB_ROOT;
Willy Tarreau14015b82021-04-10 17:33:15 +020073struct task *idle_conn_task __read_mostly = NULL;
Willy Tarreau198e92a2021-03-05 10:23:32 +010074struct list servers_list = LIST_HEAD_INIT(servers_list);
Olivier Houchard9ea5d362019-02-14 18:29:09 +010075
Aurelien DARRAGON61e38942022-11-17 16:10:35 +010076/* SERVER DELETE(n)->ADD global tracker:
77 * This is meant to provide srv->rid (revision id) value.
78 * Revision id allows to differentiate between a previously existing
79 * deleted server and a new server reusing deleted server name/id.
80 *
81 * start value is 0 (even value)
82 * LSB is used to specify that one or multiple srv delete in a row
83 * were performed.
84 * When adding a new server, increment by 1 if current
85 * value is odd (odd = LSB set),
86 * because adding a new server after one or
87 * multiple deletions means we could potentially be reusing old names:
88 * Increase the revision id to prevent mixups between old and new names.
89 *
90 * srv->rid is calculated from cnt even values only.
91 * sizeof(srv_id_reuse_cnt) must be twice sizeof(srv->rid)
92 *
93 * Wraparound is expected and should not cause issues
94 * (with current design we allow up to 4 billion unique revisions)
95 *
96 * Counter is only used under thread_isolate (cli_add/cli_del),
97 * no need for atomic ops.
98 */
99static uint64_t srv_id_reuse_cnt = 0;
100
Frédéric Lécaille7da71292019-05-20 09:47:07 +0200101/* The server names dictionary */
Thayne McCombs92149f92020-11-20 01:28:26 -0700102struct dict server_key_dict = {
103 .name = "server keys",
Frédéric Lécaille7da71292019-05-20 09:47:07 +0200104 .values = EB_ROOT_UNIQUE,
105};
106
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +0200107static const char *srv_adm_st_chg_cause_str[] = {
108 [SRV_ADM_STCHGC_NONE] = "",
109 [SRV_ADM_STCHGC_DNS_NOENT] = "entry removed from SRV record",
110 [SRV_ADM_STCHGC_DNS_NOIP] = "No IP for server ",
111 [SRV_ADM_STCHGC_DNS_NX] = "DNS NX status",
112 [SRV_ADM_STCHGC_DNS_TIMEOUT] = "DNS timeout status",
113 [SRV_ADM_STCHGC_DNS_REFUSED] = "DNS refused status",
114 [SRV_ADM_STCHGC_DNS_UNSPEC] = "unspecified DNS error",
115 [SRV_ADM_STCHGC_STATS_DISABLE] = "'disable' on stats page",
116 [SRV_ADM_STCHGC_STATS_STOP] = "'stop' on stats page"
117};
118
119const char *srv_adm_st_chg_cause(enum srv_adm_st_chg_cause cause)
120{
121 return srv_adm_st_chg_cause_str[cause];
122}
123
Simon Hormana3608442013-11-01 16:46:15 +0900124int srv_downtime(const struct server *s)
Willy Tarreau21faa912012-10-10 08:27:36 +0200125{
Amaury Denoyellee6ba7912020-10-29 15:59:05 +0100126 if ((s->cur_state != SRV_ST_STOPPED) || s->last_change >= now.tv_sec) // ignore negative time
Krzysztof Oledzki85130942007-10-22 16:21:10 +0200127 return s->down_time;
128
129 return now.tv_sec - s->last_change + s->down_time;
130}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200131
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -0500132int srv_lastsession(const struct server *s)
133{
134 if (s->counters.last_sess)
135 return now.tv_sec - s->counters.last_sess;
136
137 return -1;
138}
139
Simon Horman4a741432013-02-23 15:35:38 +0900140int srv_getinter(const struct check *check)
Willy Tarreau21faa912012-10-10 08:27:36 +0200141{
Simon Horman4a741432013-02-23 15:35:38 +0900142 const struct server *s = check->server;
143
Aurelien DARRAGON7d541a92022-12-07 12:17:24 +0100144 if ((check->state & (CHK_ST_CONFIGURED|CHK_ST_FASTINTER)) == CHK_ST_CONFIGURED &&
145 (check->health == check->rise + check->fall - 1))
Simon Horman4a741432013-02-23 15:35:38 +0900146 return check->inter;
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100147
Emeric Brun52a91d32017-08-31 14:41:55 +0200148 if ((s->next_state == SRV_ST_STOPPED) && check->health == 0)
Simon Horman4a741432013-02-23 15:35:38 +0900149 return (check->downinter)?(check->downinter):(check->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100150
Simon Horman4a741432013-02-23 15:35:38 +0900151 return (check->fastinter)?(check->fastinter):(check->inter);
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100152}
153
Olivier Houcharde9bad0a2018-01-17 17:39:34 +0100154/*
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +0100155 * Use this to publish EVENT_HDL_SUB_SERVER family type event
156 * from srv facility
157 * Event will be published in both global subscription list and
158 * server dedicated subscription list
159 * server ptr must be valid
Aurelien DARRAGON22f82f82022-11-25 18:07:49 +0100160 * must be called with srv lock or under thread_isolate
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +0100161 */
162static inline void srv_event_hdl_publish(struct event_hdl_sub_type event, struct server *srv, uint8_t thread_isolate)
163{
164 struct event_hdl_cb_data_server cb_data;
165
166 /* safe data assignments */
167 cb_data.safe.puid = srv->puid;
168 cb_data.safe.rid = srv->rid;
169 cb_data.safe.flags = srv->flags;
170 snprintf(cb_data.safe.name, sizeof(cb_data.safe.name), "%s", srv->id);
Aurelien DARRAGONd7142132023-03-22 17:35:47 +0100171 cb_data.safe.proxy_name[0] = '\0';
172 cb_data.safe.proxy_uuid = -1; /* default value */
173 if (srv->proxy) {
174 cb_data.safe.proxy_uuid = srv->proxy->uuid;
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +0100175 snprintf(cb_data.safe.proxy_name, sizeof(cb_data.safe.proxy_name), "%s", srv->proxy->id);
Aurelien DARRAGONd7142132023-03-22 17:35:47 +0100176 }
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +0100177 /* unsafe data assignments */
178 cb_data.unsafe.ptr = srv;
179 cb_data.unsafe.thread_isolate = thread_isolate;
Aurelien DARRAGON22f82f82022-11-25 18:07:49 +0100180 cb_data.unsafe.srv_lock = !thread_isolate;
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +0100181 /* publish in server dedicated sub list */
182 event_hdl_publish(&srv->e_subs, event, EVENT_HDL_CB_DATA(&cb_data));
183 /* publish in global subscription list */
184 event_hdl_publish(NULL, event, EVENT_HDL_CB_DATA(&cb_data));
185}
186
187/*
Olivier Houcharde9bad0a2018-01-17 17:39:34 +0100188 * Check that we did not get a hash collision.
Willy Tarreau595e7672020-10-20 17:30:08 +0200189 * Unlikely, but it can happen. The server's proxy must be at least
190 * read-locked.
Olivier Houcharde9bad0a2018-01-17 17:39:34 +0100191 */
192static inline void srv_check_for_dup_dyncookie(struct server *s)
Olivier Houchard4e694042017-03-14 20:01:29 +0100193{
194 struct proxy *p = s->proxy;
195 struct server *tmpserv;
Olivier Houcharde9bad0a2018-01-17 17:39:34 +0100196
197 for (tmpserv = p->srv; tmpserv != NULL;
198 tmpserv = tmpserv->next) {
199 if (tmpserv == s)
200 continue;
201 if (tmpserv->next_admin & SRV_ADMF_FMAINT)
202 continue;
203 if (tmpserv->cookie &&
204 strcmp(tmpserv->cookie, s->cookie) == 0) {
205 ha_warning("We generated two equal cookies for two different servers.\n"
206 "Please change the secret key for '%s'.\n",
207 s->proxy->id);
208 }
209 }
210
211}
212
Willy Tarreau46b7f532018-08-21 11:54:26 +0200213/*
Willy Tarreau595e7672020-10-20 17:30:08 +0200214 * Must be called with the server lock held, and will read-lock the proxy.
Willy Tarreau46b7f532018-08-21 11:54:26 +0200215 */
Olivier Houcharde9bad0a2018-01-17 17:39:34 +0100216void srv_set_dyncookie(struct server *s)
217{
218 struct proxy *p = s->proxy;
Olivier Houchard4e694042017-03-14 20:01:29 +0100219 char *tmpbuf;
220 unsigned long long hash_value;
Olivier Houchard2cb49eb2017-03-15 15:11:06 +0100221 size_t key_len;
Olivier Houchard4e694042017-03-14 20:01:29 +0100222 size_t buffer_len;
223 int addr_len;
224 int port;
225
Willy Tarreau595e7672020-10-20 17:30:08 +0200226 HA_RWLOCK_RDLOCK(PROXY_LOCK, &p->lock);
Willy Tarreau5e83d992019-07-30 11:59:34 +0200227
Olivier Houchard4e694042017-03-14 20:01:29 +0100228 if ((s->flags & SRV_F_COOKIESET) ||
229 !(s->proxy->ck_opts & PR_CK_DYNAMIC) ||
230 s->proxy->dyncookie_key == NULL)
Willy Tarreau5e83d992019-07-30 11:59:34 +0200231 goto out;
Olivier Houchard2cb49eb2017-03-15 15:11:06 +0100232 key_len = strlen(p->dyncookie_key);
Olivier Houchard4e694042017-03-14 20:01:29 +0100233
234 if (s->addr.ss_family != AF_INET &&
235 s->addr.ss_family != AF_INET6)
Willy Tarreau5e83d992019-07-30 11:59:34 +0200236 goto out;
Olivier Houchard4e694042017-03-14 20:01:29 +0100237 /*
238 * Buffer to calculate the cookie value.
239 * The buffer contains the secret key + the server IP address
240 * + the TCP port.
241 */
242 addr_len = (s->addr.ss_family == AF_INET) ? 4 : 16;
243 /*
244 * The TCP port should use only 2 bytes, but is stored in
245 * an unsigned int in struct server, so let's use 4, to be
246 * on the safe side.
247 */
248 buffer_len = key_len + addr_len + 4;
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200249 tmpbuf = trash.area;
Olivier Houchard4e694042017-03-14 20:01:29 +0100250 memcpy(tmpbuf, p->dyncookie_key, key_len);
251 memcpy(&(tmpbuf[key_len]),
252 s->addr.ss_family == AF_INET ?
253 (void *)&((struct sockaddr_in *)&s->addr)->sin_addr.s_addr :
254 (void *)&(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr),
255 addr_len);
256 /*
257 * Make sure it's the same across all the load balancers,
258 * no matter their endianness.
259 */
260 port = htonl(s->svc_port);
261 memcpy(&tmpbuf[key_len + addr_len], &port, 4);
262 hash_value = XXH64(tmpbuf, buffer_len, 0);
263 memprintf(&s->cookie, "%016llx", hash_value);
264 if (!s->cookie)
Willy Tarreau5e83d992019-07-30 11:59:34 +0200265 goto out;
Olivier Houchard4e694042017-03-14 20:01:29 +0100266 s->cklen = 16;
Olivier Houcharde9bad0a2018-01-17 17:39:34 +0100267
268 /* Don't bother checking if the dyncookie is duplicated if
269 * the server is marked as "disabled", maybe it doesn't have
270 * its real IP yet, but just a place holder.
Olivier Houchard4e694042017-03-14 20:01:29 +0100271 */
Olivier Houcharde9bad0a2018-01-17 17:39:34 +0100272 if (!(s->next_admin & SRV_ADMF_FMAINT))
273 srv_check_for_dup_dyncookie(s);
Willy Tarreau5e83d992019-07-30 11:59:34 +0200274 out:
Willy Tarreau595e7672020-10-20 17:30:08 +0200275 HA_RWLOCK_RDUNLOCK(PROXY_LOCK, &p->lock);
Olivier Houchard4e694042017-03-14 20:01:29 +0100276}
277
Amaury Denoyelle9c3251d2021-10-18 14:39:57 +0200278/* Returns true if it's possible to reuse an idle connection from server <srv>
279 * for a websocket stream. This is the case if server is configured to use the
280 * same protocol for both HTTP and websocket streams. This depends on the value
281 * of "proto", "alpn" and "ws" keywords.
282 */
283int srv_check_reuse_ws(struct server *srv)
284{
285 if (srv->mux_proto || srv->use_ssl != 1 || !srv->ssl_ctx.alpn_str) {
286 /* explicit srv.mux_proto or no ALPN : srv.mux_proto is used
287 * for mux selection.
288 */
289 const struct ist srv_mux = srv->mux_proto ?
290 srv->mux_proto->token : IST_NULL;
291
292 switch (srv->ws) {
293 /* "auto" means use the same protocol : reuse is possible. */
294 case SRV_WS_AUTO:
295 return 1;
296
297 /* "h2" means use h2 for websocket : reuse is possible if
298 * server mux is h2.
299 */
300 case SRV_WS_H2:
301 if (srv->mux_proto && isteq(srv_mux, ist("h2")))
302 return 1;
303 break;
304
305 /* "h1" means use h1 for websocket : reuse is possible if
306 * server mux is h1.
307 */
308 case SRV_WS_H1:
309 if (!srv->mux_proto || isteq(srv_mux, ist("h1")))
310 return 1;
311 break;
312 }
313 }
314 else {
315 /* ALPN selection.
316 * Based on the assumption that only "h2" and "http/1.1" token
317 * are used on server ALPN.
318 */
319 const struct ist alpn = ist2(srv->ssl_ctx.alpn_str,
320 srv->ssl_ctx.alpn_len);
321
322 switch (srv->ws) {
323 case SRV_WS_AUTO:
324 /* for auto mode, consider reuse as possible if the
325 * server uses a single protocol ALPN
326 */
327 if (!istchr(alpn, ','))
328 return 1;
329 break;
330
331 case SRV_WS_H2:
332 return isteq(alpn, ist("\x02h2"));
333
334 case SRV_WS_H1:
335 return isteq(alpn, ist("\x08http/1.1"));
336 }
337 }
338
339 return 0;
340}
341
342/* Return the proto to used for a websocket stream on <srv> without ALPN. NULL
343 * is a valid value indicating to use the fallback mux.
344 */
345const struct mux_ops *srv_get_ws_proto(struct server *srv)
346{
347 const struct mux_proto_list *mux = NULL;
348
349 switch (srv->ws) {
350 case SRV_WS_AUTO:
351 mux = srv->mux_proto;
352 break;
353
354 case SRV_WS_H1:
355 mux = get_mux_proto(ist("h1"));
356 break;
357
358 case SRV_WS_H2:
359 mux = get_mux_proto(ist("h2"));
360 break;
361 }
362
363 return mux ? mux->mux : NULL;
364}
365
Willy Tarreau21faa912012-10-10 08:27:36 +0200366/*
Amaury Denoyelle8ff04342021-06-08 15:19:51 +0200367 * Must be called with the server lock held. The server is first removed from
368 * the proxy tree if it was already attached. If <reattach> is true, the server
369 * will then be attached in the proxy tree. The proxy lock is held to
370 * manipulate the tree.
Thayne McCombs92149f92020-11-20 01:28:26 -0700371 */
Amaury Denoyelle8ff04342021-06-08 15:19:51 +0200372static void srv_set_addr_desc(struct server *s, int reattach)
Thayne McCombs92149f92020-11-20 01:28:26 -0700373{
374 struct proxy *p = s->proxy;
375 char *key;
376
377 key = sa2str(&s->addr, s->svc_port, s->flags & SRV_F_MAPPORTS);
378
379 if (s->addr_node.key) {
Thayne McCombs24da7e12021-01-05 23:10:09 -0700380 if (key && strcmp(key, s->addr_node.key) == 0) {
Thayne McCombs92149f92020-11-20 01:28:26 -0700381 free(key);
382 return;
383 }
384
385 HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
386 ebpt_delete(&s->addr_node);
387 HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
388
389 free(s->addr_node.key);
390 }
391
392 s->addr_node.key = key;
393
Amaury Denoyelle8ff04342021-06-08 15:19:51 +0200394 if (reattach) {
395 if (s->addr_node.key) {
396 HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
397 ebis_insert(&p->used_server_addr, &s->addr_node);
398 HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
399 }
Thayne McCombs24da7e12021-01-05 23:10:09 -0700400 }
Thayne McCombs92149f92020-11-20 01:28:26 -0700401}
402
403/*
Willy Tarreau21faa912012-10-10 08:27:36 +0200404 * Registers the server keyword list <kwl> as a list of valid keywords for next
405 * parsing sessions.
406 */
407void srv_register_keywords(struct srv_kw_list *kwl)
408{
Willy Tarreau2b718102021-04-21 07:32:39 +0200409 LIST_APPEND(&srv_keywords.list, &kwl->list);
Willy Tarreau21faa912012-10-10 08:27:36 +0200410}
411
412/* Return a pointer to the server keyword <kw>, or NULL if not found. If the
413 * keyword is found with a NULL ->parse() function, then an attempt is made to
414 * find one with a valid ->parse() function. This way it is possible to declare
415 * platform-dependant, known keywords as NULL, then only declare them as valid
416 * if some options are met. Note that if the requested keyword contains an
417 * opening parenthesis, everything from this point is ignored.
418 */
419struct srv_kw *srv_find_kw(const char *kw)
420{
421 int index;
422 const char *kwend;
423 struct srv_kw_list *kwl;
424 struct srv_kw *ret = NULL;
425
426 kwend = strchr(kw, '(');
427 if (!kwend)
428 kwend = kw + strlen(kw);
429
430 list_for_each_entry(kwl, &srv_keywords.list, list) {
431 for (index = 0; kwl->kw[index].kw != NULL; index++) {
432 if ((strncmp(kwl->kw[index].kw, kw, kwend - kw) == 0) &&
433 kwl->kw[index].kw[kwend-kw] == 0) {
434 if (kwl->kw[index].parse)
435 return &kwl->kw[index]; /* found it !*/
436 else
437 ret = &kwl->kw[index]; /* may be OK */
438 }
439 }
440 }
441 return ret;
442}
443
444/* Dumps all registered "server" keywords to the <out> string pointer. The
445 * unsupported keywords are only dumped if their supported form was not
446 * found.
447 */
448void srv_dump_kws(char **out)
449{
450 struct srv_kw_list *kwl;
451 int index;
452
Christopher Faulet784063e2020-05-18 12:14:18 +0200453 if (!out)
454 return;
455
Willy Tarreau21faa912012-10-10 08:27:36 +0200456 *out = NULL;
457 list_for_each_entry(kwl, &srv_keywords.list, list) {
458 for (index = 0; kwl->kw[index].kw != NULL; index++) {
459 if (kwl->kw[index].parse ||
460 srv_find_kw(kwl->kw[index].kw) == &kwl->kw[index]) {
461 memprintf(out, "%s[%4s] %s%s%s%s\n", *out ? *out : "",
462 kwl->scope,
463 kwl->kw[index].kw,
464 kwl->kw[index].skip ? " <arg>" : "",
465 kwl->kw[index].default_ok ? " [dflt_ok]" : "",
466 kwl->kw[index].parse ? "" : " (not supported)");
467 }
468 }
469 }
Willy Tarreau49c2b452021-03-12 09:58:04 +0100470}
471
472/* Try to find in srv_keyword the word that looks closest to <word> by counting
473 * transitions between letters, digits and other characters. Will return the
474 * best matching word if found, otherwise NULL. An optional array of extra
475 * words to compare may be passed in <extra>, but it must then be terminated
476 * by a NULL entry. If unused it may be NULL.
477 */
478static const char *srv_find_best_kw(const char *word)
479{
480 uint8_t word_sig[1024];
481 uint8_t list_sig[1024];
482 const struct srv_kw_list *kwl;
483 const char *best_ptr = NULL;
484 int dist, best_dist = INT_MAX;
485 const char **extra;
486 int index;
487
488 make_word_fingerprint(word_sig, word);
489 list_for_each_entry(kwl, &srv_keywords.list, list) {
490 for (index = 0; kwl->kw[index].kw != NULL; index++) {
491 make_word_fingerprint(list_sig, kwl->kw[index].kw);
492 dist = word_fingerprint_distance(word_sig, list_sig);
493 if (dist < best_dist) {
494 best_dist = dist;
495 best_ptr = kwl->kw[index].kw;
496 }
497 }
498 }
499
Amaury Denoyelle587b71e2021-03-10 16:36:02 +0100500 for (extra = extra_kw_list; *extra; extra++) {
Willy Tarreau49c2b452021-03-12 09:58:04 +0100501 make_word_fingerprint(list_sig, *extra);
502 dist = word_fingerprint_distance(word_sig, list_sig);
503 if (dist < best_dist) {
504 best_dist = dist;
505 best_ptr = *extra;
506 }
Willy Tarreau49c2b452021-03-12 09:58:04 +0100507 }
508
509 if (best_dist > 2 * strlen(word) || (best_ptr && best_dist > 2 * strlen(best_ptr)))
510 best_ptr = NULL;
511
512 return best_ptr;
Willy Tarreau21faa912012-10-10 08:27:36 +0200513}
Krzysztof Piotr Oledzki5259dfe2008-01-21 01:54:06 +0100514
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +0100515/* Parse the "backup" server keyword */
516static int srv_parse_backup(char **args, int *cur_arg,
517 struct proxy *curproxy, struct server *newsrv, char **err)
518{
519 newsrv->flags |= SRV_F_BACKUP;
520 return 0;
521}
522
Alexander Liu2a54bb72019-05-22 19:44:48 +0800523
Frédéric Lécaille9d1b95b2017-03-15 09:13:33 +0100524/* Parse the "cookie" server keyword */
525static int srv_parse_cookie(char **args, int *cur_arg,
526 struct proxy *curproxy, struct server *newsrv, char **err)
527{
528 char *arg;
529
530 arg = args[*cur_arg + 1];
531 if (!*arg) {
532 memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
533 return ERR_ALERT | ERR_FATAL;
534 }
535
536 free(newsrv->cookie);
537 newsrv->cookie = strdup(arg);
538 newsrv->cklen = strlen(arg);
539 newsrv->flags |= SRV_F_COOKIESET;
540 return 0;
541}
542
Frédéric Lécaille2a0d0612017-03-21 11:53:54 +0100543/* Parse the "disabled" server keyword */
544static int srv_parse_disabled(char **args, int *cur_arg,
545 struct proxy *curproxy, struct server *newsrv, char **err)
546{
Emeric Brun52a91d32017-08-31 14:41:55 +0200547 newsrv->next_admin |= SRV_ADMF_CMAINT | SRV_ADMF_FMAINT;
548 newsrv->next_state = SRV_ST_STOPPED;
Frédéric Lécaille2a0d0612017-03-21 11:53:54 +0100549 newsrv->check.state |= CHK_ST_PAUSED;
550 newsrv->check.health = 0;
551 return 0;
552}
553
554/* Parse the "enabled" server keyword */
555static int srv_parse_enabled(char **args, int *cur_arg,
556 struct proxy *curproxy, struct server *newsrv, char **err)
557{
Emeric Brun52a91d32017-08-31 14:41:55 +0200558 newsrv->next_admin &= ~SRV_ADMF_CMAINT & ~SRV_ADMF_FMAINT;
559 newsrv->next_state = SRV_ST_RUNNING;
Frédéric Lécaille2a0d0612017-03-21 11:53:54 +0100560 newsrv->check.state &= ~CHK_ST_PAUSED;
561 newsrv->check.health = newsrv->check.rise;
562 return 0;
563}
564
Amaury Denoyelle587b71e2021-03-10 16:36:02 +0100565/* Parse the "error-limit" server keyword */
566static int srv_parse_error_limit(char **args, int *cur_arg,
567 struct proxy *curproxy, struct server *newsrv, char **err)
568{
569 if (!*args[*cur_arg + 1]) {
570 memprintf(err, "'%s' expects an integer argument.",
571 args[*cur_arg]);
572 return ERR_ALERT | ERR_FATAL;
573 }
574
575 newsrv->consecutive_errors_limit = atoi(args[*cur_arg + 1]);
576
577 if (newsrv->consecutive_errors_limit <= 0) {
578 memprintf(err, "%s has to be > 0.",
579 args[*cur_arg]);
580 return ERR_ALERT | ERR_FATAL;
581 }
582
583 return 0;
584}
585
Amaury Denoyellef9d59572021-10-18 14:40:29 +0200586/* Parse the "ws" keyword */
587static int srv_parse_ws(char **args, int *cur_arg,
588 struct proxy *curproxy, struct server *newsrv, char **err)
589{
590 if (!args[*cur_arg + 1]) {
591 memprintf(err, "'%s' expects 'auto', 'h1' or 'h2' value", args[*cur_arg]);
592 return ERR_ALERT | ERR_FATAL;
593 }
594
595 if (strcmp(args[*cur_arg + 1], "h1") == 0) {
596 newsrv->ws = SRV_WS_H1;
597 }
598 else if (strcmp(args[*cur_arg + 1], "h2") == 0) {
599 newsrv->ws = SRV_WS_H2;
600 }
601 else if (strcmp(args[*cur_arg + 1], "auto") == 0) {
602 newsrv->ws = SRV_WS_AUTO;
603 }
604 else {
605 memprintf(err, "'%s' has to be 'auto', 'h1' or 'h2'", args[*cur_arg]);
606 return ERR_ALERT | ERR_FATAL;
607 }
608
609
610 return 0;
611}
612
Amaury Denoyelle587b71e2021-03-10 16:36:02 +0100613/* Parse the "init-addr" server keyword */
614static int srv_parse_init_addr(char **args, int *cur_arg,
615 struct proxy *curproxy, struct server *newsrv, char **err)
616{
617 char *p, *end;
618 int done;
619 struct sockaddr_storage sa;
620
621 newsrv->init_addr_methods = 0;
622 memset(&newsrv->init_addr, 0, sizeof(newsrv->init_addr));
623
624 for (p = args[*cur_arg + 1]; *p; p = end) {
625 /* cut on next comma */
626 for (end = p; *end && *end != ','; end++);
627 if (*end)
628 *(end++) = 0;
629
630 memset(&sa, 0, sizeof(sa));
631 if (strcmp(p, "libc") == 0) {
632 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_LIBC);
633 }
634 else if (strcmp(p, "last") == 0) {
635 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_LAST);
636 }
637 else if (strcmp(p, "none") == 0) {
638 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_NONE);
639 }
640 else if (str2ip2(p, &sa, 0)) {
641 if (is_addr(&newsrv->init_addr)) {
642 memprintf(err, "'%s' : initial address already specified, cannot add '%s'.",
643 args[*cur_arg], p);
644 return ERR_ALERT | ERR_FATAL;
645 }
646 newsrv->init_addr = sa;
647 done = srv_append_initaddr(&newsrv->init_addr_methods, SRV_IADDR_IP);
648 }
649 else {
650 memprintf(err, "'%s' : unknown init-addr method '%s', supported methods are 'libc', 'last', 'none'.",
651 args[*cur_arg], p);
652 return ERR_ALERT | ERR_FATAL;
653 }
654 if (!done) {
655 memprintf(err, "'%s' : too many init-addr methods when trying to add '%s'",
656 args[*cur_arg], p);
657 return ERR_ALERT | ERR_FATAL;
658 }
659 }
660
661 return 0;
662}
663
664/* Parse the "log-proto" server keyword */
665static int srv_parse_log_proto(char **args, int *cur_arg,
666 struct proxy *curproxy, struct server *newsrv, char **err)
667{
668 if (strcmp(args[*cur_arg + 1], "legacy") == 0)
669 newsrv->log_proto = SRV_LOG_PROTO_LEGACY;
670 else if (strcmp(args[*cur_arg + 1], "octet-count") == 0)
671 newsrv->log_proto = SRV_LOG_PROTO_OCTET_COUNTING;
672 else {
673 memprintf(err, "'%s' expects one of 'legacy' or 'octet-count' but got '%s'",
674 args[*cur_arg], args[*cur_arg + 1]);
675 return ERR_ALERT | ERR_FATAL;
676 }
677
678 return 0;
679}
680
681/* Parse the "maxconn" server keyword */
682static int srv_parse_maxconn(char **args, int *cur_arg,
683 struct proxy *curproxy, struct server *newsrv, char **err)
684{
685 newsrv->maxconn = atol(args[*cur_arg + 1]);
686 return 0;
687}
688
689/* Parse the "maxqueue" server keyword */
690static int srv_parse_maxqueue(char **args, int *cur_arg,
691 struct proxy *curproxy, struct server *newsrv, char **err)
692{
693 newsrv->maxqueue = atol(args[*cur_arg + 1]);
694 return 0;
695}
696
697/* Parse the "minconn" server keyword */
698static int srv_parse_minconn(char **args, int *cur_arg,
699 struct proxy *curproxy, struct server *newsrv, char **err)
700{
701 newsrv->minconn = atol(args[*cur_arg + 1]);
702 return 0;
703}
704
Willy Tarreau9c538e02019-01-23 10:21:49 +0100705static int srv_parse_max_reuse(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
706{
707 char *arg;
708
709 arg = args[*cur_arg + 1];
710 if (!*arg) {
711 memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
712 return ERR_ALERT | ERR_FATAL;
713 }
714 newsrv->max_reuse = atoi(arg);
715
716 return 0;
717}
718
Olivier Houchardb7b3faa2018-12-14 18:15:36 +0100719static int srv_parse_pool_purge_delay(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
Olivier Houchard0c18a6f2018-12-02 14:11:41 +0100720{
721 const char *res;
722 char *arg;
723 unsigned int time;
724
725 arg = args[*cur_arg + 1];
726 if (!*arg) {
727 memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
728 return ERR_ALERT | ERR_FATAL;
729 }
730 res = parse_time_err(arg, &time, TIME_UNIT_MS);
Willy Tarreau9faebe32019-06-07 19:00:37 +0200731 if (res == PARSE_TIME_OVER) {
732 memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
733 args[*cur_arg+1], args[*cur_arg]);
734 return ERR_ALERT | ERR_FATAL;
735 }
736 else if (res == PARSE_TIME_UNDER) {
737 memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
738 args[*cur_arg+1], args[*cur_arg]);
739 return ERR_ALERT | ERR_FATAL;
740 }
741 else if (res) {
Olivier Houchard0c18a6f2018-12-02 14:11:41 +0100742 memprintf(err, "unexpected character '%c' in argument to <%s>.\n",
743 *res, args[*cur_arg]);
744 return ERR_ALERT | ERR_FATAL;
745 }
Olivier Houchardb7b3faa2018-12-14 18:15:36 +0100746 newsrv->pool_purge_delay = time;
Olivier Houchard0c18a6f2018-12-02 14:11:41 +0100747
748 return 0;
749}
750
Willy Tarreau2f3f4d32020-07-01 07:43:51 +0200751static int srv_parse_pool_low_conn(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
752{
753 char *arg;
754
755 arg = args[*cur_arg + 1];
756 if (!*arg) {
757 memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
758 return ERR_ALERT | ERR_FATAL;
759 }
760
761 newsrv->low_idle_conns = atoi(arg);
762 return 0;
763}
764
Olivier Houchard006e3102018-12-10 18:30:32 +0100765static int srv_parse_pool_max_conn(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
766{
767 char *arg;
768
769 arg = args[*cur_arg + 1];
770 if (!*arg) {
771 memprintf(err, "'%s' expects <value> as argument.\n", args[*cur_arg]);
772 return ERR_ALERT | ERR_FATAL;
773 }
Willy Tarreaucb923d52019-01-23 10:39:27 +0100774
Olivier Houchard006e3102018-12-10 18:30:32 +0100775 newsrv->max_idle_conns = atoi(arg);
Willy Tarreaucb923d52019-01-23 10:39:27 +0100776 if ((int)newsrv->max_idle_conns < -1) {
777 memprintf(err, "'%s' must be >= -1", args[*cur_arg]);
778 return ERR_ALERT | ERR_FATAL;
779 }
Olivier Houchard006e3102018-12-10 18:30:32 +0100780
781 return 0;
782}
783
Willy Tarreaudff55432012-10-10 17:51:05 +0200784/* parse the "id" server keyword */
785static int srv_parse_id(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err)
786{
787 struct eb32_node *node;
788
789 if (!*args[*cur_arg + 1]) {
790 memprintf(err, "'%s' : expects an integer argument", args[*cur_arg]);
791 return ERR_ALERT | ERR_FATAL;
792 }
793
794 newsrv->puid = atol(args[*cur_arg + 1]);
795 newsrv->conf.id.key = newsrv->puid;
796
797 if (newsrv->puid <= 0) {
798 memprintf(err, "'%s' : custom id has to be > 0", args[*cur_arg]);
799 return ERR_ALERT | ERR_FATAL;
800 }
801
802 node = eb32_lookup(&curproxy->conf.used_server_id, newsrv->puid);
803 if (node) {
804 struct server *target = container_of(node, struct server, conf.id);
805 memprintf(err, "'%s' : custom id %d already used at %s:%d ('server %s')",
806 args[*cur_arg], newsrv->puid, target->conf.file, target->conf.line,
807 target->id);
808 return ERR_ALERT | ERR_FATAL;
809 }
810
Baptiste Assmann7cc419a2015-07-07 22:02:20 +0200811 newsrv->flags |= SRV_F_FORCED_ID;
Willy Tarreaudff55432012-10-10 17:51:05 +0200812 return 0;
813}
814
Frédéric Lécaille22f41a22017-03-16 17:17:36 +0100815/* Parse the "namespace" server keyword */
816static int srv_parse_namespace(char **args, int *cur_arg,
817 struct proxy *curproxy, struct server *newsrv, char **err)
818{
Willy Tarreaue5733232019-05-22 19:24:06 +0200819#ifdef USE_NS
Frédéric Lécaille22f41a22017-03-16 17:17:36 +0100820 char *arg;
821
822 arg = args[*cur_arg + 1];
823 if (!*arg) {
824 memprintf(err, "'%s' : expects <name> as argument", args[*cur_arg]);
825 return ERR_ALERT | ERR_FATAL;
826 }
827
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100828 if (strcmp(arg, "*") == 0) {
Frédéric Lécaille22f41a22017-03-16 17:17:36 +0100829 /* Use the namespace associated with the connection (if present). */
830 newsrv->flags |= SRV_F_USE_NS_FROM_PP;
831 return 0;
832 }
833
834 /*
835 * As this parser may be called several times for the same 'default-server'
836 * object, or for a new 'server' instance deriving from a 'default-server'
837 * one with SRV_F_USE_NS_FROM_PP flag enabled, let's reset it.
838 */
839 newsrv->flags &= ~SRV_F_USE_NS_FROM_PP;
840
841 newsrv->netns = netns_store_lookup(arg, strlen(arg));
842 if (!newsrv->netns)
843 newsrv->netns = netns_store_insert(arg);
844
845 if (!newsrv->netns) {
846 memprintf(err, "Cannot open namespace '%s'", arg);
847 return ERR_ALERT | ERR_FATAL;
848 }
849
850 return 0;
851#else
852 memprintf(err, "'%s': '%s' option not implemented", args[0], args[*cur_arg]);
853 return ERR_ALERT | ERR_FATAL;
854#endif
855}
856
Frédéric Lécaillef5bf9032017-03-10 11:51:05 +0100857/* Parse the "no-backup" server keyword */
858static int srv_parse_no_backup(char **args, int *cur_arg,
859 struct proxy *curproxy, struct server *newsrv, char **err)
860{
861 newsrv->flags &= ~SRV_F_BACKUP;
862 return 0;
863}
864
Frédéric Lécaille25df8902017-03-10 14:04:31 +0100865
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100866/* Disable server PROXY protocol flags. */
Willy Tarreau0e492e22019-04-15 21:25:03 +0200867static inline int srv_disable_pp_flags(struct server *srv, unsigned int flags)
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100868{
869 srv->pp_opts &= ~flags;
870 return 0;
871}
872
873/* Parse the "no-send-proxy" server keyword */
874static int srv_parse_no_send_proxy(char **args, int *cur_arg,
875 struct proxy *curproxy, struct server *newsrv, char **err)
876{
877 return srv_disable_pp_flags(newsrv, SRV_PP_V1);
878}
879
880/* Parse the "no-send-proxy-v2" server keyword */
881static int srv_parse_no_send_proxy_v2(char **args, int *cur_arg,
882 struct proxy *curproxy, struct server *newsrv, char **err)
883{
884 return srv_disable_pp_flags(newsrv, SRV_PP_V2);
885}
886
Frédéric Lécaille36d15652022-10-17 14:58:19 +0200887/* Parse the "shard" server keyword */
888static int srv_parse_shard(char **args, int *cur_arg,
889 struct proxy *curproxy, struct server *newsrv, char **err)
890{
891 newsrv->shard = atol(args[*cur_arg + 1]);
892 return 0;
893}
894
Frédéric Lécaille1b9423d2019-07-04 14:19:06 +0200895/* Parse the "no-tfo" server keyword */
896static int srv_parse_no_tfo(char **args, int *cur_arg,
897 struct proxy *curproxy, struct server *newsrv, char **err)
898{
899 newsrv->flags &= ~SRV_F_FASTOPEN;
900 return 0;
901}
902
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +0100903/* Parse the "non-stick" server keyword */
904static int srv_parse_non_stick(char **args, int *cur_arg,
905 struct proxy *curproxy, struct server *newsrv, char **err)
906{
907 newsrv->flags |= SRV_F_NON_STICK;
908 return 0;
909}
910
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100911/* Enable server PROXY protocol flags. */
Willy Tarreau0e492e22019-04-15 21:25:03 +0200912static inline int srv_enable_pp_flags(struct server *srv, unsigned int flags)
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100913{
914 srv->pp_opts |= flags;
915 return 0;
916}
Christopher Faulet8ed0a3e2018-04-10 14:45:45 +0200917/* parse the "proto" server keyword */
918static int srv_parse_proto(char **args, int *cur_arg,
919 struct proxy *px, struct server *newsrv, char **err)
920{
921 struct ist proto;
922
923 if (!*args[*cur_arg + 1]) {
924 memprintf(err, "'%s' : missing value", args[*cur_arg]);
925 return ERR_ALERT | ERR_FATAL;
926 }
Tim Duesterhusdcf753a2021-03-04 17:31:47 +0100927 proto = ist(args[*cur_arg + 1]);
Christopher Faulet8ed0a3e2018-04-10 14:45:45 +0200928 newsrv->mux_proto = get_mux_proto(proto);
929 if (!newsrv->mux_proto) {
930 memprintf(err, "'%s' : unknown MUX protocol '%s'", args[*cur_arg], args[*cur_arg+1]);
931 return ERR_ALERT | ERR_FATAL;
932 }
Christopher Faulet8ed0a3e2018-04-10 14:45:45 +0200933 return 0;
934}
Frédéric Lécaille31045e42017-03-10 16:40:00 +0100935
Emmanuel Hocdetf643b802018-02-01 15:20:32 +0100936/* parse the "proxy-v2-options" */
937static int srv_parse_proxy_v2_options(char **args, int *cur_arg,
938 struct proxy *px, struct server *newsrv, char **err)
939{
940 char *p, *n;
941 for (p = args[*cur_arg+1]; p; p = n) {
942 n = strchr(p, ',');
943 if (n)
944 *n++ = '\0';
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100945 if (strcmp(p, "ssl") == 0) {
Emmanuel Hocdetf643b802018-02-01 15:20:32 +0100946 newsrv->pp_opts |= SRV_PP_V2_SSL;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100947 } else if (strcmp(p, "cert-cn") == 0) {
Emmanuel Hocdetf643b802018-02-01 15:20:32 +0100948 newsrv->pp_opts |= SRV_PP_V2_SSL;
949 newsrv->pp_opts |= SRV_PP_V2_SSL_CN;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100950 } else if (strcmp(p, "cert-key") == 0) {
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +0100951 newsrv->pp_opts |= SRV_PP_V2_SSL;
952 newsrv->pp_opts |= SRV_PP_V2_SSL_KEY_ALG;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100953 } else if (strcmp(p, "cert-sig") == 0) {
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +0100954 newsrv->pp_opts |= SRV_PP_V2_SSL;
955 newsrv->pp_opts |= SRV_PP_V2_SSL_SIG_ALG;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100956 } else if (strcmp(p, "ssl-cipher") == 0) {
Emmanuel Hocdetfa8d0f12018-02-01 15:53:52 +0100957 newsrv->pp_opts |= SRV_PP_V2_SSL;
958 newsrv->pp_opts |= SRV_PP_V2_SSL_CIPHER;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100959 } else if (strcmp(p, "authority") == 0) {
Emmanuel Hocdet253c3b72018-02-01 18:29:59 +0100960 newsrv->pp_opts |= SRV_PP_V2_AUTHORITY;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100961 } else if (strcmp(p, "crc32c") == 0) {
Emmanuel Hocdet4399c752018-02-05 15:26:43 +0100962 newsrv->pp_opts |= SRV_PP_V2_CRC32C;
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100963 } else if (strcmp(p, "unique-id") == 0) {
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100964 newsrv->pp_opts |= SRV_PP_V2_UNIQUE_ID;
Emmanuel Hocdetf643b802018-02-01 15:20:32 +0100965 } else
966 goto fail;
967 }
968 return 0;
969 fail:
970 if (err)
971 memprintf(err, "'%s' : proxy v2 option not implemented", p);
972 return ERR_ALERT | ERR_FATAL;
973}
974
Frédéric Lécaille547356e2017-03-15 08:55:39 +0100975/* Parse the "observe" server keyword */
976static int srv_parse_observe(char **args, int *cur_arg,
977 struct proxy *curproxy, struct server *newsrv, char **err)
978{
979 char *arg;
980
981 arg = args[*cur_arg + 1];
982 if (!*arg) {
983 memprintf(err, "'%s' expects <mode> as argument.\n", args[*cur_arg]);
984 return ERR_ALERT | ERR_FATAL;
985 }
986
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100987 if (strcmp(arg, "none") == 0) {
Frédéric Lécaille547356e2017-03-15 08:55:39 +0100988 newsrv->observe = HANA_OBS_NONE;
989 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100990 else if (strcmp(arg, "layer4") == 0) {
Frédéric Lécaille547356e2017-03-15 08:55:39 +0100991 newsrv->observe = HANA_OBS_LAYER4;
992 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100993 else if (strcmp(arg, "layer7") == 0) {
Frédéric Lécaille547356e2017-03-15 08:55:39 +0100994 if (curproxy->mode != PR_MODE_HTTP) {
995 memprintf(err, "'%s' can only be used in http proxies.\n", arg);
996 return ERR_ALERT;
997 }
998 newsrv->observe = HANA_OBS_LAYER7;
999 }
1000 else {
1001 memprintf(err, "'%s' expects one of 'none', 'layer4', 'layer7' "
1002 "but got '%s'\n", args[*cur_arg], arg);
1003 return ERR_ALERT | ERR_FATAL;
1004 }
1005
1006 return 0;
1007}
1008
Amaury Denoyelle587b71e2021-03-10 16:36:02 +01001009/* Parse the "on-error" server keyword */
1010static int srv_parse_on_error(char **args, int *cur_arg,
1011 struct proxy *curproxy, struct server *newsrv, char **err)
1012{
1013 if (strcmp(args[*cur_arg + 1], "fastinter") == 0)
1014 newsrv->onerror = HANA_ONERR_FASTINTER;
1015 else if (strcmp(args[*cur_arg + 1], "fail-check") == 0)
1016 newsrv->onerror = HANA_ONERR_FAILCHK;
1017 else if (strcmp(args[*cur_arg + 1], "sudden-death") == 0)
1018 newsrv->onerror = HANA_ONERR_SUDDTH;
1019 else if (strcmp(args[*cur_arg + 1], "mark-down") == 0)
1020 newsrv->onerror = HANA_ONERR_MARKDWN;
1021 else {
1022 memprintf(err, "'%s' expects one of 'fastinter', "
1023 "'fail-check', 'sudden-death' or 'mark-down' but got '%s'",
1024 args[*cur_arg], args[*cur_arg + 1]);
1025 return ERR_ALERT | ERR_FATAL;
1026 }
1027
1028 return 0;
1029}
1030
1031/* Parse the "on-marked-down" server keyword */
1032static int srv_parse_on_marked_down(char **args, int *cur_arg,
1033 struct proxy *curproxy, struct server *newsrv, char **err)
1034{
1035 if (strcmp(args[*cur_arg + 1], "shutdown-sessions") == 0)
1036 newsrv->onmarkeddown = HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS;
1037 else {
1038 memprintf(err, "'%s' expects 'shutdown-sessions' but got '%s'",
1039 args[*cur_arg], args[*cur_arg + 1]);
1040 return ERR_ALERT | ERR_FATAL;
1041 }
1042
1043 return 0;
1044}
1045
1046/* Parse the "on-marked-up" server keyword */
1047static int srv_parse_on_marked_up(char **args, int *cur_arg,
1048 struct proxy *curproxy, struct server *newsrv, char **err)
1049{
1050 if (strcmp(args[*cur_arg + 1], "shutdown-backup-sessions") == 0)
1051 newsrv->onmarkedup = HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS;
1052 else {
1053 memprintf(err, "'%s' expects 'shutdown-backup-sessions' but got '%s'",
1054 args[*cur_arg], args[*cur_arg + 1]);
1055 return ERR_ALERT | ERR_FATAL;
1056 }
1057
1058 return 0;
1059}
1060
Frédéric Lécaille16186232017-03-14 16:42:49 +01001061/* Parse the "redir" server keyword */
1062static int srv_parse_redir(char **args, int *cur_arg,
1063 struct proxy *curproxy, struct server *newsrv, char **err)
1064{
1065 char *arg;
1066
1067 arg = args[*cur_arg + 1];
1068 if (!*arg) {
1069 memprintf(err, "'%s' expects <prefix> as argument.\n", args[*cur_arg]);
1070 return ERR_ALERT | ERR_FATAL;
1071 }
1072
1073 free(newsrv->rdr_pfx);
1074 newsrv->rdr_pfx = strdup(arg);
1075 newsrv->rdr_len = strlen(arg);
1076
1077 return 0;
1078}
1079
Amaury Denoyelle587b71e2021-03-10 16:36:02 +01001080/* Parse the "resolvers" server keyword */
1081static int srv_parse_resolvers(char **args, int *cur_arg,
1082 struct proxy *curproxy, struct server *newsrv, char **err)
1083{
1084 free(newsrv->resolvers_id);
1085 newsrv->resolvers_id = strdup(args[*cur_arg + 1]);
1086 return 0;
1087}
1088
1089/* Parse the "resolve-net" server keyword */
1090static int srv_parse_resolve_net(char **args, int *cur_arg,
1091 struct proxy *curproxy, struct server *newsrv, char **err)
1092{
1093 char *p, *e;
1094 unsigned char mask;
1095 struct resolv_options *opt;
1096
1097 if (!args[*cur_arg + 1] || args[*cur_arg + 1][0] == '\0') {
1098 memprintf(err, "'%s' expects a list of networks.",
1099 args[*cur_arg]);
1100 return ERR_ALERT | ERR_FATAL;
1101 }
1102
1103 opt = &newsrv->resolv_opts;
1104
1105 /* Split arguments by comma, and convert it from ipv4 or ipv6
1106 * string network in in_addr or in6_addr.
1107 */
1108 p = args[*cur_arg + 1];
1109 e = p;
1110 while (*p != '\0') {
1111 /* If no room available, return error. */
1112 if (opt->pref_net_nb >= SRV_MAX_PREF_NET) {
1113 memprintf(err, "'%s' exceed %d networks.",
1114 args[*cur_arg], SRV_MAX_PREF_NET);
1115 return ERR_ALERT | ERR_FATAL;
1116 }
1117 /* look for end or comma. */
1118 while (*e != ',' && *e != '\0')
1119 e++;
1120 if (*e == ',') {
1121 *e = '\0';
1122 e++;
1123 }
1124 if (str2net(p, 0, &opt->pref_net[opt->pref_net_nb].addr.in4,
1125 &opt->pref_net[opt->pref_net_nb].mask.in4)) {
1126 /* Try to convert input string from ipv4 or ipv6 network. */
1127 opt->pref_net[opt->pref_net_nb].family = AF_INET;
1128 } else if (str62net(p, &opt->pref_net[opt->pref_net_nb].addr.in6,
1129 &mask)) {
1130 /* Try to convert input string from ipv6 network. */
1131 len2mask6(mask, &opt->pref_net[opt->pref_net_nb].mask.in6);
1132 opt->pref_net[opt->pref_net_nb].family = AF_INET6;
1133 } else {
1134 /* All network conversions fail, return error. */
1135 memprintf(err, "'%s' invalid network '%s'.",
1136 args[*cur_arg], p);
1137 return ERR_ALERT | ERR_FATAL;
1138 }
1139 opt->pref_net_nb++;
1140 p = e;
1141 }
1142
1143 return 0;
1144}
1145
1146/* Parse the "resolve-opts" server keyword */
1147static int srv_parse_resolve_opts(char **args, int *cur_arg,
1148 struct proxy *curproxy, struct server *newsrv, char **err)
1149{
1150 char *p, *end;
1151
1152 for (p = args[*cur_arg + 1]; *p; p = end) {
1153 /* cut on next comma */
1154 for (end = p; *end && *end != ','; end++);
1155 if (*end)
1156 *(end++) = 0;
1157
1158 if (strcmp(p, "allow-dup-ip") == 0) {
1159 newsrv->resolv_opts.accept_duplicate_ip = 1;
1160 }
1161 else if (strcmp(p, "ignore-weight") == 0) {
1162 newsrv->resolv_opts.ignore_weight = 1;
1163 }
1164 else if (strcmp(p, "prevent-dup-ip") == 0) {
1165 newsrv->resolv_opts.accept_duplicate_ip = 0;
1166 }
1167 else {
1168 memprintf(err, "'%s' : unknown resolve-opts option '%s', supported methods are 'allow-dup-ip', 'ignore-weight', and 'prevent-dup-ip'.",
1169 args[*cur_arg], p);
1170 return ERR_ALERT | ERR_FATAL;
1171 }
1172 }
1173
1174 return 0;
1175}
1176
1177/* Parse the "resolve-prefer" server keyword */
1178static int srv_parse_resolve_prefer(char **args, int *cur_arg,
1179 struct proxy *curproxy, struct server *newsrv, char **err)
1180{
1181 if (strcmp(args[*cur_arg + 1], "ipv4") == 0)
1182 newsrv->resolv_opts.family_prio = AF_INET;
1183 else if (strcmp(args[*cur_arg + 1], "ipv6") == 0)
1184 newsrv->resolv_opts.family_prio = AF_INET6;
1185 else {
1186 memprintf(err, "'%s' expects either ipv4 or ipv6 as argument.",
1187 args[*cur_arg]);
1188 return ERR_ALERT | ERR_FATAL;
1189 }
1190
1191 return 0;
1192}
1193
Frédéric Lécaille31045e42017-03-10 16:40:00 +01001194/* Parse the "send-proxy" server keyword */
1195static int srv_parse_send_proxy(char **args, int *cur_arg,
1196 struct proxy *curproxy, struct server *newsrv, char **err)
1197{
1198 return srv_enable_pp_flags(newsrv, SRV_PP_V1);
1199}
1200
1201/* Parse the "send-proxy-v2" server keyword */
1202static int srv_parse_send_proxy_v2(char **args, int *cur_arg,
1203 struct proxy *curproxy, struct server *newsrv, char **err)
1204{
1205 return srv_enable_pp_flags(newsrv, SRV_PP_V2);
1206}
1207
Amaury Denoyelle587b71e2021-03-10 16:36:02 +01001208/* Parse the "slowstart" server keyword */
1209static int srv_parse_slowstart(char **args, int *cur_arg,
1210 struct proxy *curproxy, struct server *newsrv, char **err)
1211{
1212 /* slowstart is stored in seconds */
1213 unsigned int val;
1214 const char *time_err = parse_time_err(args[*cur_arg + 1], &val, TIME_UNIT_MS);
1215
1216 if (time_err == PARSE_TIME_OVER) {
1217 memprintf(err, "overflow in argument <%s> to <%s> of server %s, maximum value is 2147483647 ms (~24.8 days).",
1218 args[*cur_arg+1], args[*cur_arg], newsrv->id);
1219 return ERR_ALERT | ERR_FATAL;
1220 }
1221 else if (time_err == PARSE_TIME_UNDER) {
1222 memprintf(err, "underflow in argument <%s> to <%s> of server %s, minimum non-null value is 1 ms.",
1223 args[*cur_arg+1], args[*cur_arg], newsrv->id);
1224 return ERR_ALERT | ERR_FATAL;
1225 }
1226 else if (time_err) {
1227 memprintf(err, "unexpected character '%c' in 'slowstart' argument of server %s.",
1228 *time_err, newsrv->id);
1229 return ERR_ALERT | ERR_FATAL;
1230 }
1231 newsrv->slowstart = (val + 999) / 1000;
1232
1233 return 0;
1234}
Frédéric Lécailledba97072017-03-17 15:33:50 +01001235
1236/* Parse the "source" server keyword */
1237static int srv_parse_source(char **args, int *cur_arg,
1238 struct proxy *curproxy, struct server *newsrv, char **err)
1239{
1240 char *errmsg;
1241 int port_low, port_high;
1242 struct sockaddr_storage *sk;
Frédéric Lécailledba97072017-03-17 15:33:50 +01001243
1244 errmsg = NULL;
1245
1246 if (!*args[*cur_arg + 1]) {
1247 memprintf(err, "'%s' expects <addr>[:<port>[-<port>]], and optionally '%s' <addr>, "
1248 "and '%s' <name> as argument.\n", args[*cur_arg], "usesrc", "interface");
1249 goto err;
1250 }
1251
1252 /* 'sk' is statically allocated (no need to be freed). */
Willy Tarreau65ec4e32020-09-16 19:17:08 +02001253 sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, NULL,
1254 &errmsg, NULL, NULL,
1255 PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_RANGE | PA_O_STREAM | PA_O_CONNECT);
Frédéric Lécailledba97072017-03-17 15:33:50 +01001256 if (!sk) {
1257 memprintf(err, "'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg);
1258 goto err;
1259 }
1260
Frédéric Lécailledba97072017-03-17 15:33:50 +01001261 newsrv->conn_src.opts |= CO_SRC_BIND;
1262 newsrv->conn_src.source_addr = *sk;
1263
1264 if (port_low != port_high) {
1265 int i;
1266
Frédéric Lécailledba97072017-03-17 15:33:50 +01001267 newsrv->conn_src.sport_range = port_range_alloc_range(port_high - port_low + 1);
Remi Tricot-Le Bretonf1800e62021-05-12 09:44:06 +02001268 if (!newsrv->conn_src.sport_range) {
1269 ha_alert("Server '%s': Out of memory (sport_range)\n", args[0]);
1270 goto err;
1271 }
Frédéric Lécailledba97072017-03-17 15:33:50 +01001272 for (i = 0; i < newsrv->conn_src.sport_range->size; i++)
1273 newsrv->conn_src.sport_range->ports[i] = port_low + i;
1274 }
1275
1276 *cur_arg += 2;
1277 while (*(args[*cur_arg])) {
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001278 if (strcmp(args[*cur_arg], "usesrc") == 0) { /* address to use outside */
Frédéric Lécailledba97072017-03-17 15:33:50 +01001279#if defined(CONFIG_HAP_TRANSPARENT)
1280 if (!*args[*cur_arg + 1]) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001281 ha_alert("'usesrc' expects <addr>[:<port>], 'client', 'clientip', "
1282 "or 'hdr_ip(name,#)' as argument.\n");
Frédéric Lécailledba97072017-03-17 15:33:50 +01001283 goto err;
1284 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001285 if (strcmp(args[*cur_arg + 1], "client") == 0) {
Frédéric Lécailledba97072017-03-17 15:33:50 +01001286 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
1287 newsrv->conn_src.opts |= CO_SRC_TPROXY_CLI;
1288 }
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001289 else if (strcmp(args[*cur_arg + 1], "clientip") == 0) {
Frédéric Lécailledba97072017-03-17 15:33:50 +01001290 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
1291 newsrv->conn_src.opts |= CO_SRC_TPROXY_CIP;
1292 }
1293 else if (!strncmp(args[*cur_arg + 1], "hdr_ip(", 7)) {
1294 char *name, *end;
1295
1296 name = args[*cur_arg + 1] + 7;
Willy Tarreau90807112020-02-25 08:16:33 +01001297 while (isspace((unsigned char)*name))
Frédéric Lécailledba97072017-03-17 15:33:50 +01001298 name++;
1299
1300 end = name;
Willy Tarreau90807112020-02-25 08:16:33 +01001301 while (*end && !isspace((unsigned char)*end) && *end != ',' && *end != ')')
Frédéric Lécailledba97072017-03-17 15:33:50 +01001302 end++;
1303
1304 newsrv->conn_src.opts &= ~CO_SRC_TPROXY_MASK;
1305 newsrv->conn_src.opts |= CO_SRC_TPROXY_DYN;
1306 free(newsrv->conn_src.bind_hdr_name);
1307 newsrv->conn_src.bind_hdr_name = calloc(1, end - name + 1);
Remi Tricot-Le Bretonf1800e62021-05-12 09:44:06 +02001308 if (!newsrv->conn_src.bind_hdr_name) {
1309 ha_alert("Server '%s': Out of memory (bind_hdr_name)\n", args[0]);
1310 goto err;
1311 }
Frédéric Lécailledba97072017-03-17 15:33:50 +01001312 newsrv->conn_src.bind_hdr_len = end - name;
1313 memcpy(newsrv->conn_src.bind_hdr_name, name, end - name);
1314 newsrv->conn_src.bind_hdr_name[end - name] = '\0';
1315 newsrv->conn_src.bind_hdr_occ = -1;
1316
1317 /* now look for an occurrence number */
Willy Tarreau90807112020-02-25 08:16:33 +01001318 while (isspace((unsigned char)*end))
Frédéric Lécailledba97072017-03-17 15:33:50 +01001319 end++;
1320 if (*end == ',') {
1321 end++;
1322 name = end;
1323 if (*end == '-')
1324 end++;
Willy Tarreau90807112020-02-25 08:16:33 +01001325 while (isdigit((unsigned char)*end))
Frédéric Lécailledba97072017-03-17 15:33:50 +01001326 end++;
1327 newsrv->conn_src.bind_hdr_occ = strl2ic(name, end - name);
1328 }
1329
1330 if (newsrv->conn_src.bind_hdr_occ < -MAX_HDR_HISTORY) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001331 ha_alert("usesrc hdr_ip(name,num) does not support negative"
1332 " occurrences values smaller than %d.\n", MAX_HDR_HISTORY);
Frédéric Lécailledba97072017-03-17 15:33:50 +01001333 goto err;
1334 }
1335 }
1336 else {
1337 struct sockaddr_storage *sk;
1338 int port1, port2;
1339
1340 /* 'sk' is statically allocated (no need to be freed). */
Willy Tarreau65ec4e32020-09-16 19:17:08 +02001341 sk = str2sa_range(args[*cur_arg + 1], NULL, &port1, &port2, NULL, NULL,
1342 &errmsg, NULL, NULL,
1343 PA_O_RESOLVE | PA_O_PORT_OK | PA_O_STREAM | PA_O_CONNECT);
Frédéric Lécailledba97072017-03-17 15:33:50 +01001344 if (!sk) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001345 ha_alert("'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg);
Frédéric Lécailledba97072017-03-17 15:33:50 +01001346 goto err;
1347 }
1348
Frédéric Lécailledba97072017-03-17 15:33:50 +01001349 newsrv->conn_src.tproxy_addr = *sk;
1350 newsrv->conn_src.opts |= CO_SRC_TPROXY_ADDR;
1351 }
1352 global.last_checks |= LSTCHK_NETADM;
1353 *cur_arg += 2;
1354 continue;
1355#else /* no TPROXY support */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001356 ha_alert("'usesrc' not allowed here because support for TPROXY was not compiled in.\n");
Frédéric Lécailledba97072017-03-17 15:33:50 +01001357 goto err;
1358#endif /* defined(CONFIG_HAP_TRANSPARENT) */
1359 } /* "usesrc" */
1360
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01001361 if (strcmp(args[*cur_arg], "interface") == 0) { /* specifically bind to this interface */
Frédéric Lécailledba97072017-03-17 15:33:50 +01001362#ifdef SO_BINDTODEVICE
1363 if (!*args[*cur_arg + 1]) {
Christopher Faulet767a84b2017-11-24 16:50:31 +01001364 ha_alert("'%s' : missing interface name.\n", args[0]);
Frédéric Lécailledba97072017-03-17 15:33:50 +01001365 goto err;
1366 }
1367 free(newsrv->conn_src.iface_name);
1368 newsrv->conn_src.iface_name = strdup(args[*cur_arg + 1]);
1369 newsrv->conn_src.iface_len = strlen(newsrv->conn_src.iface_name);
1370 global.last_checks |= LSTCHK_NETADM;
1371#else
Christopher Faulet767a84b2017-11-24 16:50:31 +01001372 ha_alert("'%s' : '%s' option not implemented.\n", args[0], args[*cur_arg]);
Frédéric Lécailledba97072017-03-17 15:33:50 +01001373 goto err;
1374#endif
1375 *cur_arg += 2;
1376 continue;
1377 }
1378 /* this keyword in not an option of "source" */
1379 break;
1380 } /* while */
1381
1382 return 0;
1383
1384 err:
1385 free(errmsg);
1386 return ERR_ALERT | ERR_FATAL;
1387}
1388
Frédéric Lécaillef9bc1d62017-03-10 15:50:49 +01001389/* Parse the "stick" server keyword */
1390static int srv_parse_stick(char **args, int *cur_arg,
1391 struct proxy *curproxy, struct server *newsrv, char **err)
1392{
1393 newsrv->flags &= ~SRV_F_NON_STICK;
1394 return 0;
1395}
1396
Frédéric Lécaille67e0e612017-03-14 15:21:31 +01001397/* Parse the "track" server keyword */
1398static int srv_parse_track(char **args, int *cur_arg,
1399 struct proxy *curproxy, struct server *newsrv, char **err)
1400{
1401 char *arg;
1402
1403 arg = args[*cur_arg + 1];
1404 if (!*arg) {
1405 memprintf(err, "'track' expects [<proxy>/]<server> as argument.\n");
1406 return ERR_ALERT | ERR_FATAL;
1407 }
1408
1409 free(newsrv->trackit);
1410 newsrv->trackit = strdup(arg);
1411
1412 return 0;
Alexander Liu2a54bb72019-05-22 19:44:48 +08001413}
1414
1415/* Parse the "socks4" server keyword */
1416static int srv_parse_socks4(char **args, int *cur_arg,
1417 struct proxy *curproxy, struct server *newsrv, char **err)
1418{
1419 char *errmsg;
1420 int port_low, port_high;
1421 struct sockaddr_storage *sk;
Alexander Liu2a54bb72019-05-22 19:44:48 +08001422
1423 errmsg = NULL;
1424
1425 if (!*args[*cur_arg + 1]) {
1426 memprintf(err, "'%s' expects <addr>:<port> as argument.\n", args[*cur_arg]);
1427 goto err;
1428 }
1429
1430 /* 'sk' is statically allocated (no need to be freed). */
Willy Tarreau65ec4e32020-09-16 19:17:08 +02001431 sk = str2sa_range(args[*cur_arg + 1], NULL, &port_low, &port_high, NULL, NULL,
1432 &errmsg, NULL, NULL,
1433 PA_O_RESOLVE | PA_O_PORT_OK | PA_O_PORT_MAND | PA_O_STREAM | PA_O_CONNECT);
Alexander Liu2a54bb72019-05-22 19:44:48 +08001434 if (!sk) {
1435 memprintf(err, "'%s %s' : %s\n", args[*cur_arg], args[*cur_arg + 1], errmsg);
1436 goto err;
1437 }
1438
Alexander Liu2a54bb72019-05-22 19:44:48 +08001439 newsrv->flags |= SRV_F_SOCKS4_PROXY;
1440 newsrv->socks4_addr = *sk;
1441
Alexander Liu2a54bb72019-05-22 19:44:48 +08001442 return 0;
1443
1444 err:
1445 free(errmsg);
1446 return ERR_ALERT | ERR_FATAL;
Frédéric Lécaille67e0e612017-03-14 15:21:31 +01001447}
1448
Frédéric Lécailledba97072017-03-17 15:33:50 +01001449
Willy Tarreau034c88c2017-01-23 23:36:45 +01001450/* parse the "tfo" server keyword */
1451static int srv_parse_tfo(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1452{
1453 newsrv->flags |= SRV_F_FASTOPEN;
1454 return 0;
1455}
1456
Amaury Denoyelle587b71e2021-03-10 16:36:02 +01001457/* parse the "usesrc" server keyword */
1458static int srv_parse_usesrc(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1459{
1460 memprintf(err, "'%s' only allowed after a '%s' statement.",
1461 "usesrc", "source");
1462 return ERR_ALERT | ERR_FATAL;
1463}
1464
1465/* parse the "weight" server keyword */
1466static int srv_parse_weight(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
1467{
1468 int w;
1469
1470 w = atol(args[*cur_arg + 1]);
1471 if (w < 0 || w > SRV_UWGHT_MAX) {
1472 memprintf(err, "weight of server %s is not within 0 and %d (%d).",
1473 newsrv->id, SRV_UWGHT_MAX, w);
1474 return ERR_ALERT | ERR_FATAL;
1475 }
1476 newsrv->uweight = newsrv->iweight = w;
1477
1478 return 0;
1479}
1480
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001481/* Shutdown all connections of a server. The caller must pass a termination
Willy Tarreaue7dff022015-04-03 01:14:29 +02001482 * code in <why>, which must be one of SF_ERR_* indicating the reason for the
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001483 * shutdown.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001484 *
1485 * Must be called with the server lock held.
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001486 */
Willy Tarreau87b09662015-04-03 00:22:06 +02001487void srv_shutdown_streams(struct server *srv, int why)
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001488{
Willy Tarreau751153e2021-02-17 13:33:24 +01001489 struct stream *stream;
1490 struct mt_list *elt1, elt2;
Willy Tarreaud4e78d82021-03-04 10:47:54 +01001491 int thr;
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001492
Willy Tarreaud4e78d82021-03-04 10:47:54 +01001493 for (thr = 0; thr < global.nbthread; thr++)
1494 mt_list_for_each_entry_safe(stream, &srv->per_thr[thr].streams, by_srv, elt1, elt2)
1495 if (stream->srv_conn == srv)
1496 stream_shutdown(stream, why);
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001497}
1498
1499/* Shutdown all connections of all backup servers of a proxy. The caller must
Willy Tarreaue7dff022015-04-03 01:14:29 +02001500 * pass a termination code in <why>, which must be one of SF_ERR_* indicating
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001501 * the reason for the shutdown.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001502 *
1503 * Must be called with the server lock held.
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001504 */
Willy Tarreau87b09662015-04-03 00:22:06 +02001505void srv_shutdown_backup_streams(struct proxy *px, int why)
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001506{
1507 struct server *srv;
1508
1509 for (srv = px->srv; srv != NULL; srv = srv->next)
1510 if (srv->flags & SRV_F_BACKUP)
Willy Tarreau87b09662015-04-03 00:22:06 +02001511 srv_shutdown_streams(srv, why);
Willy Tarreau4aac7db2014-05-16 11:48:10 +02001512}
1513
Willy Tarreaubda92272014-05-20 21:55:30 +02001514/* Appends some information to a message string related to a server going UP or
1515 * DOWN. If both <forced> and <reason> are null and the server tracks another
1516 * one, a "via" information will be provided to know where the status came from.
Emeric Brun5a133512017-10-19 14:42:30 +02001517 * If <check> is non-null, an entire string describing the check result will be
1518 * appended after a comma and a space (eg: to report some information from the
1519 * check that changed the state). In the other case, the string will be built
1520 * using the check results stored into the struct server if present.
1521 * If <xferred> is non-negative, some information about requeued sessions are
Willy Tarreaubda92272014-05-20 21:55:30 +02001522 * provided.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001523 *
1524 * Must be called with the server lock held.
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001525 */
Willy Tarreau83061a82018-07-13 11:56:34 +02001526void srv_append_status(struct buffer *msg, struct server *s,
1527 struct check *check, int xferred, int forced)
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001528{
Emeric Brun5a133512017-10-19 14:42:30 +02001529 short status = s->op_st_chg.status;
1530 short code = s->op_st_chg.code;
1531 long duration = s->op_st_chg.duration;
1532 char *desc = s->op_st_chg.reason;
1533
1534 if (check) {
1535 status = check->status;
1536 code = check->code;
1537 duration = check->duration;
1538 desc = check->desc;
1539 }
1540
1541 if (status != -1) {
1542 chunk_appendf(msg, ", reason: %s", get_check_status_description(status));
1543
1544 if (status >= HCHK_STATUS_L57DATA)
1545 chunk_appendf(msg, ", code: %d", code);
1546
1547 if (desc && *desc) {
Willy Tarreau83061a82018-07-13 11:56:34 +02001548 struct buffer src;
Emeric Brun5a133512017-10-19 14:42:30 +02001549
1550 chunk_appendf(msg, ", info: \"");
1551
1552 chunk_initlen(&src, desc, 0, strlen(desc));
1553 chunk_asciiencode(msg, &src, '"');
1554
1555 chunk_appendf(msg, "\"");
1556 }
1557
1558 if (duration >= 0)
1559 chunk_appendf(msg, ", check duration: %ldms", duration);
1560 }
1561 else if (desc && *desc) {
1562 chunk_appendf(msg, ", %s", desc);
1563 }
1564 else if (!forced && s->track) {
Willy Tarreaubda92272014-05-20 21:55:30 +02001565 chunk_appendf(msg, " via %s/%s", s->track->proxy->id, s->track->id);
Emeric Brun5a133512017-10-19 14:42:30 +02001566 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001567
1568 if (xferred >= 0) {
Emeric Brun52a91d32017-08-31 14:41:55 +02001569 if (s->next_state == SRV_ST_STOPPED)
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001570 chunk_appendf(msg, ". %d active and %d backup servers left.%s"
1571 " %d sessions active, %d requeued, %d remaining in queue",
1572 s->proxy->srv_act, s->proxy->srv_bck,
1573 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
Willy Tarreaua0570452021-06-18 09:30:30 +02001574 s->cur_sess, xferred, s->queue.length);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001575 else
1576 chunk_appendf(msg, ". %d active and %d backup servers online.%s"
1577 " %d sessions requeued, %d total in queue",
1578 s->proxy->srv_act, s->proxy->srv_bck,
1579 (s->proxy->srv_bck && !s->proxy->srv_act) ? " Running on backup." : "",
Willy Tarreaua0570452021-06-18 09:30:30 +02001580 xferred, s->queue.length);
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001581 }
1582}
1583
Emeric Brun5a133512017-10-19 14:42:30 +02001584/* Marks server <s> down, regardless of its checks' statuses. The server is
1585 * registered in a list to postpone the counting of the remaining servers on
1586 * the proxy and transfers queued streams whenever possible to other servers at
1587 * a sync point. Maintenance servers are ignored. It stores the <reason> if
1588 * non-null as the reason for going down or the available data from the check
1589 * struct to recompute this reason later.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001590 *
1591 * Must be called with the server lock held.
Willy Tarreaue7d1ef12014-05-20 22:25:12 +02001592 */
Emeric Brun5a133512017-10-19 14:42:30 +02001593void srv_set_stopped(struct server *s, const char *reason, struct check *check)
Willy Tarreaue7d1ef12014-05-20 22:25:12 +02001594{
1595 struct server *srv;
Willy Tarreaue7d1ef12014-05-20 22:25:12 +02001596
Emeric Brun64cc49c2017-10-03 14:46:45 +02001597 if ((s->cur_admin & SRV_ADMF_MAINT) || s->next_state == SRV_ST_STOPPED)
Willy Tarreaue7d1ef12014-05-20 22:25:12 +02001598 return;
1599
Emeric Brun52a91d32017-08-31 14:41:55 +02001600 s->next_state = SRV_ST_STOPPED;
Emeric Brun5a133512017-10-19 14:42:30 +02001601 *s->op_st_chg.reason = 0;
1602 s->op_st_chg.status = -1;
1603 if (reason) {
1604 strlcpy2(s->op_st_chg.reason, reason, sizeof(s->op_st_chg.reason));
1605 }
1606 else if (check) {
Willy Tarreau358847f2017-11-20 21:33:21 +01001607 strlcpy2(s->op_st_chg.reason, check->desc, sizeof(s->op_st_chg.reason));
Emeric Brun5a133512017-10-19 14:42:30 +02001608 s->op_st_chg.code = check->code;
1609 s->op_st_chg.status = check->status;
1610 s->op_st_chg.duration = check->duration;
1611 }
Willy Tarreaue7d1ef12014-05-20 22:25:12 +02001612
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001613 /* propagate changes */
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001614 srv_update_status(s);
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001615
Emeric Brun9f0b4582017-10-23 14:39:51 +02001616 for (srv = s->trackers; srv; srv = srv->tracknext) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001617 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
Emeric Brun5a133512017-10-19 14:42:30 +02001618 srv_set_stopped(srv, NULL, NULL);
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001619 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
Emeric Brun9f0b4582017-10-23 14:39:51 +02001620 }
Willy Tarreaue7d1ef12014-05-20 22:25:12 +02001621}
1622
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001623/* Marks server <s> up regardless of its checks' statuses and provided it isn't
Emeric Brun5a133512017-10-19 14:42:30 +02001624 * in maintenance. The server is registered in a list to postpone the counting
1625 * of the remaining servers on the proxy and tries to grab requests from the
1626 * proxy at a sync point. Maintenance servers are ignored. It stores the
1627 * <reason> if non-null as the reason for going down or the available data
1628 * from the check struct to recompute this reason later.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001629 *
1630 * Must be called with the server lock held.
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001631 */
Emeric Brun5a133512017-10-19 14:42:30 +02001632void srv_set_running(struct server *s, const char *reason, struct check *check)
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001633{
1634 struct server *srv;
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001635
Emeric Brun64cc49c2017-10-03 14:46:45 +02001636 if (s->cur_admin & SRV_ADMF_MAINT)
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001637 return;
1638
Emeric Brun52a91d32017-08-31 14:41:55 +02001639 if (s->next_state == SRV_ST_STARTING || s->next_state == SRV_ST_RUNNING)
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001640 return;
1641
Emeric Brun52a91d32017-08-31 14:41:55 +02001642 s->next_state = SRV_ST_STARTING;
Emeric Brun5a133512017-10-19 14:42:30 +02001643 *s->op_st_chg.reason = 0;
1644 s->op_st_chg.status = -1;
1645 if (reason) {
1646 strlcpy2(s->op_st_chg.reason, reason, sizeof(s->op_st_chg.reason));
1647 }
1648 else if (check) {
Willy Tarreau358847f2017-11-20 21:33:21 +01001649 strlcpy2(s->op_st_chg.reason, check->desc, sizeof(s->op_st_chg.reason));
Emeric Brun5a133512017-10-19 14:42:30 +02001650 s->op_st_chg.code = check->code;
1651 s->op_st_chg.status = check->status;
1652 s->op_st_chg.duration = check->duration;
1653 }
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001654
Emeric Brun64cc49c2017-10-03 14:46:45 +02001655 if (s->slowstart <= 0)
1656 s->next_state = SRV_ST_RUNNING;
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001657
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001658 /* propagate changes */
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001659 srv_update_status(s);
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001660
Emeric Brun9f0b4582017-10-23 14:39:51 +02001661 for (srv = s->trackers; srv; srv = srv->tracknext) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001662 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
Emeric Brun5a133512017-10-19 14:42:30 +02001663 srv_set_running(srv, NULL, NULL);
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001664 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
Emeric Brun9f0b4582017-10-23 14:39:51 +02001665 }
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001666}
1667
Willy Tarreau8eb77842014-05-21 13:54:57 +02001668/* Marks server <s> stopping regardless of its checks' statuses and provided it
Emeric Brun5a133512017-10-19 14:42:30 +02001669 * isn't in maintenance. The server is registered in a list to postpone the
1670 * counting of the remaining servers on the proxy and tries to grab requests
1671 * from the proxy. Maintenance servers are ignored. It stores the
1672 * <reason> if non-null as the reason for going down or the available data
1673 * from the check struct to recompute this reason later.
Willy Tarreau8eb77842014-05-21 13:54:57 +02001674 * up. Note that it makes use of the trash to build the log strings, so <reason>
1675 * must not be placed there.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001676 *
1677 * Must be called with the server lock held.
Willy Tarreau8eb77842014-05-21 13:54:57 +02001678 */
Emeric Brun5a133512017-10-19 14:42:30 +02001679void srv_set_stopping(struct server *s, const char *reason, struct check *check)
Willy Tarreau8eb77842014-05-21 13:54:57 +02001680{
1681 struct server *srv;
Willy Tarreau8eb77842014-05-21 13:54:57 +02001682
Emeric Brun64cc49c2017-10-03 14:46:45 +02001683 if (s->cur_admin & SRV_ADMF_MAINT)
Willy Tarreau8eb77842014-05-21 13:54:57 +02001684 return;
1685
Emeric Brun52a91d32017-08-31 14:41:55 +02001686 if (s->next_state == SRV_ST_STOPPING)
Willy Tarreau8eb77842014-05-21 13:54:57 +02001687 return;
1688
Emeric Brun52a91d32017-08-31 14:41:55 +02001689 s->next_state = SRV_ST_STOPPING;
Emeric Brun5a133512017-10-19 14:42:30 +02001690 *s->op_st_chg.reason = 0;
1691 s->op_st_chg.status = -1;
1692 if (reason) {
1693 strlcpy2(s->op_st_chg.reason, reason, sizeof(s->op_st_chg.reason));
1694 }
1695 else if (check) {
Willy Tarreau358847f2017-11-20 21:33:21 +01001696 strlcpy2(s->op_st_chg.reason, check->desc, sizeof(s->op_st_chg.reason));
Emeric Brun5a133512017-10-19 14:42:30 +02001697 s->op_st_chg.code = check->code;
1698 s->op_st_chg.status = check->status;
1699 s->op_st_chg.duration = check->duration;
1700 }
Willy Tarreau8eb77842014-05-21 13:54:57 +02001701
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001702 /* propagate changes */
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001703 srv_update_status(s);
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001704
Emeric Brun9f0b4582017-10-23 14:39:51 +02001705 for (srv = s->trackers; srv; srv = srv->tracknext) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001706 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
Emeric Brun5a133512017-10-19 14:42:30 +02001707 srv_set_stopping(srv, NULL, NULL);
Christopher Faulet8d01fd62018-01-24 21:49:41 +01001708 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
Emeric Brun9f0b4582017-10-23 14:39:51 +02001709 }
Willy Tarreau8eb77842014-05-21 13:54:57 +02001710}
Willy Tarreaudbd5e782014-05-20 22:46:35 +02001711
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001712/* Enables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
1713 * enforce either maint mode or drain mode. It is not allowed to set more than
1714 * one flag at once. The equivalent "inherited" flag is propagated to all
1715 * tracking servers. Maintenance mode disables health checks (but not agent
1716 * checks). When either the flag is already set or no flag is passed, nothing
Willy Tarreau8b428482016-11-07 15:53:43 +01001717 * is done. If <cause> is non-null, it will be displayed at the end of the log
1718 * lines to justify the state change.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001719 *
1720 * Must be called with the server lock held.
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001721 */
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02001722void srv_set_admin_flag(struct server *s, enum srv_admin mode, enum srv_adm_st_chg_cause cause)
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001723{
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001724 struct server *srv;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001725
1726 if (!mode)
1727 return;
1728
1729 /* stop going down as soon as we meet a server already in the same state */
Emeric Brun52a91d32017-08-31 14:41:55 +02001730 if (s->next_admin & mode)
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001731 return;
1732
Emeric Brun52a91d32017-08-31 14:41:55 +02001733 s->next_admin |= mode;
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02001734 s->adm_st_chg_cause = cause;
Emeric Brun64cc49c2017-10-03 14:46:45 +02001735
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001736 /* propagate changes */
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001737 srv_update_status(s);
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001738
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001739 /* stop going down if the equivalent flag was already present (forced or inherited) */
Emeric Brun52a91d32017-08-31 14:41:55 +02001740 if (((mode & SRV_ADMF_MAINT) && (s->next_admin & ~mode & SRV_ADMF_MAINT)) ||
1741 ((mode & SRV_ADMF_DRAIN) && (s->next_admin & ~mode & SRV_ADMF_DRAIN)))
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001742 return;
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001743
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001744 /* compute the inherited flag to propagate */
1745 if (mode & SRV_ADMF_MAINT)
1746 mode = SRV_ADMF_IMAINT;
1747 else if (mode & SRV_ADMF_DRAIN)
1748 mode = SRV_ADMF_IDRAIN;
1749
Emeric Brun9f0b4582017-10-23 14:39:51 +02001750 for (srv = s->trackers; srv; srv = srv->tracknext) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001751 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
Willy Tarreau8b428482016-11-07 15:53:43 +01001752 srv_set_admin_flag(srv, mode, cause);
Christopher Faulet8d01fd62018-01-24 21:49:41 +01001753 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
Emeric Brun9f0b4582017-10-23 14:39:51 +02001754 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001755}
1756
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001757/* Disables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
1758 * stop enforcing either maint mode or drain mode. It is not allowed to set more
1759 * than one flag at once. The equivalent "inherited" flag is propagated to all
1760 * tracking servers. Leaving maintenance mode re-enables health checks. When
1761 * either the flag is already cleared or no flag is passed, nothing is done.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001762 *
1763 * Must be called with the server lock held.
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001764 */
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001765void srv_clr_admin_flag(struct server *s, enum srv_admin mode)
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001766{
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001767 struct server *srv;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001768
1769 if (!mode)
1770 return;
1771
1772 /* stop going down as soon as we see the flag is not there anymore */
Emeric Brun52a91d32017-08-31 14:41:55 +02001773 if (!(s->next_admin & mode))
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001774 return;
1775
Emeric Brun52a91d32017-08-31 14:41:55 +02001776 s->next_admin &= ~mode;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001777
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001778 /* propagate changes */
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001779 srv_update_status(s);
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001780
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001781 /* stop going down if the equivalent flag is still present (forced or inherited) */
Emeric Brun52a91d32017-08-31 14:41:55 +02001782 if (((mode & SRV_ADMF_MAINT) && (s->next_admin & SRV_ADMF_MAINT)) ||
1783 ((mode & SRV_ADMF_DRAIN) && (s->next_admin & SRV_ADMF_DRAIN)))
Willy Tarreaueeba36b2018-08-21 08:22:26 +02001784 return;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001785
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001786 if (mode & SRV_ADMF_MAINT)
1787 mode = SRV_ADMF_IMAINT;
1788 else if (mode & SRV_ADMF_DRAIN)
1789 mode = SRV_ADMF_IDRAIN;
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001790
Emeric Brun9f0b4582017-10-23 14:39:51 +02001791 for (srv = s->trackers; srv; srv = srv->tracknext) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001792 HA_SPIN_LOCK(SERVER_LOCK, &srv->lock);
Willy Tarreaubfc7b7a2014-05-22 16:14:34 +02001793 srv_clr_admin_flag(srv, mode);
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001794 HA_SPIN_UNLOCK(SERVER_LOCK, &srv->lock);
Emeric Brun9f0b4582017-10-23 14:39:51 +02001795 }
Willy Tarreaua0066dd2014-05-16 11:25:16 +02001796}
1797
Willy Tarreau757478e2016-11-03 19:22:19 +01001798/* principle: propagate maint and drain to tracking servers. This is useful
1799 * upon startup so that inherited states are correct.
1800 */
1801static void srv_propagate_admin_state(struct server *srv)
1802{
1803 struct server *srv2;
1804
1805 if (!srv->trackers)
1806 return;
1807
1808 for (srv2 = srv->trackers; srv2; srv2 = srv2->tracknext) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001809 HA_SPIN_LOCK(SERVER_LOCK, &srv2->lock);
Emeric Brun52a91d32017-08-31 14:41:55 +02001810 if (srv->next_admin & (SRV_ADMF_MAINT | SRV_ADMF_CMAINT))
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02001811 srv_set_admin_flag(srv2, SRV_ADMF_IMAINT, SRV_ADM_STCHGC_NONE);
Willy Tarreau757478e2016-11-03 19:22:19 +01001812
Emeric Brun52a91d32017-08-31 14:41:55 +02001813 if (srv->next_admin & SRV_ADMF_DRAIN)
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02001814 srv_set_admin_flag(srv2, SRV_ADMF_IDRAIN, SRV_ADM_STCHGC_NONE);
Christopher Faulet2a944ee2017-11-07 10:42:54 +01001815 HA_SPIN_UNLOCK(SERVER_LOCK, &srv2->lock);
Willy Tarreau757478e2016-11-03 19:22:19 +01001816 }
1817}
1818
1819/* Compute and propagate the admin states for all servers in proxy <px>.
1820 * Only servers *not* tracking another one are considered, because other
1821 * ones will be handled when the server they track is visited.
1822 */
1823void srv_compute_all_admin_states(struct proxy *px)
1824{
1825 struct server *srv;
1826
1827 for (srv = px->srv; srv; srv = srv->next) {
1828 if (srv->track)
1829 continue;
1830 srv_propagate_admin_state(srv);
1831 }
1832}
1833
Willy Tarreaudff55432012-10-10 17:51:05 +02001834/* Note: must not be declared <const> as its list will be overwritten.
1835 * Please take care of keeping this list alphabetically sorted, doing so helps
1836 * all code contributors.
1837 * Optional keywords are also declared with a NULL ->parse() function so that
1838 * the config parser can report an appropriate error when a known keyword was
1839 * not enabled.
Frédéric Lécailledfacd692017-04-16 17:14:14 +02001840 * Note: -1 as ->skip value means that the number of arguments are variable.
Willy Tarreaudff55432012-10-10 17:51:05 +02001841 */
1842static struct srv_kw_list srv_kws = { "ALL", { }, {
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001843 { "backup", srv_parse_backup, 0, 1, 1 }, /* Flag as backup server */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001844 { "cookie", srv_parse_cookie, 1, 1, 0 }, /* Assign a cookie to the server */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001845 { "disabled", srv_parse_disabled, 0, 1, 1 }, /* Start the server in 'disabled' state */
1846 { "enabled", srv_parse_enabled, 0, 1, 1 }, /* Start the server in 'enabled' state */
Amaury Denoyelle725f8d22021-09-20 15:16:12 +02001847 { "error-limit", srv_parse_error_limit, 1, 1, 1 }, /* Configure the consecutive count of check failures to consider a server on error */
Amaury Denoyellef9d59572021-10-18 14:40:29 +02001848 { "ws", srv_parse_ws, 1, 1, 1 }, /* websocket protocol */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001849 { "id", srv_parse_id, 1, 0, 1 }, /* set id# of server */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001850 { "init-addr", srv_parse_init_addr, 1, 1, 0 }, /* */
1851 { "log-proto", srv_parse_log_proto, 1, 1, 0 }, /* Set the protocol for event messages, only relevant in a ring section */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001852 { "maxconn", srv_parse_maxconn, 1, 1, 1 }, /* Set the max number of concurrent connection */
1853 { "maxqueue", srv_parse_maxqueue, 1, 1, 1 }, /* Set the max number of connection to put in queue */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001854 { "max-reuse", srv_parse_max_reuse, 1, 1, 0 }, /* Set the max number of requests on a connection, -1 means unlimited */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001855 { "minconn", srv_parse_minconn, 1, 1, 1 }, /* Enable a dynamic maxconn limit */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001856 { "namespace", srv_parse_namespace, 1, 1, 0 }, /* Namespace the server socket belongs to (if supported) */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001857 { "no-backup", srv_parse_no_backup, 0, 1, 1 }, /* Flag as non-backup server */
1858 { "no-send-proxy", srv_parse_no_send_proxy, 0, 1, 1 }, /* Disable use of PROXY V1 protocol */
1859 { "no-send-proxy-v2", srv_parse_no_send_proxy_v2, 0, 1, 1 }, /* Disable use of PROXY V2 protocol */
1860 { "no-tfo", srv_parse_no_tfo, 0, 1, 1 }, /* Disable use of TCP Fast Open */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001861 { "non-stick", srv_parse_non_stick, 0, 1, 0 }, /* Disable stick-table persistence */
Amaury Denoyelle725f8d22021-09-20 15:16:12 +02001862 { "observe", srv_parse_observe, 1, 1, 1 }, /* Enables health adjusting based on observing communication with the server */
1863 { "on-error", srv_parse_on_error, 1, 1, 1 }, /* Configure the action on check failure */
1864 { "on-marked-down", srv_parse_on_marked_down, 1, 1, 1 }, /* Configure the action when a server is marked down */
1865 { "on-marked-up", srv_parse_on_marked_up, 1, 1, 1 }, /* Configure the action when a server is marked up */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001866 { "pool-low-conn", srv_parse_pool_low_conn, 1, 1, 1 }, /* Set the min number of orphan idle connecbefore being allowed to pick from other threads */
1867 { "pool-max-conn", srv_parse_pool_max_conn, 1, 1, 1 }, /* Set the max number of orphan idle connections, -1 means unlimited */
1868 { "pool-purge-delay", srv_parse_pool_purge_delay, 1, 1, 1 }, /* Set the time before we destroy orphan idle connections, defaults to 1s */
Amaury Denoyelle30467232021-03-12 18:03:27 +01001869 { "proto", srv_parse_proto, 1, 1, 1 }, /* Set the proto to use for all outgoing connections */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001870 { "proxy-v2-options", srv_parse_proxy_v2_options, 1, 1, 1 }, /* options for send-proxy-v2 */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001871 { "redir", srv_parse_redir, 1, 1, 0 }, /* Enable redirection mode */
Ilya Shipitsinba13f162021-03-19 22:21:44 +05001872 { "resolve-net", srv_parse_resolve_net, 1, 1, 0 }, /* Set the preferred network range for name resolution */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001873 { "resolve-opts", srv_parse_resolve_opts, 1, 1, 0 }, /* Set options for name resolution */
Ilya Shipitsinba13f162021-03-19 22:21:44 +05001874 { "resolve-prefer", srv_parse_resolve_prefer, 1, 1, 0 }, /* Set the preferred family for name resolution */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001875 { "resolvers", srv_parse_resolvers, 1, 1, 0 }, /* Configure the resolver to use for name resolution */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001876 { "send-proxy", srv_parse_send_proxy, 0, 1, 1 }, /* Enforce use of PROXY V1 protocol */
1877 { "send-proxy-v2", srv_parse_send_proxy_v2, 0, 1, 1 }, /* Enforce use of PROXY V2 protocol */
Frédéric Lécaille36d15652022-10-17 14:58:19 +02001878 { "shard", srv_parse_shard, 1, 1, 1 }, /* Server shard (only in peers protocol context) */
Amaury Denoyellecd8a6f22021-09-21 11:51:54 +02001879 { "slowstart", srv_parse_slowstart, 1, 1, 1 }, /* Set the warm-up timer for a previously failed server */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001880 { "source", srv_parse_source, -1, 1, 1 }, /* Set the source address to be used to connect to the server */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001881 { "stick", srv_parse_stick, 0, 1, 0 }, /* Enable stick-table persistence */
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001882 { "tfo", srv_parse_tfo, 0, 1, 1 }, /* enable TCP Fast Open of server */
Amaury Denoyelle56eb8ed2021-07-13 10:36:03 +02001883 { "track", srv_parse_track, 1, 1, 1 }, /* Set the current state of the server, tracking another one */
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01001884 { "socks4", srv_parse_socks4, 1, 1, 0 }, /* Set the socks4 proxy of the server*/
Amaury Denoyellefc465a52021-03-09 17:36:23 +01001885 { "usesrc", srv_parse_usesrc, 0, 1, 1 }, /* safe-guard against usesrc without preceding <source> keyword */
1886 { "weight", srv_parse_weight, 1, 1, 1 }, /* Set the load-balancing weight */
Willy Tarreaudff55432012-10-10 17:51:05 +02001887 { NULL, NULL, 0 },
1888}};
1889
Willy Tarreau0108d902018-11-25 19:14:37 +01001890INITCALL1(STG_REGISTER, srv_register_keywords, &srv_kws);
Willy Tarreaudff55432012-10-10 17:51:05 +02001891
Willy Tarreau004e0452013-11-21 11:22:01 +01001892/* Recomputes the server's eweight based on its state, uweight, the current time,
Ilya Shipitsinc02a23f2020-05-06 00:53:22 +05001893 * and the proxy's algorithm. To be used after updating sv->uweight. The warmup
Willy Tarreau3ff577e2018-08-02 11:48:52 +02001894 * state is automatically disabled if the time is elapsed. If <must_update> is
1895 * not zero, the update will be propagated immediately.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001896 *
1897 * Must be called with the server lock held.
Willy Tarreau004e0452013-11-21 11:22:01 +01001898 */
Willy Tarreau3ff577e2018-08-02 11:48:52 +02001899void server_recalc_eweight(struct server *sv, int must_update)
Willy Tarreau004e0452013-11-21 11:22:01 +01001900{
1901 struct proxy *px = sv->proxy;
1902 unsigned w;
1903
1904 if (now.tv_sec < sv->last_change || now.tv_sec >= sv->last_change + sv->slowstart) {
1905 /* go to full throttle if the slowstart interval is reached */
Emeric Brun52a91d32017-08-31 14:41:55 +02001906 if (sv->next_state == SRV_ST_STARTING)
1907 sv->next_state = SRV_ST_RUNNING;
Willy Tarreau004e0452013-11-21 11:22:01 +01001908 }
1909
1910 /* We must take care of not pushing the server to full throttle during slow starts.
1911 * It must also start immediately, at least at the minimal step when leaving maintenance.
1912 */
Emeric Brun52a91d32017-08-31 14:41:55 +02001913 if ((sv->next_state == SRV_ST_STARTING) && (px->lbprm.algo & BE_LB_PROP_DYN))
Willy Tarreau004e0452013-11-21 11:22:01 +01001914 w = (px->lbprm.wdiv * (now.tv_sec - sv->last_change) + sv->slowstart) / sv->slowstart;
1915 else
1916 w = px->lbprm.wdiv;
1917
Emeric Brun52a91d32017-08-31 14:41:55 +02001918 sv->next_eweight = (sv->uweight * w + px->lbprm.wmult - 1) / px->lbprm.wmult;
Willy Tarreau004e0452013-11-21 11:22:01 +01001919
Willy Tarreau3ff577e2018-08-02 11:48:52 +02001920 /* propagate changes only if needed (i.e. not recursively) */
Willy Tarreau49725a02018-08-21 19:54:09 +02001921 if (must_update)
Willy Tarreau3ff577e2018-08-02 11:48:52 +02001922 srv_update_status(sv);
Willy Tarreau004e0452013-11-21 11:22:01 +01001923}
1924
Willy Tarreaubaaee002006-06-26 02:48:02 +02001925/*
Simon Horman7d09b9a2013-02-12 10:45:51 +09001926 * Parses weight_str and configures sv accordingly.
1927 * Returns NULL on success, error message string otherwise.
Willy Tarreau46b7f532018-08-21 11:54:26 +02001928 *
1929 * Must be called with the server lock held.
Simon Horman7d09b9a2013-02-12 10:45:51 +09001930 */
1931const char *server_parse_weight_change_request(struct server *sv,
1932 const char *weight_str)
1933{
1934 struct proxy *px;
Simon Hormanb796afa2013-02-12 10:45:53 +09001935 long int w;
1936 char *end;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001937
1938 px = sv->proxy;
1939
1940 /* if the weight is terminated with '%', it is set relative to
1941 * the initial weight, otherwise it is absolute.
1942 */
1943 if (!*weight_str)
1944 return "Require <weight> or <weight%>.\n";
1945
Simon Hormanb796afa2013-02-12 10:45:53 +09001946 w = strtol(weight_str, &end, 10);
1947 if (end == weight_str)
1948 return "Empty weight string empty or preceded by garbage";
1949 else if (end[0] == '%' && end[1] == '\0') {
Simon Horman58b5d292013-02-12 10:45:52 +09001950 if (w < 0)
Simon Horman7d09b9a2013-02-12 10:45:51 +09001951 return "Relative weight must be positive.\n";
Simon Horman58b5d292013-02-12 10:45:52 +09001952 /* Avoid integer overflow */
1953 if (w > 25600)
1954 w = 25600;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001955 w = sv->iweight * w / 100;
Simon Horman58b5d292013-02-12 10:45:52 +09001956 if (w > 256)
1957 w = 256;
Simon Horman7d09b9a2013-02-12 10:45:51 +09001958 }
1959 else if (w < 0 || w > 256)
1960 return "Absolute weight can only be between 0 and 256 inclusive.\n";
Simon Hormanb796afa2013-02-12 10:45:53 +09001961 else if (end[0] != '\0')
1962 return "Trailing garbage in weight string";
Simon Horman7d09b9a2013-02-12 10:45:51 +09001963
1964 if (w && w != sv->iweight && !(px->lbprm.algo & BE_LB_PROP_DYN))
1965 return "Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.\n";
1966
1967 sv->uweight = w;
Willy Tarreau3ff577e2018-08-02 11:48:52 +02001968 server_recalc_eweight(sv, 1);
Simon Horman7d09b9a2013-02-12 10:45:51 +09001969
1970 return NULL;
1971}
1972
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001973/*
Thierry Fournier09a91782016-02-24 08:25:39 +01001974 * Parses <addr_str> and configures <sv> accordingly. <from> precise
1975 * the source of the change in the associated message log.
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001976 * Returns:
1977 * - error string on error
1978 * - NULL on success
Willy Tarreau46b7f532018-08-21 11:54:26 +02001979 *
1980 * Must be called with the server lock held.
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001981 */
1982const char *server_parse_addr_change_request(struct server *sv,
Thierry Fournier09a91782016-02-24 08:25:39 +01001983 const char *addr_str, const char *updater)
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001984{
1985 unsigned char ip[INET6_ADDRSTRLEN];
1986
1987 if (inet_pton(AF_INET6, addr_str, ip)) {
Christopher Faulet69beaa92021-02-16 12:07:47 +01001988 srv_update_addr(sv, ip, AF_INET6, updater);
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001989 return NULL;
1990 }
1991 if (inet_pton(AF_INET, addr_str, ip)) {
Christopher Faulet69beaa92021-02-16 12:07:47 +01001992 srv_update_addr(sv, ip, AF_INET, updater);
Baptiste Assmann3d8f8312015-04-13 22:54:33 +02001993 return NULL;
1994 }
1995
1996 return "Could not understand IP address format.\n";
1997}
1998
Willy Tarreau46b7f532018-08-21 11:54:26 +02001999/*
2000 * Must be called with the server lock held.
2001 */
Nenad Merdanovic174dd372016-04-24 23:10:06 +02002002const char *server_parse_maxconn_change_request(struct server *sv,
2003 const char *maxconn_str)
2004{
2005 long int v;
2006 char *end;
2007
2008 if (!*maxconn_str)
2009 return "Require <maxconn>.\n";
2010
2011 v = strtol(maxconn_str, &end, 10);
2012 if (end == maxconn_str)
2013 return "maxconn string empty or preceded by garbage";
2014 else if (end[0] != '\0')
2015 return "Trailing garbage in maxconn string";
2016
2017 if (sv->maxconn == sv->minconn) { // static maxconn
2018 sv->maxconn = sv->minconn = v;
2019 } else { // dynamic maxconn
2020 sv->maxconn = v;
2021 }
2022
2023 if (may_dequeue_tasks(sv, sv->proxy))
Willy Tarreau9ab78292021-06-22 18:47:51 +02002024 process_srv_queue(sv);
Nenad Merdanovic174dd372016-04-24 23:10:06 +02002025
2026 return NULL;
2027}
2028
Frédéric Lécaille759ea982017-03-30 17:32:36 +02002029static struct sample_expr *srv_sni_sample_parse_expr(struct server *srv, struct proxy *px,
2030 const char *file, int linenum, char **err)
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002031{
2032 int idx;
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002033 const char *args[] = {
Frédéric Lécaille759ea982017-03-30 17:32:36 +02002034 srv->sni_expr,
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002035 NULL,
2036 };
2037
2038 idx = 0;
Olivier Houchard7d8e6882017-04-20 18:21:17 +02002039 px->conf.args.ctx = ARGC_SRV;
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002040
Willy Tarreaue3b57bf2020-02-14 16:50:14 +01002041 return sample_parse_expr((char **)args, &idx, file, linenum, err, &px->conf.args, NULL);
Frédéric Lécaille759ea982017-03-30 17:32:36 +02002042}
2043
William Lallemand0d058672022-03-16 15:44:42 +01002044int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err)
Frédéric Lécaille759ea982017-03-30 17:32:36 +02002045{
2046 struct sample_expr *expr;
2047
2048 expr = srv_sni_sample_parse_expr(newsrv, px, px->conf.file, px->conf.line, err);
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002049 if (!expr) {
2050 memprintf(err, "error detected while parsing sni expression : %s", *err);
2051 return ERR_ALERT | ERR_FATAL;
2052 }
2053
2054 if (!(expr->fetch->val & SMP_VAL_BE_SRV_CON)) {
2055 memprintf(err, "error detected while parsing sni expression : "
2056 " fetch method '%s' extracts information from '%s', "
Amaury Denoyellec008a632021-05-28 11:01:22 +02002057 "none of which is available here.",
Frédéric Lécaille759ea982017-03-30 17:32:36 +02002058 newsrv->sni_expr, sample_src_names(expr->fetch->use));
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002059 return ERR_ALERT | ERR_FATAL;
2060 }
2061
2062 px->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
2063 release_sample_expr(newsrv->ssl_ctx.sni);
2064 newsrv->ssl_ctx.sni = expr;
2065
2066 return 0;
2067}
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002068
Gaetan Rivet10c4b4a2020-02-11 11:42:38 +01002069static void display_parser_err(const char *file, int linenum, char **args, int cur_arg, int err_code, char **err)
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002070{
Gaetan Rivet10c4b4a2020-02-11 11:42:38 +01002071 char *msg = "error encountered while processing ";
2072 char *quote = "'";
2073 char *token = args[cur_arg];
2074
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002075 if (err && *err) {
2076 indent_msg(err, 2);
Gaetan Rivet10c4b4a2020-02-11 11:42:38 +01002077 msg = *err;
2078 quote = "";
2079 token = "";
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002080 }
Gaetan Rivet10c4b4a2020-02-11 11:42:38 +01002081
2082 if (err_code & ERR_WARN && !(err_code & ERR_ALERT))
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02002083 ha_warning("%s%s%s%s.\n", msg, quote, token, quote);
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002084 else
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02002085 ha_alert("%s%s%s%s.\n", msg, quote, token, quote);
Frédéric Lécaille9a146de2017-03-20 14:54:41 +01002086}
2087
Christopher Faulet0b365e32022-08-03 11:21:14 +02002088static void srv_conn_src_sport_range_cpy(struct server *srv, const struct server *src)
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002089{
2090 int range_sz;
2091
2092 range_sz = src->conn_src.sport_range->size;
2093 if (range_sz > 0) {
2094 srv->conn_src.sport_range = port_range_alloc_range(range_sz);
2095 if (srv->conn_src.sport_range != NULL) {
2096 int i;
2097
2098 for (i = 0; i < range_sz; i++) {
2099 srv->conn_src.sport_range->ports[i] =
2100 src->conn_src.sport_range->ports[i];
2101 }
2102 }
2103 }
2104}
2105
2106/*
2107 * Copy <src> server connection source settings to <srv> server everything needed.
2108 */
Christopher Faulet0b365e32022-08-03 11:21:14 +02002109static void srv_conn_src_cpy(struct server *srv, const struct server *src)
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002110{
2111 srv->conn_src.opts = src->conn_src.opts;
2112 srv->conn_src.source_addr = src->conn_src.source_addr;
2113
2114 /* Source port range copy. */
2115 if (src->conn_src.sport_range != NULL)
2116 srv_conn_src_sport_range_cpy(srv, src);
2117
2118#ifdef CONFIG_HAP_TRANSPARENT
2119 if (src->conn_src.bind_hdr_name != NULL) {
2120 srv->conn_src.bind_hdr_name = strdup(src->conn_src.bind_hdr_name);
2121 srv->conn_src.bind_hdr_len = strlen(src->conn_src.bind_hdr_name);
2122 }
2123 srv->conn_src.bind_hdr_occ = src->conn_src.bind_hdr_occ;
2124 srv->conn_src.tproxy_addr = src->conn_src.tproxy_addr;
2125#endif
2126 if (src->conn_src.iface_name != NULL)
2127 srv->conn_src.iface_name = strdup(src->conn_src.iface_name);
2128}
2129
2130/*
2131 * Copy <src> server SSL settings to <srv> server allocating
2132 * everything needed.
2133 */
2134#if defined(USE_OPENSSL)
Christopher Faulet0b365e32022-08-03 11:21:14 +02002135static void srv_ssl_settings_cpy(struct server *srv, const struct server *src)
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002136{
Christopher Faulet4ab26792021-12-01 09:50:41 +01002137 /* <src> is the current proxy's default server and SSL is enabled */
William Lallemand2c776f12021-12-28 18:47:17 +01002138 BUG_ON(src->ssl_ctx.ctx != NULL); /* the SSL_CTX must never be initialized in a default-server */
2139
Christopher Faulet4ab26792021-12-01 09:50:41 +01002140 if (src == &srv->proxy->defsrv && src->use_ssl == 1)
2141 srv->flags |= SRV_F_DEFSRV_USE_SSL;
2142
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002143 if (src->ssl_ctx.ca_file != NULL)
2144 srv->ssl_ctx.ca_file = strdup(src->ssl_ctx.ca_file);
2145 if (src->ssl_ctx.crl_file != NULL)
2146 srv->ssl_ctx.crl_file = strdup(src->ssl_ctx.crl_file);
William Lallemand2c776f12021-12-28 18:47:17 +01002147 if (src->ssl_ctx.client_crt != NULL)
2148 srv->ssl_ctx.client_crt = strdup(src->ssl_ctx.client_crt);
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002149
2150 srv->ssl_ctx.verify = src->ssl_ctx.verify;
2151
Remi Tricot-Le Breton0498fa42021-07-13 18:28:22 +02002152
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002153 if (src->ssl_ctx.verify_host != NULL)
2154 srv->ssl_ctx.verify_host = strdup(src->ssl_ctx.verify_host);
2155 if (src->ssl_ctx.ciphers != NULL)
2156 srv->ssl_ctx.ciphers = strdup(src->ssl_ctx.ciphers);
Jerome Magnin2e8d52f2020-04-22 11:40:18 +02002157 if (src->ssl_ctx.options)
2158 srv->ssl_ctx.options = src->ssl_ctx.options;
2159 if (src->ssl_ctx.methods.flags)
2160 srv->ssl_ctx.methods.flags = src->ssl_ctx.methods.flags;
2161 if (src->ssl_ctx.methods.min)
2162 srv->ssl_ctx.methods.min = src->ssl_ctx.methods.min;
2163 if (src->ssl_ctx.methods.max)
2164 srv->ssl_ctx.methods.max = src->ssl_ctx.methods.max;
2165
Dirkjan Bussink415150f2018-09-14 11:14:21 +02002166 if (src->ssl_ctx.ciphersuites != NULL)
2167 srv->ssl_ctx.ciphersuites = strdup(src->ssl_ctx.ciphersuites);
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002168 if (src->sni_expr != NULL)
2169 srv->sni_expr = strdup(src->sni_expr);
Olivier Houchardc7566002018-11-20 23:33:50 +01002170
Olivier Houchardc7566002018-11-20 23:33:50 +01002171 if (src->ssl_ctx.alpn_str) {
2172 srv->ssl_ctx.alpn_str = malloc(src->ssl_ctx.alpn_len);
2173 if (srv->ssl_ctx.alpn_str) {
2174 memcpy(srv->ssl_ctx.alpn_str, src->ssl_ctx.alpn_str,
2175 src->ssl_ctx.alpn_len);
2176 srv->ssl_ctx.alpn_len = src->ssl_ctx.alpn_len;
2177 }
2178 }
Willy Tarreau80527bc2021-10-06 14:48:37 +02002179
Olivier Houchardc7566002018-11-20 23:33:50 +01002180 if (src->ssl_ctx.npn_str) {
2181 srv->ssl_ctx.npn_str = malloc(src->ssl_ctx.npn_len);
2182 if (srv->ssl_ctx.npn_str) {
2183 memcpy(srv->ssl_ctx.npn_str, src->ssl_ctx.npn_str,
2184 src->ssl_ctx.npn_len);
2185 srv->ssl_ctx.npn_len = src->ssl_ctx.npn_len;
2186 }
2187 }
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002188}
Willy Tarreaua8a72c62021-10-06 11:48:34 +02002189
2190/* Activate ssl on server <s>.
2191 * do nothing if there is no change to apply
2192 *
2193 * Must be called with the server lock held.
2194 */
2195void srv_set_ssl(struct server *s, int use_ssl)
2196{
2197 if (s->use_ssl == use_ssl)
2198 return;
2199
2200 s->use_ssl = use_ssl;
2201 if (s->use_ssl)
2202 s->xprt = xprt_get(XPRT_SSL);
2203 else
William Dauchya087f872022-01-06 16:57:15 +01002204 s->xprt = xprt_get(XPRT_RAW);
Willy Tarreaua8a72c62021-10-06 11:48:34 +02002205}
2206
2207#endif /* USE_OPENSSL */
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002208
2209/*
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002210 * Prepare <srv> for hostname resolution.
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002211 * May be safely called with a default server as <src> argument (without hostname).
Frédéric Lécailleb418c122017-04-26 11:24:02 +02002212 * Returns -1 in case of any allocation failure, 0 if not.
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002213 */
Christopher Faulet69beaa92021-02-16 12:07:47 +01002214int srv_prepare_for_resolution(struct server *srv, const char *hostname)
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002215{
Christopher Faulet67957bd2017-09-27 11:00:59 +02002216 char *hostname_dn;
2217 int hostname_len, hostname_dn_len;
2218
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002219 if (!hostname)
Frédéric Lécailleb418c122017-04-26 11:24:02 +02002220 return 0;
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002221
Christopher Faulet67957bd2017-09-27 11:00:59 +02002222 hostname_len = strlen(hostname);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002223 hostname_dn = trash.area;
Willy Tarreaubf9498a2021-10-14 07:49:49 +02002224 hostname_dn_len = resolv_str_to_dn_label(hostname, hostname_len,
Emeric Brund30e9a12020-12-23 18:49:16 +01002225 hostname_dn, trash.size);
Christopher Faulet67957bd2017-09-27 11:00:59 +02002226 if (hostname_dn_len == -1)
2227 goto err;
Baptiste Assmann81ed1a02017-05-03 10:11:44 +02002228
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002229
Christopher Faulet67957bd2017-09-27 11:00:59 +02002230 free(srv->hostname);
2231 free(srv->hostname_dn);
2232 srv->hostname = strdup(hostname);
2233 srv->hostname_dn = strdup(hostname_dn);
2234 srv->hostname_dn_len = hostname_dn_len;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002235 if (!srv->hostname || !srv->hostname_dn)
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002236 goto err;
2237
Frédéric Lécailleb418c122017-04-26 11:24:02 +02002238 return 0;
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002239
2240 err:
Willy Tarreau61cfdf42021-02-20 10:46:51 +01002241 ha_free(&srv->hostname);
2242 ha_free(&srv->hostname_dn);
Frédéric Lécailleb418c122017-04-26 11:24:02 +02002243 return -1;
2244}
2245
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002246/*
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002247 * Copy <src> server settings to <srv> server allocating
2248 * everything needed.
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002249 * This function is not supposed to be called at any time, but only
2250 * during server settings parsing or during server allocations from
2251 * a server template, and just after having calloc()'ed a new server.
2252 * So, <src> may only be a default server (when parsing server settings)
2253 * or a server template (during server allocations from a server template).
2254 * <srv_tmpl> distinguishes these two cases (must be 1 if <srv> is a template,
2255 * 0 if not).
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002256 */
Christopher Fauletb32cb9b2022-08-03 11:28:08 +02002257void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl)
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002258{
2259 /* Connection source settings copy */
2260 srv_conn_src_cpy(srv, src);
2261
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002262 if (srv_tmpl) {
2263 srv->addr = src->addr;
2264 srv->svc_port = src->svc_port;
2265 }
2266
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002267 srv->pp_opts = src->pp_opts;
2268 if (src->rdr_pfx != NULL) {
2269 srv->rdr_pfx = strdup(src->rdr_pfx);
2270 srv->rdr_len = src->rdr_len;
2271 }
2272 if (src->cookie != NULL) {
2273 srv->cookie = strdup(src->cookie);
2274 srv->cklen = src->cklen;
2275 }
2276 srv->use_ssl = src->use_ssl;
Willy Tarreau24441082019-12-11 15:43:45 +01002277 srv->check.addr = src->check.addr;
2278 srv->agent.addr = src->agent.addr;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002279 srv->check.use_ssl = src->check.use_ssl;
2280 srv->check.port = src->check.port;
Olivier Houchard21944012018-12-21 19:42:01 +01002281 srv->check.sni = src->check.sni;
Olivier Houchard92150142018-12-21 19:47:01 +01002282 srv->check.alpn_str = src->check.alpn_str;
Ilya Shipitsin0c50b1e2019-04-30 21:21:28 +05002283 srv->check.alpn_len = src->check.alpn_len;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002284 /* Note: 'flags' field has potentially been already initialized. */
2285 srv->flags |= src->flags;
2286 srv->do_check = src->do_check;
2287 srv->do_agent = src->do_agent;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002288 srv->check.inter = src->check.inter;
2289 srv->check.fastinter = src->check.fastinter;
2290 srv->check.downinter = src->check.downinter;
2291 srv->agent.use_ssl = src->agent.use_ssl;
2292 srv->agent.port = src->agent.port;
Christopher Faulet0ae3d1d2020-04-06 17:54:24 +02002293
2294 if (src->agent.tcpcheck_rules) {
2295 srv->agent.tcpcheck_rules = calloc(1, sizeof(*srv->agent.tcpcheck_rules));
2296 if (srv->agent.tcpcheck_rules) {
2297 srv->agent.tcpcheck_rules->flags = src->agent.tcpcheck_rules->flags;
2298 srv->agent.tcpcheck_rules->list = src->agent.tcpcheck_rules->list;
2299 LIST_INIT(&srv->agent.tcpcheck_rules->preset_vars);
2300 dup_tcpcheck_vars(&srv->agent.tcpcheck_rules->preset_vars,
2301 &src->agent.tcpcheck_rules->preset_vars);
2302 }
2303 }
2304
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002305 srv->agent.inter = src->agent.inter;
2306 srv->agent.fastinter = src->agent.fastinter;
2307 srv->agent.downinter = src->agent.downinter;
2308 srv->maxqueue = src->maxqueue;
Amaury Denoyelle9c3251d2021-10-18 14:39:57 +02002309 srv->ws = src->ws;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002310 srv->minconn = src->minconn;
2311 srv->maxconn = src->maxconn;
2312 srv->slowstart = src->slowstart;
2313 srv->observe = src->observe;
2314 srv->onerror = src->onerror;
2315 srv->onmarkeddown = src->onmarkeddown;
2316 srv->onmarkedup = src->onmarkedup;
2317 if (src->trackit != NULL)
2318 srv->trackit = strdup(src->trackit);
2319 srv->consecutive_errors_limit = src->consecutive_errors_limit;
2320 srv->uweight = srv->iweight = src->iweight;
2321
2322 srv->check.send_proxy = src->check.send_proxy;
2323 /* health: up, but will fall down at first failure */
2324 srv->check.rise = srv->check.health = src->check.rise;
2325 srv->check.fall = src->check.fall;
2326
2327 /* Here we check if 'disabled' is the default server state */
Emeric Brun52a91d32017-08-31 14:41:55 +02002328 if (src->next_admin & (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT)) {
2329 srv->next_admin |= SRV_ADMF_CMAINT | SRV_ADMF_FMAINT;
2330 srv->next_state = SRV_ST_STOPPED;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002331 srv->check.state |= CHK_ST_PAUSED;
2332 srv->check.health = 0;
2333 }
2334
2335 /* health: up but will fall down at first failure */
2336 srv->agent.rise = srv->agent.health = src->agent.rise;
2337 srv->agent.fall = src->agent.fall;
2338
2339 if (src->resolvers_id != NULL)
2340 srv->resolvers_id = strdup(src->resolvers_id);
Emeric Brun21fbeed2020-12-23 18:01:04 +01002341 srv->resolv_opts.family_prio = src->resolv_opts.family_prio;
2342 srv->resolv_opts.accept_duplicate_ip = src->resolv_opts.accept_duplicate_ip;
2343 srv->resolv_opts.ignore_weight = src->resolv_opts.ignore_weight;
2344 if (srv->resolv_opts.family_prio == AF_UNSPEC)
2345 srv->resolv_opts.family_prio = AF_INET6;
2346 memcpy(srv->resolv_opts.pref_net,
2347 src->resolv_opts.pref_net,
2348 sizeof srv->resolv_opts.pref_net);
2349 srv->resolv_opts.pref_net_nb = src->resolv_opts.pref_net_nb;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002350
2351 srv->init_addr_methods = src->init_addr_methods;
2352 srv->init_addr = src->init_addr;
2353#if defined(USE_OPENSSL)
2354 srv_ssl_settings_cpy(srv, src);
2355#endif
2356#ifdef TCP_USER_TIMEOUT
2357 srv->tcp_ut = src->tcp_ut;
2358#endif
Christopher Faulet8ed0a3e2018-04-10 14:45:45 +02002359 srv->mux_proto = src->mux_proto;
Olivier Houchardb7b3faa2018-12-14 18:15:36 +01002360 srv->pool_purge_delay = src->pool_purge_delay;
Willy Tarreau2f3f4d32020-07-01 07:43:51 +02002361 srv->low_idle_conns = src->low_idle_conns;
Olivier Houchard006e3102018-12-10 18:30:32 +01002362 srv->max_idle_conns = src->max_idle_conns;
Willy Tarreau9c538e02019-01-23 10:21:49 +01002363 srv->max_reuse = src->max_reuse;
Christopher Faulet8ed0a3e2018-04-10 14:45:45 +02002364
Olivier Houchard8da5f982017-08-04 18:35:36 +02002365 if (srv_tmpl)
2366 srv->srvrq = src->srvrq;
Alexander Liu2a54bb72019-05-22 19:44:48 +08002367
2368 srv->check.via_socks4 = src->check.via_socks4;
2369 srv->socks4_addr = src->socks4_addr;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002370}
2371
Willy Tarreau198e92a2021-03-05 10:23:32 +01002372/* allocate a server and attach it to the global servers_list. Returns
2373 * the server on success, otherwise NULL.
2374 */
William Lallemand313bfd12018-10-26 14:47:32 +02002375struct server *new_server(struct proxy *proxy)
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002376{
2377 struct server *srv;
2378
2379 srv = calloc(1, sizeof *srv);
2380 if (!srv)
2381 return NULL;
2382
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +02002383 srv_take(srv);
2384
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002385 srv->obj_type = OBJ_TYPE_SERVER;
2386 srv->proxy = proxy;
Willy Tarreaucdc83e02021-06-23 16:11:02 +02002387 queue_init(&srv->queue, proxy, srv);
Willy Tarreau2b718102021-04-21 07:32:39 +02002388 LIST_APPEND(&servers_list, &srv->global_list);
Emeric Brun34067662021-06-11 10:48:45 +02002389 LIST_INIT(&srv->srv_rec_item);
Emeric Brunbd78c912021-06-11 10:08:05 +02002390 LIST_INIT(&srv->ip_rec_item);
Aurelien DARRAGONf175b082023-02-01 17:22:32 +01002391 MT_LIST_INIT(&srv->prev_deleted);
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +01002392 event_hdl_sub_list_init(&srv->e_subs);
Christopher Faulet40a007c2017-07-03 15:41:01 +02002393
Emeric Brun52a91d32017-08-31 14:41:55 +02002394 srv->next_state = SRV_ST_RUNNING; /* early server setup */
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002395 srv->last_change = now.tv_sec;
2396
Christopher Faulet38290462020-04-21 11:46:40 +02002397 srv->check.obj_type = OBJ_TYPE_CHECK;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002398 srv->check.status = HCHK_STATUS_INI;
2399 srv->check.server = srv;
Olivier Houchardc98aa1f2019-01-11 18:17:17 +01002400 srv->check.proxy = proxy;
Christopher Faulet5d503fc2020-03-30 20:34:34 +02002401 srv->check.tcpcheck_rules = &proxy->tcpcheck_rules;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002402
Christopher Faulet38290462020-04-21 11:46:40 +02002403 srv->agent.obj_type = OBJ_TYPE_CHECK;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002404 srv->agent.status = HCHK_STATUS_INI;
2405 srv->agent.server = srv;
Willy Tarreau1ba32032019-01-21 07:48:26 +01002406 srv->agent.proxy = proxy;
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002407 srv->xprt = srv->check.xprt = srv->agent.xprt = xprt_get(XPRT_RAW);
Frédéric Lécaillef46c10c2020-11-23 14:29:28 +01002408#if defined(USE_QUIC)
2409 srv->cids = EB_ROOT_UNIQUE;
2410#endif
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002411
Amaury Denoyelle7f8f6cb2020-11-10 14:24:31 +01002412 srv->extra_counters = NULL;
William Lallemand3ce6eed2021-02-08 10:43:44 +01002413#ifdef USE_OPENSSL
2414 HA_RWLOCK_INIT(&srv->ssl_ctx.lock);
2415#endif
Amaury Denoyelle7f8f6cb2020-11-10 14:24:31 +01002416
Willy Tarreau975b1552019-06-06 16:25:55 +02002417 /* please don't put default server settings here, they are set in
Willy Tarreau144289b2021-02-12 08:19:01 +01002418 * proxy_preset_defaults().
Willy Tarreau975b1552019-06-06 16:25:55 +02002419 */
Frédéric Lécaille58b207c2017-03-30 14:18:30 +02002420 return srv;
2421}
Frédéric Lécaille759ea982017-03-30 17:32:36 +02002422
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +02002423/* Increment the server refcount. */
2424void srv_take(struct server *srv)
Amaury Denoyelled6b70802021-08-02 15:50:00 +02002425{
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +02002426 HA_ATOMIC_INC(&srv->refcount);
Amaury Denoyelled6b70802021-08-02 15:50:00 +02002427}
2428
Amaury Denoyelle13f2e2c2021-08-09 15:08:54 +02002429/* Deallocate a server <srv> and its member. <srv> must be allocated. For
2430 * dynamic servers, its refcount is decremented first. The free operations are
Aurelien DARRAGON32483ec2023-03-09 11:56:14 +01002431 * conducted only if the refcount is nul.
Amaury Denoyellef5c1e122021-08-25 15:03:46 +02002432 *
2433 * As a convenience, <srv.next> is returned if srv is not NULL. It may be useful
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +02002434 * when calling srv_drop on the list of servers.
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002435 */
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +02002436struct server *srv_drop(struct server *srv)
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002437{
Amaury Denoyellef5c1e122021-08-25 15:03:46 +02002438 struct server *next = NULL;
2439
William Lallemand4c395fc2021-08-20 10:10:15 +02002440 if (!srv)
Amaury Denoyellef5c1e122021-08-25 15:03:46 +02002441 goto end;
2442
2443 next = srv->next;
William Lallemand4c395fc2021-08-20 10:10:15 +02002444
Amaury Denoyelled6b70802021-08-02 15:50:00 +02002445 /* For dynamic servers, decrement the reference counter. Only free the
2446 * server when reaching zero.
2447 */
Aurelien DARRAGON32483ec2023-03-09 11:56:14 +01002448 if (HA_ATOMIC_SUB_FETCH(&srv->refcount, 1))
2449 goto end;
Amaury Denoyelled6b70802021-08-02 15:50:00 +02002450
Aurelien DARRAGONf175b082023-02-01 17:22:32 +01002451 /* make sure we are removed from our 'next->prev_deleted' list
2452 * This doesn't require full thread isolation as we're using mt lists
2453 * However this could easily be turned into regular list if required
2454 * (with the proper use of thread isolation)
2455 */
2456 MT_LIST_DELETE(&srv->prev_deleted);
2457
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002458 task_destroy(srv->warmup);
Christopher Fauletdcac4182021-06-15 16:17:17 +02002459 task_destroy(srv->srvrq_check);
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002460
2461 free(srv->id);
2462 free(srv->cookie);
2463 free(srv->hostname);
2464 free(srv->hostname_dn);
2465 free((char*)srv->conf.file);
2466 free(srv->per_thr);
Willy Tarreauc21a1872022-11-21 14:14:06 +01002467 free(srv->per_tgrp);
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002468 free(srv->curr_idle_thr);
2469 free(srv->resolvers_id);
2470 free(srv->addr_node.key);
Amaury Denoyellefb247942021-04-20 16:48:22 +02002471 free(srv->lb_nodes);
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002472
Aurelien DARRAGONb5ee8be2023-03-09 14:28:00 +01002473 if (xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->destroy_srv)
2474 xprt_get(XPRT_SSL)->destroy_srv(srv);
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002475 HA_SPIN_DESTROY(&srv->lock);
2476
Willy Tarreau2b718102021-04-21 07:32:39 +02002477 LIST_DELETE(&srv->global_list);
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +01002478 event_hdl_sub_list_destroy(&srv->e_subs);
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002479
2480 EXTRA_COUNTERS_FREE(srv->extra_counters);
2481
Tim Duesterhus025b93e2021-11-04 21:03:52 +01002482 ha_free(&srv);
Amaury Denoyellef5c1e122021-08-25 15:03:46 +02002483
2484 end:
2485 return next;
Amaury Denoyelle828adf02021-03-16 17:20:15 +01002486}
2487
Amaury Denoyelle56eb8ed2021-07-13 10:36:03 +02002488/* Remove a server <srv> from a tracking list if <srv> is tracking another
2489 * server. No special care is taken if <srv> is tracked itself by another one :
2490 * this situation should be avoided by the caller.
2491 *
2492 * Not thread-safe.
2493 */
2494static void release_server_track(struct server *srv)
2495{
2496 struct server *strack = srv->track;
2497 struct server **base;
2498
2499 if (!strack)
2500 return;
2501
2502 for (base = &strack->trackers; *base; base = &((*base)->tracknext)) {
2503 if (*base == srv) {
2504 *base = srv->tracknext;
2505 return;
2506 }
2507 }
2508
2509 /* srv not found on the tracking list, this should never happen */
2510 BUG_ON(!*base);
2511}
2512
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01002513/*
2514 * Parse as much as possible such a range string argument: low[-high]
2515 * Set <nb_low> and <nb_high> values so that they may be reused by this loop
2516 * for(int i = nb_low; i <= nb_high; i++)... with nb_low >= 1.
2517 * Fails if 'low' < 0 or 'high' is present and not higher than 'low'.
2518 * Returns 0 if succeeded, -1 if not.
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002519 */
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002520static int _srv_parse_tmpl_range(struct server *srv, const char *arg,
2521 int *nb_low, int *nb_high)
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002522{
2523 char *nb_high_arg;
2524
2525 *nb_high = 0;
2526 chunk_printf(&trash, "%s", arg);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002527 *nb_low = atoi(trash.area);
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002528
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002529 if ((nb_high_arg = strchr(trash.area, '-'))) {
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002530 *nb_high_arg++ = '\0';
2531 *nb_high = atoi(nb_high_arg);
2532 }
2533 else {
2534 *nb_high += *nb_low;
2535 *nb_low = 1;
2536 }
2537
2538 if (*nb_low < 0 || *nb_high < *nb_low)
2539 return -1;
2540
2541 return 0;
2542}
2543
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002544/* Parse as much as possible such a range string argument: low[-high]
2545 * Set <nb_low> and <nb_high> values so that they may be reused by this loop
2546 * for(int i = nb_low; i <= nb_high; i++)... with nb_low >= 1.
2547 *
Ilya Shipitsinba13f162021-03-19 22:21:44 +05002548 * This function is first intended to be used through parse_server to
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002549 * initialize a new server on startup.
2550 *
2551 * Fails if 'low' < 0 or 'high' is present and not higher than 'low'.
2552 * Returns 0 if succeeded, -1 if not.
2553 */
2554static inline void _srv_parse_set_id_from_prefix(struct server *srv,
2555 const char *prefix, int nb)
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002556{
2557 chunk_printf(&trash, "%s%d", prefix, nb);
2558 free(srv->id);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002559 srv->id = strdup(trash.area);
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002560}
2561
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002562/* Initialize as much as possible servers from <srv> server template.
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002563 * Note that a server template is a special server with
2564 * a few different parameters than a server which has
2565 * been parsed mostly the same way as a server.
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002566 *
Ilya Shipitsinba13f162021-03-19 22:21:44 +05002567 * This function is first intended to be used through parse_server to
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002568 * initialize a new server on startup.
2569 *
Joseph Herlant44466822018-11-15 08:57:51 -08002570 * Returns the number of servers successfully allocated,
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002571 * 'srv' template included.
2572 */
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002573static int _srv_parse_tmpl_init(struct server *srv, struct proxy *px)
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002574{
2575 int i;
2576 struct server *newsrv;
2577
2578 for (i = srv->tmpl_info.nb_low + 1; i <= srv->tmpl_info.nb_high; i++) {
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002579 newsrv = new_server(px);
2580 if (!newsrv)
2581 goto err;
2582
Christopher Faulet75bef002020-11-02 22:04:55 +01002583 newsrv->conf.file = strdup(srv->conf.file);
2584 newsrv->conf.line = srv->conf.line;
2585
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002586 srv_settings_cpy(newsrv, srv, 1);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02002587 srv_prepare_for_resolution(newsrv, srv->hostname);
Willy Tarreau80527bc2021-10-06 14:48:37 +02002588
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002589 if (newsrv->sni_expr) {
2590 newsrv->ssl_ctx.sni = srv_sni_sample_parse_expr(newsrv, px, NULL, 0, NULL);
2591 if (!newsrv->ssl_ctx.sni)
2592 goto err;
2593 }
Willy Tarreau80527bc2021-10-06 14:48:37 +02002594
Emeric Brun34067662021-06-11 10:48:45 +02002595 /* append to list of servers available to receive an hostname */
Emeric Bruncaef19e2021-06-14 10:02:18 +02002596 if (newsrv->srvrq)
2597 LIST_APPEND(&newsrv->srvrq->attached_servers, &newsrv->srv_rec_item);
Emeric Brun34067662021-06-11 10:48:45 +02002598
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002599 /* Set this new server ID. */
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002600 _srv_parse_set_id_from_prefix(newsrv, srv->tmpl_info.prefix, i);
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002601
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002602 /* Linked backwards first. This will be restablished after parsing. */
2603 newsrv->next = px->srv;
2604 px->srv = newsrv;
2605 }
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002606 _srv_parse_set_id_from_prefix(srv, srv->tmpl_info.prefix, srv->tmpl_info.nb_low);
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002607
2608 return i - srv->tmpl_info.nb_low;
2609
2610 err:
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002611 _srv_parse_set_id_from_prefix(srv, srv->tmpl_info.prefix, srv->tmpl_info.nb_low);
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002612 if (newsrv) {
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002613 release_sample_expr(newsrv->ssl_ctx.sni);
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002614 free_check(&newsrv->agent);
2615 free_check(&newsrv->check);
Willy Tarreau2b718102021-04-21 07:32:39 +02002616 LIST_DELETE(&newsrv->global_list);
Frédéric Lécaille72ed4752017-04-14 13:28:00 +02002617 }
2618 free(newsrv);
2619 return i - srv->tmpl_info.nb_low;
2620}
2621
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002622/* Allocate a new server pointed by <srv> and try to parse the first arguments
2623 * in <args> as an address for a server or an address-range for a template or
2624 * nothing for a default-server. <cur_arg> is incremented to the next argument.
2625 *
Ilya Shipitsinba13f162021-03-19 22:21:44 +05002626 * This function is first intended to be used through parse_server to
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002627 * initialize a new server on startup.
2628 *
2629 * A mask of errors is returned. On a parsing error, ERR_FATAL is set. In case
2630 * of memory exhaustion, ERR_ABORT is set. If the server cannot be allocated,
2631 * <srv> will be set to NULL.
2632 */
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002633static int _srv_parse_init(struct server **srv, char **args, int *cur_arg,
2634 struct proxy *curproxy,
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002635 int parse_flags)
Willy Tarreau272adea2014-03-31 10:39:59 +02002636{
2637 struct server *newsrv = NULL;
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002638 const char *err = NULL;
Willy Tarreau272adea2014-03-31 10:39:59 +02002639 int err_code = 0;
Willy Tarreau07101d52015-09-08 16:16:35 +02002640 char *fqdn = NULL;
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002641 int tmpl_range_low = 0, tmpl_range_high = 0;
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002642 char *errmsg = NULL;
Willy Tarreau272adea2014-03-31 10:39:59 +02002643
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002644 *srv = NULL;
2645
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002646 /* There is no mandatory first arguments for default server. */
2647 if (parse_flags & SRV_PARSE_PARSE_ADDR) {
2648 if (parse_flags & SRV_PARSE_TEMPLATE) {
2649 if (!*args[3]) {
2650 /* 'server-template' line number of argument check. */
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002651 ha_alert("'%s' expects <prefix> <nb | range> <addr>[:<port>] as arguments.\n",
2652 args[0]);
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002653 err_code |= ERR_ALERT | ERR_FATAL;
2654 goto out;
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002655 }
2656
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002657 err = invalid_prefix_char(args[1]);
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002658 }
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002659 else {
2660 if (!*args[2]) {
2661 /* 'server' line number of argument check. */
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002662 ha_alert("'%s' expects <name> and <addr>[:<port>] as arguments.\n",
2663 args[0]);
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002664 err_code |= ERR_ALERT | ERR_FATAL;
2665 goto out;
2666 }
2667
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002668 err = invalid_char(args[1]);
Willy Tarreau272adea2014-03-31 10:39:59 +02002669 }
2670
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002671 if (err) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002672 ha_alert("character '%c' is not permitted in %s %s '%s'.\n",
2673 *err, args[0], !(parse_flags & SRV_PARSE_TEMPLATE) ? "name" : "prefix", args[1]);
Willy Tarreau272adea2014-03-31 10:39:59 +02002674 err_code |= ERR_ALERT | ERR_FATAL;
2675 goto out;
2676 }
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002677 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002678
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002679 *cur_arg = 2;
2680 if (parse_flags & SRV_PARSE_TEMPLATE) {
2681 /* Parse server-template <nb | range> arg. */
2682 if (_srv_parse_tmpl_range(newsrv, args[*cur_arg], &tmpl_range_low, &tmpl_range_high) < 0) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002683 ha_alert("Wrong %s number or range arg '%s'.\n",
2684 args[0], args[*cur_arg]);
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002685 err_code |= ERR_ALERT | ERR_FATAL;
2686 goto out;
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002687 }
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002688 (*cur_arg)++;
2689 }
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002690
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002691 if (!(parse_flags & SRV_PARSE_DEFAULT_SERVER)) {
2692 struct sockaddr_storage *sk;
2693 int port1, port2, port;
Willy Tarreau272adea2014-03-31 10:39:59 +02002694
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002695 *srv = newsrv = new_server(curproxy);
2696 if (!newsrv) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002697 ha_alert("out of memory.\n");
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002698 err_code |= ERR_ALERT | ERR_ABORT;
2699 goto out;
2700 }
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02002701 register_parsing_obj(&newsrv->obj_type);
Willy Tarreau272adea2014-03-31 10:39:59 +02002702
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002703 if (parse_flags & SRV_PARSE_TEMPLATE) {
2704 newsrv->tmpl_info.nb_low = tmpl_range_low;
2705 newsrv->tmpl_info.nb_high = tmpl_range_high;
2706 }
Frédéric Lécailleb82f7422017-04-13 18:24:23 +02002707
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01002708 if (parse_flags & SRV_PARSE_DYNAMIC)
2709 newsrv->flags |= SRV_F_DYNAMIC;
2710
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002711 /* Note: for a server template, its id is its prefix.
2712 * This is a temporary id which will be used for server allocations to come
2713 * after parsing.
2714 */
2715 if (!(parse_flags & SRV_PARSE_TEMPLATE))
2716 newsrv->id = strdup(args[1]);
2717 else
2718 newsrv->tmpl_info.prefix = strdup(args[1]);
Willy Tarreau272adea2014-03-31 10:39:59 +02002719
Aurelien DARRAGON61e38942022-11-17 16:10:35 +01002720 /* revision defaults to 0 */
2721 newsrv->rid = 0;
2722
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002723 /* several ways to check the port component :
2724 * - IP => port=+0, relative (IPv4 only)
2725 * - IP: => port=+0, relative
2726 * - IP:N => port=N, absolute
2727 * - IP:+N => port=+N, relative
2728 * - IP:-N => port=-N, relative
2729 */
2730 if (!(parse_flags & SRV_PARSE_PARSE_ADDR))
2731 goto skip_addr;
Frédéric Lécaille355b2032019-01-11 14:06:12 +01002732
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002733 sk = str2sa_range(args[*cur_arg], &port, &port1, &port2, NULL, NULL,
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002734 &errmsg, NULL, &fqdn,
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002735 (parse_flags & SRV_PARSE_INITIAL_RESOLVE ? PA_O_RESOLVE : 0) | PA_O_PORT_OK | PA_O_PORT_OFS | PA_O_STREAM | PA_O_XPRT | PA_O_CONNECT);
2736 if (!sk) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002737 ha_alert("%s\n", errmsg);
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002738 err_code |= ERR_ALERT | ERR_FATAL;
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002739 ha_free(&errmsg);
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002740 goto out;
2741 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002742
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002743 if (!port1 || !port2) {
2744 /* no port specified, +offset, -offset */
2745 newsrv->flags |= SRV_F_MAPPORTS;
2746 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002747
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002748 /* save hostname and create associated name resolution */
2749 if (fqdn) {
2750 if (fqdn[0] == '_') { /* SRV record */
2751 /* Check if a SRV request already exists, and if not, create it */
2752 if ((newsrv->srvrq = find_srvrq_by_name(fqdn, curproxy)) == NULL)
2753 newsrv->srvrq = new_resolv_srvrq(newsrv, fqdn);
2754 if (newsrv->srvrq == NULL) {
Christopher Faulet67957bd2017-09-27 11:00:59 +02002755 err_code |= ERR_ALERT | ERR_FATAL;
2756 goto out;
Baptiste Assmann4f91f7e2017-05-03 12:09:54 +02002757 }
Christopher Faulet81ba74a2021-06-29 20:52:35 +02002758 LIST_APPEND(&newsrv->srvrq->attached_servers, &newsrv->srv_rec_item);
Baptiste Assmanna68ca962015-04-14 01:15:08 +02002759 }
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002760 else if (srv_prepare_for_resolution(newsrv, fqdn) == -1) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002761 ha_alert("Can't create DNS resolution for server '%s'\n",
2762 newsrv->id);
Willy Tarreau272adea2014-03-31 10:39:59 +02002763 err_code |= ERR_ALERT | ERR_FATAL;
2764 goto out;
2765 }
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002766 }
Frédéric Lécaille5c3cd972017-03-15 16:36:09 +01002767
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002768 newsrv->addr = *sk;
2769 newsrv->svc_port = port;
Amaury Denoyelle8ff04342021-06-08 15:19:51 +02002770 /*
2771 * we don't need to lock the server here, because
2772 * we are in the process of initializing.
2773 *
2774 * Note that the server is not attached into the proxy tree if
2775 * this is a dynamic server.
2776 */
2777 srv_set_addr_desc(newsrv, !(parse_flags & SRV_PARSE_DYNAMIC));
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002778
Willy Tarreau14e7f292021-10-27 17:41:07 +02002779 if (!newsrv->srvrq && !newsrv->hostname &&
2780 !protocol_lookup(newsrv->addr.ss_family, PROTO_TYPE_STREAM, 0)) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002781 ha_alert("Unknown protocol family %d '%s'\n",
2782 newsrv->addr.ss_family, args[*cur_arg]);
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002783 err_code |= ERR_ALERT | ERR_FATAL;
2784 goto out;
Willy Tarreau272adea2014-03-31 10:39:59 +02002785 }
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002786
2787 (*cur_arg)++;
2788 skip_addr:
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01002789 if (!(parse_flags & SRV_PARSE_DYNAMIC)) {
2790 /* Copy default server settings to new server */
2791 srv_settings_cpy(newsrv, &curproxy->defsrv, 0);
2792 } else {
2793 /* Initialize dynamic server weight to 1 */
2794 newsrv->uweight = newsrv->iweight = 1;
2795
2796 /* A dynamic server is disabled on startup */
2797 newsrv->next_admin = SRV_ADMF_FMAINT;
2798 newsrv->next_state = SRV_ST_STOPPED;
2799 server_recalc_eweight(newsrv, 0);
Amaury Denoyellefca18172021-07-22 16:03:36 +02002800
2801 /* Set default values for checks */
2802 newsrv->check.inter = DEF_CHKINTR;
2803 newsrv->check.rise = DEF_RISETIME;
2804 newsrv->check.fall = DEF_FALLTIME;
2805
2806 newsrv->agent.inter = DEF_CHKINTR;
2807 newsrv->agent.rise = DEF_AGENT_RISETIME;
2808 newsrv->agent.fall = DEF_AGENT_FALLTIME;
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01002809 }
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002810 HA_SPIN_INIT(&newsrv->lock);
2811 }
2812 else {
2813 *srv = newsrv = &curproxy->defsrv;
2814 *cur_arg = 1;
2815 newsrv->resolv_opts.family_prio = AF_INET6;
2816 newsrv->resolv_opts.accept_duplicate_ip = 0;
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002817 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002818
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002819 free(fqdn);
2820 return 0;
Willy Tarreau9faebe32019-06-07 19:00:37 +02002821
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002822out:
2823 free(fqdn);
2824 return err_code;
2825}
Willy Tarreau272adea2014-03-31 10:39:59 +02002826
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002827/* Parse the server keyword in <args>.
2828 * <cur_arg> is incremented beyond the keyword optional value. Note that this
2829 * might not be the case if an error is reported.
2830 *
Ilya Shipitsinba13f162021-03-19 22:21:44 +05002831 * This function is first intended to be used through parse_server to
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002832 * initialize a new server on startup.
2833 *
2834 * A mask of errors is returned. ERR_FATAL is set if the parsing should be
2835 * interrupted.
2836 */
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002837static int _srv_parse_kw(struct server *srv, char **args, int *cur_arg,
2838 struct proxy *curproxy,
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002839 int parse_flags)
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002840{
2841 int err_code = 0;
2842 struct srv_kw *kw;
2843 const char *best;
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002844 char *errmsg = NULL;
Willy Tarreau272adea2014-03-31 10:39:59 +02002845
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002846 kw = srv_find_kw(args[*cur_arg]);
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002847 if (!kw) {
2848 best = srv_find_best_kw(args[*cur_arg]);
2849 if (best)
Willy Tarreau245721b2022-05-31 09:25:34 +02002850 ha_alert("unknown keyword '%s'; did you mean '%s' maybe ?%s\n",
2851 args[*cur_arg], best,
2852 (parse_flags & SRV_PARSE_PARSE_ADDR) ? "" :
2853 " Hint: no address was expected for this server.");
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002854 else
Willy Tarreau245721b2022-05-31 09:25:34 +02002855 ha_alert("unknown keyword '%s'.%s\n", args[*cur_arg],
2856 (parse_flags & SRV_PARSE_PARSE_ADDR) ? "" :
2857 " Hint: no address was expected for this server.");
Willy Tarreau272adea2014-03-31 10:39:59 +02002858
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002859 return ERR_ALERT | ERR_FATAL;
2860 }
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002861
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002862 if (!kw->parse) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002863 ha_alert("'%s' option is not implemented in this version (check build options)\n",
2864 args[*cur_arg]);
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002865 err_code = ERR_ALERT | ERR_FATAL;
2866 goto out;
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002867 }
Willy Tarreau272adea2014-03-31 10:39:59 +02002868
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002869 if ((parse_flags & SRV_PARSE_DEFAULT_SERVER) && !kw->default_ok) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002870 ha_alert("'%s' option is not accepted in default-server sections\n",
2871 args[*cur_arg]);
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002872 err_code = ERR_ALERT;
2873 goto out;
2874 }
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01002875 else if ((parse_flags & SRV_PARSE_DYNAMIC) && !kw->dynamic_ok) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002876 ha_alert("'%s' option is not accepted for dynamic server\n",
2877 args[*cur_arg]);
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01002878 err_code |= ERR_ALERT;
2879 goto out;
2880 }
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002881
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002882 err_code = kw->parse(args, cur_arg, curproxy, srv, &errmsg);
2883 if (err_code) {
2884 display_parser_err(NULL, 0, args, *cur_arg, err_code, &errmsg);
2885 free(errmsg);
2886 }
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002887
2888out:
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002889 if (kw->skip != -1)
2890 *cur_arg += 1 + kw->skip;
2891
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002892 return err_code;
2893}
2894
Ilya Shipitsinba13f162021-03-19 22:21:44 +05002895/* This function is first intended to be used through parse_server to
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002896 * initialize a new server on startup.
2897 */
2898static int _srv_parse_sni_expr_init(char **args, int cur_arg,
2899 struct server *srv, struct proxy *proxy,
2900 char **errmsg)
2901{
2902 int ret;
2903
2904 if (!srv->sni_expr)
2905 return 0;
2906
2907 ret = server_parse_sni_expr(srv, proxy, errmsg);
2908 if (!ret)
2909 return 0;
2910
2911 return ret;
2912}
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002913
2914/* Server initializations finalization.
2915 * Initialize health check, agent check and SNI expression if enabled.
2916 * Must not be called for a default server instance.
2917 *
Ilya Shipitsinba13f162021-03-19 22:21:44 +05002918 * This function is first intended to be used through parse_server to
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002919 * initialize a new server on startup.
2920 */
2921static int _srv_parse_finalize(char **args, int cur_arg,
2922 struct server *srv, struct proxy *px,
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002923 int parse_flags)
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002924{
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002925 int ret;
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002926 char *errmsg = NULL;
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002927
2928 if (srv->do_check && srv->trackit) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002929 ha_alert("unable to enable checks and tracking at the same time!\n");
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002930 return ERR_ALERT | ERR_FATAL;
2931 }
2932
2933 if (srv->do_agent && !srv->agent.port) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002934 ha_alert("server %s does not have agent port. Agent check has been disabled.\n",
2935 srv->id);
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002936 return ERR_ALERT | ERR_FATAL;
2937 }
2938
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002939 if ((ret = _srv_parse_sni_expr_init(args, cur_arg, srv, px, &errmsg)) != 0) {
2940 if (errmsg) {
2941 ha_alert("%s\n", errmsg);
2942 free(errmsg);
2943 }
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002944 return ret;
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002945 }
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002946
Amaury Denoyelle76e10e72021-03-08 17:08:01 +01002947 /* A dynamic server is disabled on startup. It must not be counted as
2948 * an active backend entry.
2949 */
2950 if (!(parse_flags & SRV_PARSE_DYNAMIC)) {
2951 if (srv->flags & SRV_F_BACKUP)
2952 px->srv_bck++;
2953 else
2954 px->srv_act++;
2955 }
2956
Amaury Denoyelle7d27efe2021-03-17 14:25:39 +01002957 srv_lb_commit_status(srv);
2958
2959 return 0;
2960}
2961
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002962int parse_server(const char *file, int linenum, char **args,
2963 struct proxy *curproxy, const struct proxy *defproxy,
2964 int parse_flags)
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002965{
2966 struct server *newsrv = NULL;
2967 int err_code = 0;
2968
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002969 int cur_arg;
Willy Tarreau272adea2014-03-31 10:39:59 +02002970
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02002971 set_usermsgs_ctx(file, linenum, NULL);
2972
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002973 if (!(parse_flags & SRV_PARSE_DEFAULT_SERVER) && curproxy == defproxy) {
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02002974 ha_alert("'%s' not allowed in 'defaults' section.\n", args[0]);
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002975 err_code |= ERR_ALERT | ERR_FATAL;
2976 goto out;
2977 }
2978 else if (failifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) {
2979 err_code |= ERR_ALERT | ERR_FATAL;
2980 goto out;
2981 }
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002982
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002983 if ((parse_flags & (SRV_PARSE_IN_PEER_SECTION|SRV_PARSE_PARSE_ADDR)) ==
2984 (SRV_PARSE_IN_PEER_SECTION|SRV_PARSE_PARSE_ADDR)) {
2985 if (!*args[2])
2986 return 0;
2987 }
Amaury Denoyelle9394a942021-03-08 11:20:52 +01002988
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002989 err_code = _srv_parse_init(&newsrv, args, &cur_arg, curproxy,
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02002990 parse_flags);
Amaury Denoyellecf58dd72021-03-08 16:35:54 +01002991
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002992 /* the servers are linked backwards first */
2993 if (newsrv && !(parse_flags & SRV_PARSE_DEFAULT_SERVER)) {
2994 newsrv->next = curproxy->srv;
2995 curproxy->srv = newsrv;
2996 }
Amaury Denoyellea8f442e2021-03-08 10:29:33 +01002997
Amaury Denoyelle30c05372021-03-08 16:36:46 +01002998 if (err_code & ERR_CODE)
2999 goto out;
Amaury Denoyelle9394a942021-03-08 11:20:52 +01003000
Amaury Denoyelle30c05372021-03-08 16:36:46 +01003001 newsrv->conf.file = strdup(file);
3002 newsrv->conf.line = linenum;
Amaury Denoyelle9394a942021-03-08 11:20:52 +01003003
Amaury Denoyelle30c05372021-03-08 16:36:46 +01003004 while (*args[cur_arg]) {
Amaury Denoyelle30c05372021-03-08 16:36:46 +01003005 err_code = _srv_parse_kw(newsrv, args, &cur_arg, curproxy,
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02003006 parse_flags);
Amaury Denoyelle30c05372021-03-08 16:36:46 +01003007 if (err_code & ERR_FATAL)
3008 goto out;
3009 }
Amaury Denoyelle9394a942021-03-08 11:20:52 +01003010
Amaury Denoyelle30c05372021-03-08 16:36:46 +01003011 if (!(parse_flags & SRV_PARSE_DEFAULT_SERVER)) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02003012 err_code |= _srv_parse_finalize(args, cur_arg, newsrv, curproxy, parse_flags);
Amaury Denoyelle30c05372021-03-08 16:36:46 +01003013 if (err_code & ERR_FATAL)
3014 goto out;
Willy Tarreau272adea2014-03-31 10:39:59 +02003015 }
Amaury Denoyellecf58dd72021-03-08 16:35:54 +01003016
Amaury Denoyelle30c05372021-03-08 16:36:46 +01003017 if (parse_flags & SRV_PARSE_TEMPLATE)
3018 _srv_parse_tmpl_init(newsrv, curproxy);
3019
Amaury Denoyelle1613b4a2021-06-08 17:00:20 +02003020 /* If the server id is fixed, insert it in the proxy used_id tree.
3021 * This is needed to detect a later duplicate id via srv_parse_id.
3022 *
3023 * If no is specified, a dynamic one is generated in
3024 * check_config_validity.
3025 */
3026 if (newsrv->flags & SRV_F_FORCED_ID)
3027 eb32_insert(&curproxy->conf.used_server_id, &newsrv->conf.id);
3028
Amaury Denoyelle24abb0c2021-05-07 15:13:51 +02003029 HA_DIAG_WARNING_COND((curproxy->cap & PR_CAP_LB) && !newsrv->uweight,
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02003030 "configured with weight of 0 will never be selected by load balancing algorithms\n");
Amaury Denoyelleda0e7f62021-03-30 10:26:27 +02003031
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02003032 reset_usermsgs_ctx();
Willy Tarreau272adea2014-03-31 10:39:59 +02003033 return 0;
3034
3035 out:
Amaury Denoyelle0fc136c2021-05-28 11:00:18 +02003036 reset_usermsgs_ctx();
Willy Tarreau272adea2014-03-31 10:39:59 +02003037 return err_code;
3038}
3039
Baptiste Assmann19a106d2015-07-08 22:03:56 +02003040/* Returns a pointer to the first server matching either id <id>.
3041 * NULL is returned if no match is found.
3042 * the lookup is performed in the backend <bk>
3043 */
3044struct server *server_find_by_id(struct proxy *bk, int id)
3045{
3046 struct eb32_node *eb32;
3047 struct server *curserver;
3048
3049 if (!bk || (id ==0))
3050 return NULL;
3051
3052 /* <bk> has no backend capabilities, so it can't have a server */
3053 if (!(bk->cap & PR_CAP_BE))
3054 return NULL;
3055
3056 curserver = NULL;
3057
3058 eb32 = eb32_lookup(&bk->conf.used_server_id, id);
3059 if (eb32)
3060 curserver = container_of(eb32, struct server, conf.id);
3061
3062 return curserver;
3063}
3064
3065/* Returns a pointer to the first server matching either name <name>, or id
3066 * if <name> starts with a '#'. NULL is returned if no match is found.
3067 * the lookup is performed in the backend <bk>
3068 */
3069struct server *server_find_by_name(struct proxy *bk, const char *name)
3070{
3071 struct server *curserver;
3072
3073 if (!bk || !name)
3074 return NULL;
3075
3076 /* <bk> has no backend capabilities, so it can't have a server */
3077 if (!(bk->cap & PR_CAP_BE))
3078 return NULL;
3079
3080 curserver = NULL;
3081 if (*name == '#') {
3082 curserver = server_find_by_id(bk, atoi(name + 1));
3083 if (curserver)
3084 return curserver;
3085 }
3086 else {
3087 curserver = bk->srv;
3088
3089 while (curserver && (strcmp(curserver->id, name) != 0))
3090 curserver = curserver->next;
3091
3092 if (curserver)
3093 return curserver;
3094 }
3095
3096 return NULL;
3097}
3098
3099struct server *server_find_best_match(struct proxy *bk, char *name, int id, int *diff)
3100{
3101 struct server *byname;
3102 struct server *byid;
3103
3104 if (!name && !id)
3105 return NULL;
3106
3107 if (diff)
3108 *diff = 0;
3109
3110 byname = byid = NULL;
3111
3112 if (name) {
3113 byname = server_find_by_name(bk, name);
3114 if (byname && (!id || byname->puid == id))
3115 return byname;
3116 }
3117
3118 /* remaining possibilities :
3119 * - name not set
3120 * - name set but not found
3121 * - name found but ID doesn't match
3122 */
3123 if (id) {
3124 byid = server_find_by_id(bk, id);
3125 if (byid) {
3126 if (byname) {
3127 /* use id only if forced by configuration */
3128 if (byid->flags & SRV_F_FORCED_ID) {
3129 if (diff)
3130 *diff |= 2;
3131 return byid;
3132 }
3133 else {
3134 if (diff)
3135 *diff |= 1;
3136 return byname;
3137 }
3138 }
3139
3140 /* remaining possibilities:
3141 * - name not set
3142 * - name set but not found
3143 */
3144 if (name && diff)
3145 *diff |= 2;
3146 return byid;
3147 }
3148
3149 /* id bot found */
3150 if (byname) {
3151 if (diff)
3152 *diff |= 1;
3153 return byname;
3154 }
3155 }
3156
3157 return NULL;
3158}
3159
Simon Horman7d09b9a2013-02-12 10:45:51 +09003160/*
Baptiste Assmann14e40142015-04-14 01:13:07 +02003161 * update a server's current IP address.
3162 * ip is a pointer to the new IP address, whose address family is ip_sin_family.
3163 * ip is in network format.
3164 * updater is a string which contains an information about the requester of the update.
3165 * updater is used if not NULL.
3166 *
3167 * A log line and a stderr warning message is generated based on server's backend options.
Willy Tarreau46b7f532018-08-21 11:54:26 +02003168 *
3169 * Must be called with the server lock held.
Baptiste Assmann14e40142015-04-14 01:13:07 +02003170 */
Christopher Faulet69beaa92021-02-16 12:07:47 +01003171int srv_update_addr(struct server *s, void *ip, int ip_sin_family, const char *updater)
Baptiste Assmann14e40142015-04-14 01:13:07 +02003172{
Christopher Fauletd6c6b5f2020-09-08 10:27:24 +02003173 /* save the new IP family & address if necessary */
3174 switch (ip_sin_family) {
3175 case AF_INET:
3176 if (s->addr.ss_family == ip_sin_family &&
3177 !memcmp(ip, &((struct sockaddr_in *)&s->addr)->sin_addr.s_addr, 4))
3178 return 0;
3179 break;
3180 case AF_INET6:
3181 if (s->addr.ss_family == ip_sin_family &&
3182 !memcmp(ip, &((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, 16))
3183 return 0;
3184 break;
3185 };
3186
Baptiste Assmann14e40142015-04-14 01:13:07 +02003187 /* generates a log line and a warning on stderr */
3188 if (1) {
3189 /* book enough space for both IPv4 and IPv6 */
3190 char oldip[INET6_ADDRSTRLEN];
3191 char newip[INET6_ADDRSTRLEN];
3192
3193 memset(oldip, '\0', INET6_ADDRSTRLEN);
3194 memset(newip, '\0', INET6_ADDRSTRLEN);
3195
3196 /* copy old IP address in a string */
3197 switch (s->addr.ss_family) {
3198 case AF_INET:
3199 inet_ntop(s->addr.ss_family, &((struct sockaddr_in *)&s->addr)->sin_addr, oldip, INET_ADDRSTRLEN);
3200 break;
3201 case AF_INET6:
3202 inet_ntop(s->addr.ss_family, &((struct sockaddr_in6 *)&s->addr)->sin6_addr, oldip, INET6_ADDRSTRLEN);
3203 break;
Christopher Fauletb0b76072020-09-08 10:38:40 +02003204 default:
Willy Tarreaufc458ec2023-04-07 18:11:39 +02003205 strlcpy2(oldip, "(none)", sizeof(oldip));
Christopher Fauletb0b76072020-09-08 10:38:40 +02003206 break;
Baptiste Assmann14e40142015-04-14 01:13:07 +02003207 };
3208
3209 /* copy new IP address in a string */
3210 switch (ip_sin_family) {
3211 case AF_INET:
3212 inet_ntop(ip_sin_family, ip, newip, INET_ADDRSTRLEN);
3213 break;
3214 case AF_INET6:
3215 inet_ntop(ip_sin_family, ip, newip, INET6_ADDRSTRLEN);
3216 break;
3217 };
3218
3219 /* save log line into a buffer */
3220 chunk_printf(&trash, "%s/%s changed its IP from %s to %s by %s",
3221 s->proxy->id, s->id, oldip, newip, updater);
3222
3223 /* write the buffer on stderr */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003224 ha_warning("%s.\n", trash.area);
Baptiste Assmann14e40142015-04-14 01:13:07 +02003225
3226 /* send a log */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003227 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.area);
Baptiste Assmann14e40142015-04-14 01:13:07 +02003228 }
3229
3230 /* save the new IP family */
3231 s->addr.ss_family = ip_sin_family;
3232 /* save the new IP address */
3233 switch (ip_sin_family) {
3234 case AF_INET:
Willy Tarreaueec1d382016-07-13 11:59:39 +02003235 memcpy(&((struct sockaddr_in *)&s->addr)->sin_addr.s_addr, ip, 4);
Baptiste Assmann14e40142015-04-14 01:13:07 +02003236 break;
3237 case AF_INET6:
3238 memcpy(((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr, ip, 16);
3239 break;
3240 };
Olivier Houchard4e694042017-03-14 20:01:29 +01003241 srv_set_dyncookie(s);
Amaury Denoyelle8ff04342021-06-08 15:19:51 +02003242 srv_set_addr_desc(s, 1);
Baptiste Assmann14e40142015-04-14 01:13:07 +02003243
3244 return 0;
3245}
3246
William Dauchy7cabc062021-02-11 22:51:24 +01003247/* update agent health check address and port
3248 * addr can be ip4/ip6 or a hostname
3249 * if one error occurs, don't apply anything
3250 * must be called with the server lock held.
3251 */
Christopher Faulet69beaa92021-02-16 12:07:47 +01003252const char *srv_update_agent_addr_port(struct server *s, const char *addr, const char *port)
William Dauchy7cabc062021-02-11 22:51:24 +01003253{
3254 struct sockaddr_storage sk;
3255 struct buffer *msg;
3256 int new_port;
3257
3258 msg = get_trash_chunk();
3259 chunk_reset(msg);
3260
3261 if (!(s->agent.state & CHK_ST_ENABLED)) {
3262 chunk_strcat(msg, "agent checks are not enabled on this server");
3263 goto out;
3264 }
3265 if (addr) {
3266 memset(&sk, 0, sizeof(struct sockaddr_storage));
3267 if (str2ip(addr, &sk) == NULL) {
3268 chunk_appendf(msg, "invalid addr '%s'", addr);
3269 goto out;
3270 }
3271 }
3272 if (port) {
3273 if (strl2irc(port, strlen(port), &new_port) != 0) {
3274 chunk_appendf(msg, "provided port is not an integer");
3275 goto out;
3276 }
3277 if (new_port < 0 || new_port > 65535) {
3278 chunk_appendf(msg, "provided port is invalid");
3279 goto out;
3280 }
3281 }
3282out:
3283 if (msg->data)
3284 return msg->area;
3285 else {
3286 if (addr)
3287 set_srv_agent_addr(s, &sk);
3288 if (port)
3289 set_srv_agent_port(s, new_port);
3290 }
3291 return NULL;
3292}
3293
William Dauchyb456e1f2021-02-11 22:51:23 +01003294/* update server health check address and port
3295 * addr must be ip4 or ip6, it won't be resolved
3296 * if one error occurs, don't apply anything
3297 * must be called with the server lock held.
3298 */
Christopher Faulet69beaa92021-02-16 12:07:47 +01003299const char *srv_update_check_addr_port(struct server *s, const char *addr, const char *port)
William Dauchyb456e1f2021-02-11 22:51:23 +01003300{
3301 struct sockaddr_storage sk;
3302 struct buffer *msg;
3303 int new_port;
3304
3305 msg = get_trash_chunk();
3306 chunk_reset(msg);
3307
3308 if (!(s->check.state & CHK_ST_ENABLED)) {
3309 chunk_strcat(msg, "health checks are not enabled on this server");
3310 goto out;
3311 }
3312 if (addr) {
3313 memset(&sk, 0, sizeof(struct sockaddr_storage));
3314 if (str2ip2(addr, &sk, 0) == NULL) {
3315 chunk_appendf(msg, "invalid addr '%s'", addr);
3316 goto out;
3317 }
3318 }
3319 if (port) {
3320 if (strl2irc(port, strlen(port), &new_port) != 0) {
3321 chunk_appendf(msg, "provided port is not an integer");
3322 goto out;
3323 }
3324 if (new_port < 0 || new_port > 65535) {
3325 chunk_appendf(msg, "provided port is invalid");
3326 goto out;
3327 }
3328 /* prevent the update of port to 0 if MAPPORTS are in use */
3329 if ((s->flags & SRV_F_MAPPORTS) && new_port == 0) {
3330 chunk_appendf(msg, "can't unset 'port' since MAPPORTS is in use");
3331 goto out;
3332 }
3333 }
3334out:
3335 if (msg->data)
3336 return msg->area;
3337 else {
3338 if (addr)
3339 s->check.addr = sk;
3340 if (port)
3341 s->check.port = new_port;
3342 }
3343 return NULL;
3344}
3345
Baptiste Assmann14e40142015-04-14 01:13:07 +02003346/*
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003347 * This function update a server's addr and port only for AF_INET and AF_INET6 families.
3348 *
3349 * Caller can pass its name through <updater> to get it integrated in the response message
3350 * returned by the function.
3351 *
3352 * The function first does the following, in that order:
3353 * - validates the new addr and/or port
3354 * - checks if an update is required (new IP or port is different than current ones)
3355 * - checks the update is allowed:
3356 * - don't switch from/to a family other than AF_INET4 and AF_INET6
3357 * - allow all changes if no CHECKS are configured
3358 * - if CHECK is configured:
3359 * - if switch to port map (SRV_F_MAPPORTS), ensure health check have their own ports
3360 * - applies required changes to both ADDR and PORT if both 'required' and 'allowed'
3361 * conditions are met
Willy Tarreau46b7f532018-08-21 11:54:26 +02003362 *
3363 * Must be called with the server lock held.
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003364 */
Christopher Faulet69beaa92021-02-16 12:07:47 +01003365const char *srv_update_addr_port(struct server *s, const char *addr, const char *port, char *updater)
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003366{
3367 struct sockaddr_storage sa;
3368 int ret, port_change_required;
3369 char current_addr[INET6_ADDRSTRLEN];
David Carlier327298c2016-11-20 10:42:38 +00003370 uint16_t current_port, new_port;
Willy Tarreau83061a82018-07-13 11:56:34 +02003371 struct buffer *msg;
Olivier Houchard4e694042017-03-14 20:01:29 +01003372 int changed = 0;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003373
3374 msg = get_trash_chunk();
3375 chunk_reset(msg);
3376
3377 if (addr) {
3378 memset(&sa, 0, sizeof(struct sockaddr_storage));
3379 if (str2ip2(addr, &sa, 0) == NULL) {
3380 chunk_printf(msg, "Invalid addr '%s'", addr);
3381 goto out;
3382 }
3383
3384 /* changes are allowed on AF_INET* families only */
3385 if ((sa.ss_family != AF_INET) && (sa.ss_family != AF_INET6)) {
3386 chunk_printf(msg, "Update to families other than AF_INET and AF_INET6 supported only through configuration file");
3387 goto out;
3388 }
3389
3390 /* collecting data currently setup */
3391 memset(current_addr, '\0', sizeof(current_addr));
3392 ret = addr_to_str(&s->addr, current_addr, sizeof(current_addr));
3393 /* changes are allowed on AF_INET* families only */
3394 if ((ret != AF_INET) && (ret != AF_INET6)) {
3395 chunk_printf(msg, "Update for the current server address family is only supported through configuration file");
3396 goto out;
3397 }
3398
3399 /* applying ADDR changes if required and allowed
3400 * ipcmp returns 0 when both ADDR are the same
3401 */
Amaury Denoyelle21e611d2022-12-01 17:46:45 +01003402 if (ipcmp(&s->addr, &sa, 0) == 0) {
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003403 chunk_appendf(msg, "no need to change the addr");
3404 goto port;
3405 }
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003406 ipcpy(&sa, &s->addr);
Olivier Houchard4e694042017-03-14 20:01:29 +01003407 changed = 1;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003408
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003409 /* update report for caller */
3410 chunk_printf(msg, "IP changed from '%s' to '%s'", current_addr, addr);
3411 }
3412
3413 port:
3414 if (port) {
3415 char sign = '\0';
3416 char *endptr;
3417
3418 if (addr)
3419 chunk_appendf(msg, ", ");
3420
3421 /* collecting data currently setup */
Willy Tarreau04276f32017-01-06 17:41:29 +01003422 current_port = s->svc_port;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003423
3424 /* check if PORT change is required */
3425 port_change_required = 0;
3426
3427 sign = *port;
Ryabin Sergey77ee7522017-01-11 19:39:55 +04003428 errno = 0;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003429 new_port = strtol(port, &endptr, 10);
3430 if ((errno != 0) || (port == endptr)) {
3431 chunk_appendf(msg, "problem converting port '%s' to an int", port);
3432 goto out;
3433 }
3434
3435 /* check if caller triggers a port mapped or offset */
3436 if (sign == '-' || (sign == '+')) {
3437 /* check if server currently uses port map */
3438 if (!(s->flags & SRV_F_MAPPORTS)) {
3439 /* switch from fixed port to port map mandatorily triggers
3440 * a port change */
3441 port_change_required = 1;
3442 /* check is configured
3443 * we're switching from a fixed port to a SRV_F_MAPPORTS (mapped) port
3444 * prevent PORT change if check doesn't have it's dedicated port while switching
3445 * to port mapping */
William Dauchy69f118d2021-02-03 22:30:07 +01003446 if (!s->check.port) {
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003447 chunk_appendf(msg, "can't change <port> to port map because it is incompatible with current health check port configuration (use 'port' statement from the 'server' directive.");
3448 goto out;
3449 }
3450 }
3451 /* we're already using port maps */
3452 else {
3453 port_change_required = current_port != new_port;
3454 }
3455 }
3456 /* fixed port */
3457 else {
3458 port_change_required = current_port != new_port;
3459 }
3460
3461 /* applying PORT changes if required and update response message */
3462 if (port_change_required) {
3463 /* apply new port */
Willy Tarreau04276f32017-01-06 17:41:29 +01003464 s->svc_port = new_port;
Olivier Houchard4e694042017-03-14 20:01:29 +01003465 changed = 1;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003466
3467 /* prepare message */
3468 chunk_appendf(msg, "port changed from '");
3469 if (s->flags & SRV_F_MAPPORTS)
3470 chunk_appendf(msg, "+");
3471 chunk_appendf(msg, "%d' to '", current_port);
3472
3473 if (sign == '-') {
3474 s->flags |= SRV_F_MAPPORTS;
3475 chunk_appendf(msg, "%c", sign);
3476 /* just use for result output */
3477 new_port = -new_port;
3478 }
3479 else if (sign == '+') {
3480 s->flags |= SRV_F_MAPPORTS;
3481 chunk_appendf(msg, "%c", sign);
3482 }
3483 else {
3484 s->flags &= ~SRV_F_MAPPORTS;
3485 }
3486
3487 chunk_appendf(msg, "%d'", new_port);
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003488 }
3489 else {
3490 chunk_appendf(msg, "no need to change the port");
3491 }
3492 }
3493
3494out:
William Dauchy6318d332020-05-02 21:52:36 +02003495 if (changed) {
3496 /* force connection cleanup on the given server */
3497 srv_cleanup_connections(s);
Olivier Houchard4e694042017-03-14 20:01:29 +01003498 srv_set_dyncookie(s);
Amaury Denoyelle8ff04342021-06-08 15:19:51 +02003499 srv_set_addr_desc(s, 1);
William Dauchy6318d332020-05-02 21:52:36 +02003500 }
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003501 if (updater)
3502 chunk_appendf(msg, " by '%s'", updater);
3503 chunk_appendf(msg, "\n");
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003504 return msg->area;
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003505}
3506
Christopher Faulet5efdef22021-03-11 18:03:21 +01003507/*
3508 * update server status based on result of SRV resolution
3509 * returns:
3510 * 0 if server status is updated
3511 * 1 if server status has not changed
3512 *
3513 * Must be called with the server lock held.
3514 */
3515int srvrq_update_srv_status(struct server *s, int has_no_ip)
3516{
3517 if (!s->srvrq)
3518 return 1;
3519
3520 /* since this server has an IP, it can go back in production */
3521 if (has_no_ip == 0) {
3522 srv_clr_admin_flag(s, SRV_ADMF_RMAINT);
3523 return 1;
3524 }
3525
3526 if (s->next_admin & SRV_ADMF_RMAINT)
3527 return 1;
3528
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02003529 srv_set_admin_flag(s, SRV_ADMF_RMAINT, SRV_ADM_STCHGC_DNS_NOENT);
Christopher Faulet5efdef22021-03-11 18:03:21 +01003530 return 0;
3531}
Baptiste Assmannd458adc2016-08-02 08:18:55 +02003532
3533/*
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003534 * update server status based on result of name resolution
3535 * returns:
3536 * 0 if server status is updated
3537 * 1 if server status has not changed
Willy Tarreau46b7f532018-08-21 11:54:26 +02003538 *
3539 * Must be called with the server lock held.
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003540 */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003541int snr_update_srv_status(struct server *s, int has_no_ip)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003542{
Emeric Brun750fe792020-12-23 16:51:12 +01003543 struct resolvers *resolvers = s->resolvers;
Christopher Fauletd83a6df2021-03-12 10:23:05 +01003544 struct resolv_resolution *resolution = (s->resolv_requester ? s->resolv_requester->resolution : NULL);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003545 int exp;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003546
Jerome Magnin012261a2020-07-28 13:38:22 +02003547 /* If resolution is NULL we're dealing with SRV records Additional records */
Christopher Faulet5efdef22021-03-11 18:03:21 +01003548 if (resolution == NULL)
3549 return srvrq_update_srv_status(s, has_no_ip);
Jerome Magnin012261a2020-07-28 13:38:22 +02003550
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003551 switch (resolution->status) {
3552 case RSLV_STATUS_NONE:
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003553 /* status when HAProxy has just (re)started.
3554 * Nothing to do, since the task is already automatically started */
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003555 break;
3556
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003557 case RSLV_STATUS_VALID:
3558 /*
3559 * resume health checks
3560 * server will be turned back on if health check is safe
3561 */
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003562 if (has_no_ip) {
Emeric Brun52a91d32017-08-31 14:41:55 +02003563 if (s->next_admin & SRV_ADMF_RMAINT)
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003564 return 1;
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02003565 srv_set_admin_flag(s, SRV_ADMF_RMAINT, SRV_ADM_STCHGC_DNS_NOIP);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003566 return 0;
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003567 }
Christopher Faulet67957bd2017-09-27 11:00:59 +02003568
Emeric Brun52a91d32017-08-31 14:41:55 +02003569 if (!(s->next_admin & SRV_ADMF_RMAINT))
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003570 return 1;
3571 srv_clr_admin_flag(s, SRV_ADMF_RMAINT);
3572 chunk_printf(&trash, "Server %s/%s administratively READY thanks to valid DNS answer",
3573 s->proxy->id, s->id);
3574
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003575 ha_warning("%s.\n", trash.area);
3576 send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.area);
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003577 return 0;
3578
3579 case RSLV_STATUS_NX:
3580 /* stop server if resolution is NX for a long enough period */
Christopher Faulet67957bd2017-09-27 11:00:59 +02003581 exp = tick_add(resolution->last_valid, resolvers->hold.nx);
3582 if (!tick_is_expired(exp, now_ms))
3583 break;
3584
3585 if (s->next_admin & SRV_ADMF_RMAINT)
3586 return 1;
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02003587 srv_set_admin_flag(s, SRV_ADMF_RMAINT, SRV_ADM_STCHGC_DNS_NX);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003588 return 0;
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003589
3590 case RSLV_STATUS_TIMEOUT:
3591 /* stop server if resolution is TIMEOUT for a long enough period */
Christopher Faulet67957bd2017-09-27 11:00:59 +02003592 exp = tick_add(resolution->last_valid, resolvers->hold.timeout);
3593 if (!tick_is_expired(exp, now_ms))
3594 break;
3595
3596 if (s->next_admin & SRV_ADMF_RMAINT)
3597 return 1;
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02003598 srv_set_admin_flag(s, SRV_ADMF_RMAINT, SRV_ADM_STCHGC_DNS_TIMEOUT);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003599 return 0;
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003600
3601 case RSLV_STATUS_REFUSED:
3602 /* stop server if resolution is REFUSED for a long enough period */
Christopher Faulet67957bd2017-09-27 11:00:59 +02003603 exp = tick_add(resolution->last_valid, resolvers->hold.refused);
3604 if (!tick_is_expired(exp, now_ms))
3605 break;
3606
3607 if (s->next_admin & SRV_ADMF_RMAINT)
3608 return 1;
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02003609 srv_set_admin_flag(s, SRV_ADMF_RMAINT, SRV_ADM_STCHGC_DNS_REFUSED);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003610 return 0;
Baptiste Assmann3b9fe9f2016-11-02 22:58:18 +01003611
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003612 default:
Christopher Faulet67957bd2017-09-27 11:00:59 +02003613 /* stop server if resolution failed for a long enough period */
3614 exp = tick_add(resolution->last_valid, resolvers->hold.other);
3615 if (!tick_is_expired(exp, now_ms))
3616 break;
3617
3618 if (s->next_admin & SRV_ADMF_RMAINT)
3619 return 1;
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02003620 srv_set_admin_flag(s, SRV_ADMF_RMAINT, SRV_ADM_STCHGC_DNS_UNSPEC);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003621 return 0;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003622 }
3623
3624 return 1;
3625}
3626
3627/*
3628 * Server Name Resolution valid response callback
3629 * It expects:
3630 * - <nameserver>: the name server which answered the valid response
3631 * - <response>: buffer containing a valid DNS response
3632 * - <response_len>: size of <response>
3633 * It performs the following actions:
3634 * - ignore response if current ip found and server family not met
3635 * - update with first new ip found if family is met and current IP is not found
3636 * returns:
3637 * 0 on error
3638 * 1 when no error or safe ignore
Olivier Houchard28381072017-11-06 17:30:28 +01003639 *
3640 * Must be called with server lock held
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003641 */
Emeric Brun08622d32020-12-23 17:41:43 +01003642int snr_resolution_cb(struct resolv_requester *requester, struct dns_counters *counters)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003643{
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003644 struct server *s = NULL;
Emeric Brun08622d32020-12-23 17:41:43 +01003645 struct resolv_resolution *resolution = NULL;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003646 void *serverip, *firstip;
3647 short server_sin_family, firstip_sin_family;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003648 int ret;
Willy Tarreau83061a82018-07-13 11:56:34 +02003649 struct buffer *chk = get_trash_chunk();
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003650 int has_no_ip = 0;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003651
Christopher Faulet67957bd2017-09-27 11:00:59 +02003652 s = objt_server(requester->owner);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003653 if (!s)
3654 return 1;
3655
Christopher Faulet49531e82021-03-10 15:07:27 +01003656 if (s->srvrq) {
Emeric Brun34067662021-06-11 10:48:45 +02003657 /* If DNS resolution is disabled ignore it.
3658 * This is the case if the server was associated to
3659 * a SRV record and this record is now expired.
Christopher Faulet49531e82021-03-10 15:07:27 +01003660 */
Emeric Brun34067662021-06-11 10:48:45 +02003661 if (s->flags & SRV_F_NO_RESOLUTION)
Christopher Faulet49531e82021-03-10 15:07:27 +01003662 return 1;
3663 }
3664
Christopher Fauletd83a6df2021-03-12 10:23:05 +01003665 resolution = (s->resolv_requester ? s->resolv_requester->resolution : NULL);
Christopher Faulet49531e82021-03-10 15:07:27 +01003666 if (!resolution)
3667 return 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003668
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003669 /* initializing variables */
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003670 firstip = NULL; /* pointer to the first valid response found */
3671 /* it will be used as the new IP if a change is required */
3672 firstip_sin_family = AF_UNSPEC;
3673 serverip = NULL; /* current server IP address */
3674
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003675 /* initializing server IP pointer */
3676 server_sin_family = s->addr.ss_family;
3677 switch (server_sin_family) {
3678 case AF_INET:
3679 serverip = &((struct sockaddr_in *)&s->addr)->sin_addr.s_addr;
3680 break;
3681
3682 case AF_INET6:
3683 serverip = &((struct sockaddr_in6 *)&s->addr)->sin6_addr.s6_addr;
3684 break;
3685
Willy Tarreau3acfcd12017-01-06 19:18:32 +01003686 case AF_UNSPEC:
3687 break;
3688
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003689 default:
3690 goto invalid;
3691 }
3692
Emeric Brund30e9a12020-12-23 18:49:16 +01003693 ret = resolv_get_ip_from_response(&resolution->response, &s->resolv_opts,
3694 serverip, server_sin_family, &firstip,
3695 &firstip_sin_family, s);
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003696
3697 switch (ret) {
Emeric Brun456de772020-12-23 18:17:31 +01003698 case RSLV_UPD_NO:
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003699 goto update_status;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003700
Emeric Brun456de772020-12-23 18:17:31 +01003701 case RSLV_UPD_SRVIP_NOT_FOUND:
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003702 goto save_ip;
3703
Emeric Brun456de772020-12-23 18:17:31 +01003704 case RSLV_UPD_NO_IP_FOUND:
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003705 has_no_ip = 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003706 goto update_status;
Baptiste Assmann0453a1d2015-09-09 00:51:08 +02003707
Emeric Brun456de772020-12-23 18:17:31 +01003708 case RSLV_UPD_NAME_ERROR:
Baptiste Assmannfad03182015-10-28 02:03:32 +01003709 /* update resolution status to OTHER error type */
Christopher Faulet67957bd2017-09-27 11:00:59 +02003710 resolution->status = RSLV_STATUS_OTHER;
Christopher Faulet07ecff52021-06-24 15:33:52 +02003711 has_no_ip = 1;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003712 goto update_status;
Baptiste Assmannfad03182015-10-28 02:03:32 +01003713
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003714 default:
Christopher Faulet07ecff52021-06-24 15:33:52 +02003715 has_no_ip = 1;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003716 goto invalid;
3717
3718 }
3719
3720 save_ip:
Emeric Brun50c870e2021-01-04 10:40:46 +01003721 if (counters) {
Emeric Brund174f0e2021-10-29 17:30:41 +02003722 counters->app.resolver.update++;
Christopher Faulet67957bd2017-09-27 11:00:59 +02003723 /* save the first ip we found */
Emeric Brun50c870e2021-01-04 10:40:46 +01003724 chunk_printf(chk, "%s/%s", counters->pid, counters->id);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003725 }
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003726 else
3727 chunk_printf(chk, "DNS cache");
Christopher Faulet69beaa92021-02-16 12:07:47 +01003728 srv_update_addr(s, firstip, firstip_sin_family, (char *) chk->area);
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003729
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003730 update_status:
Christopher Fauleta8ce4972021-06-24 15:26:03 +02003731 if (!snr_update_srv_status(s, has_no_ip) && has_no_ip)
3732 memset(&s->addr, 0, sizeof(s->addr));
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003733 return 1;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003734
3735 invalid:
Emeric Brun50c870e2021-01-04 10:40:46 +01003736 if (counters) {
Emeric Brund174f0e2021-10-29 17:30:41 +02003737 counters->app.resolver.invalid++;
Christopher Faulet67957bd2017-09-27 11:00:59 +02003738 goto update_status;
Christopher Faulet3bbd65b2017-09-15 11:55:45 +02003739 }
Christopher Faulet07ecff52021-06-24 15:33:52 +02003740 if (!snr_update_srv_status(s, has_no_ip) && has_no_ip)
3741 memset(&s->addr, 0, sizeof(s->addr));
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003742 return 0;
3743}
3744
3745/*
Baptiste Assmannb4badf72020-11-19 22:38:33 +01003746 * SRV record error management callback
3747 * returns:
Emeric Brun12ca6582021-06-10 15:25:25 +02003748 * 0 if we can trash answser items.
3749 * 1 when safely ignored and we must kept answer items
Baptiste Assmannb4badf72020-11-19 22:38:33 +01003750 *
3751 * Grabs the server's lock.
3752 */
3753int srvrq_resolution_error_cb(struct resolv_requester *requester, int error_code)
3754{
Baptiste Assmannb4badf72020-11-19 22:38:33 +01003755 struct resolv_srvrq *srvrq;
3756 struct resolv_resolution *res;
3757 struct resolvers *resolvers;
3758 int exp;
3759
3760 /* SRV records */
3761 srvrq = objt_resolv_srvrq(requester->owner);
3762 if (!srvrq)
Emeric Brun12ca6582021-06-10 15:25:25 +02003763 return 0;
Baptiste Assmannb4badf72020-11-19 22:38:33 +01003764
3765 resolvers = srvrq->resolvers;
3766 res = requester->resolution;
3767
3768 switch (res->status) {
3769
3770 case RSLV_STATUS_NX:
3771 /* stop server if resolution is NX for a long enough period */
3772 exp = tick_add(res->last_valid, resolvers->hold.nx);
3773 if (!tick_is_expired(exp, now_ms))
3774 return 1;
3775 break;
3776
3777 case RSLV_STATUS_TIMEOUT:
3778 /* stop server if resolution is TIMEOUT for a long enough period */
3779 exp = tick_add(res->last_valid, resolvers->hold.timeout);
3780 if (!tick_is_expired(exp, now_ms))
3781 return 1;
3782 break;
3783
3784 case RSLV_STATUS_REFUSED:
3785 /* stop server if resolution is REFUSED for a long enough period */
3786 exp = tick_add(res->last_valid, resolvers->hold.refused);
3787 if (!tick_is_expired(exp, now_ms))
3788 return 1;
3789 break;
3790
3791 default:
3792 /* stop server if resolution failed for a long enough period */
3793 exp = tick_add(res->last_valid, resolvers->hold.other);
3794 if (!tick_is_expired(exp, now_ms))
3795 return 1;
3796 }
3797
Emeric Brun34067662021-06-11 10:48:45 +02003798 /* Remove any associated server ref */
Willy Tarreau6878f802021-10-20 14:07:31 +02003799 resolv_detach_from_resolution_answer_items(res, requester);
Baptiste Assmannb4badf72020-11-19 22:38:33 +01003800
Emeric Brun12ca6582021-06-10 15:25:25 +02003801 return 0;
Baptiste Assmannb4badf72020-11-19 22:38:33 +01003802}
3803
3804/*
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003805 * Server Name Resolution error management callback
3806 * returns:
Emeric Brun12ca6582021-06-10 15:25:25 +02003807 * 0 if we can trash answser items.
3808 * 1 when safely ignored and we must kept answer items
Willy Tarreau46b7f532018-08-21 11:54:26 +02003809 *
3810 * Grabs the server's lock.
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003811 */
Emeric Brun08622d32020-12-23 17:41:43 +01003812int snr_resolution_error_cb(struct resolv_requester *requester, int error_code)
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003813{
Christopher Faulet67957bd2017-09-27 11:00:59 +02003814 struct server *s;
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003815
Christopher Faulet67957bd2017-09-27 11:00:59 +02003816 s = objt_server(requester->owner);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003817 if (!s)
Emeric Brun12ca6582021-06-10 15:25:25 +02003818 return 0;
3819
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003820 HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
Emeric Brun12ca6582021-06-10 15:25:25 +02003821 if (!snr_update_srv_status(s, 1)) {
Christopher Faulet5130c212021-03-10 20:31:40 +01003822 memset(&s->addr, 0, sizeof(s->addr));
Emeric Brun12ca6582021-06-10 15:25:25 +02003823 HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
Willy Tarreau6878f802021-10-20 14:07:31 +02003824 resolv_detach_from_resolution_answer_items(requester->resolution, requester);
Emeric Brun12ca6582021-06-10 15:25:25 +02003825 return 0;
3826 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003827 HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
Emeric Brun12ca6582021-06-10 15:25:25 +02003828
Baptiste Assmanna68ca962015-04-14 01:15:08 +02003829 return 1;
3830}
3831
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003832/*
3833 * Function to check if <ip> is already affected to a server in the backend
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003834 * which owns <srv> and is up.
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003835 * It returns a pointer to the first server found or NULL if <ip> is not yet
3836 * assigned.
Olivier Houchard28381072017-11-06 17:30:28 +01003837 *
3838 * Must be called with server lock held
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003839 */
3840struct server *snr_check_ip_callback(struct server *srv, void *ip, unsigned char *ip_family)
3841{
3842 struct server *tmpsrv;
3843 struct proxy *be;
3844
3845 if (!srv)
3846 return NULL;
3847
3848 be = srv->proxy;
3849 for (tmpsrv = be->srv; tmpsrv; tmpsrv = tmpsrv->next) {
Emeric Brune9fd6b52017-11-02 17:20:39 +01003850 /* we found the current server is the same, ignore it */
3851 if (srv == tmpsrv)
3852 continue;
3853
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003854 /* We want to compare the IP in the record with the IP of the servers in the
3855 * same backend, only if:
3856 * * DNS resolution is enabled on the server
3857 * * the hostname used for the resolution by our server is the same than the
3858 * one used for the server found in the backend
3859 * * the server found in the backend is not our current server
3860 */
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003861 HA_SPIN_LOCK(SERVER_LOCK, &tmpsrv->lock);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003862 if ((tmpsrv->hostname_dn == NULL) ||
3863 (srv->hostname_dn_len != tmpsrv->hostname_dn_len) ||
Christopher Faulet59b29252021-03-16 11:21:04 +01003864 (strcasecmp(srv->hostname_dn, tmpsrv->hostname_dn) != 0) ||
Emeric Brune9fd6b52017-11-02 17:20:39 +01003865 (srv->puid == tmpsrv->puid)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003866 HA_SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock);
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003867 continue;
Emeric Brune9fd6b52017-11-02 17:20:39 +01003868 }
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003869
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003870 /* If the server has been taken down, don't consider it */
Emeric Brune9fd6b52017-11-02 17:20:39 +01003871 if (tmpsrv->next_admin & SRV_ADMF_RMAINT) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003872 HA_SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock);
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003873 continue;
Emeric Brune9fd6b52017-11-02 17:20:39 +01003874 }
Olivier Houcharda8c6db82017-07-06 18:46:47 +02003875
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003876 /* At this point, we have 2 different servers using the same DNS hostname
3877 * for their respective resolution.
3878 */
3879 if (*ip_family == tmpsrv->addr.ss_family &&
3880 ((tmpsrv->addr.ss_family == AF_INET &&
3881 memcmp(ip, &((struct sockaddr_in *)&tmpsrv->addr)->sin_addr, 4) == 0) ||
3882 (tmpsrv->addr.ss_family == AF_INET6 &&
3883 memcmp(ip, &((struct sockaddr_in6 *)&tmpsrv->addr)->sin6_addr, 16) == 0))) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003884 HA_SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock);
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003885 return tmpsrv;
3886 }
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003887 HA_SPIN_UNLOCK(SERVER_LOCK, &tmpsrv->lock);
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003888 }
3889
Emeric Brune9fd6b52017-11-02 17:20:39 +01003890
Baptiste Assmannfb7091e2017-05-03 15:43:12 +02003891 return NULL;
3892}
3893
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003894/* Sets the server's address (srv->addr) from srv->hostname using the libc's
3895 * resolver. This is suited for initial address configuration. Returns 0 on
3896 * success otherwise a non-zero error code. In case of error, *err_code, if
3897 * not NULL, is filled up.
3898 */
3899int srv_set_addr_via_libc(struct server *srv, int *err_code)
3900{
3901 if (str2ip2(srv->hostname, &srv->addr, 1) == NULL) {
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003902 if (err_code)
Willy Tarreau465b6e52016-11-07 19:19:22 +01003903 *err_code |= ERR_WARN;
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003904 return 1;
3905 }
3906 return 0;
3907}
3908
Frédéric Lécailleb418c122017-04-26 11:24:02 +02003909/* Set the server's FDQN (->hostname) from <hostname>.
3910 * Returns -1 if failed, 0 if not.
Willy Tarreau46b7f532018-08-21 11:54:26 +02003911 *
3912 * Must be called with the server lock held.
Frédéric Lécailleb418c122017-04-26 11:24:02 +02003913 */
Emeric Brun08622d32020-12-23 17:41:43 +01003914int srv_set_fqdn(struct server *srv, const char *hostname, int resolv_locked)
Frédéric Lécailleb418c122017-04-26 11:24:02 +02003915{
Emeric Brun08622d32020-12-23 17:41:43 +01003916 struct resolv_resolution *resolution;
Christopher Faulet67957bd2017-09-27 11:00:59 +02003917 char *hostname_dn;
3918 int hostname_len, hostname_dn_len;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003919
Frédéric Lécaille5afb3cf2018-08-21 15:04:23 +02003920 /* Note that the server lock is already held. */
3921 if (!srv->resolvers)
3922 return -1;
3923
Emeric Brun08622d32020-12-23 17:41:43 +01003924 if (!resolv_locked)
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003925 HA_SPIN_LOCK(DNS_LOCK, &srv->resolvers->lock);
Christopher Fauletd83a6df2021-03-12 10:23:05 +01003926 /* run time DNS/SRV resolution was not active for this server
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003927 * and we can't enable it at run time for now.
3928 */
Christopher Fauletd83a6df2021-03-12 10:23:05 +01003929 if (!srv->resolv_requester && !srv->srvrq)
Christopher Fauletb2812a62017-10-04 16:17:58 +02003930 goto err;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003931
3932 chunk_reset(&trash);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003933 hostname_len = strlen(hostname);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02003934 hostname_dn = trash.area;
Willy Tarreaubf9498a2021-10-14 07:49:49 +02003935 hostname_dn_len = resolv_str_to_dn_label(hostname, hostname_len,
Emeric Brund30e9a12020-12-23 18:49:16 +01003936 hostname_dn, trash.size);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003937 if (hostname_dn_len == -1)
Christopher Fauletb2812a62017-10-04 16:17:58 +02003938 goto err;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003939
Christopher Fauletd83a6df2021-03-12 10:23:05 +01003940 resolution = (srv->resolv_requester ? srv->resolv_requester->resolution : NULL);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003941 if (resolution &&
3942 resolution->hostname_dn &&
Christopher Faulet59b29252021-03-16 11:21:04 +01003943 resolution->hostname_dn_len == hostname_dn_len &&
3944 strcasecmp(resolution->hostname_dn, hostname_dn) == 0)
Christopher Fauletb2812a62017-10-04 16:17:58 +02003945 goto end;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003946
Willy Tarreau6878f802021-10-20 14:07:31 +02003947 resolv_unlink_resolution(srv->resolv_requester);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003948
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003949 free(srv->hostname);
3950 free(srv->hostname_dn);
Christopher Faulet67957bd2017-09-27 11:00:59 +02003951 srv->hostname = strdup(hostname);
3952 srv->hostname_dn = strdup(hostname_dn);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003953 srv->hostname_dn_len = hostname_dn_len;
3954 if (!srv->hostname || !srv->hostname_dn)
Christopher Fauletb2812a62017-10-04 16:17:58 +02003955 goto err;
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003956
Baptiste Assmann13a92322019-06-07 09:40:55 +02003957 if (srv->flags & SRV_F_NO_RESOLUTION)
3958 goto end;
3959
Emeric Brund30e9a12020-12-23 18:49:16 +01003960 if (resolv_link_resolution(srv, OBJ_TYPE_SERVER, 1) == -1)
Christopher Fauletb2812a62017-10-04 16:17:58 +02003961 goto err;
3962
3963 end:
Emeric Brun08622d32020-12-23 17:41:43 +01003964 if (!resolv_locked)
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003965 HA_SPIN_UNLOCK(DNS_LOCK, &srv->resolvers->lock);
Baptiste Assmann201c07f2017-05-22 15:17:15 +02003966 return 0;
Christopher Fauletb2812a62017-10-04 16:17:58 +02003967
3968 err:
Emeric Brun08622d32020-12-23 17:41:43 +01003969 if (!resolv_locked)
Christopher Faulet2a944ee2017-11-07 10:42:54 +01003970 HA_SPIN_UNLOCK(DNS_LOCK, &srv->resolvers->lock);
Christopher Fauletb2812a62017-10-04 16:17:58 +02003971 return -1;
Frédéric Lécailleb418c122017-04-26 11:24:02 +02003972}
3973
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01003974/* Sets the server's address (srv->addr) from srv->lastaddr which was filled
3975 * from the state file. This is suited for initial address configuration.
3976 * Returns 0 on success otherwise a non-zero error code. In case of error,
3977 * *err_code, if not NULL, is filled up.
3978 */
3979static int srv_apply_lastaddr(struct server *srv, int *err_code)
3980{
3981 if (!str2ip2(srv->lastaddr, &srv->addr, 0)) {
3982 if (err_code)
3983 *err_code |= ERR_WARN;
3984 return 1;
3985 }
3986 return 0;
3987}
3988
Willy Tarreau25e51522016-11-04 15:10:17 +01003989/* returns 0 if no error, otherwise a combination of ERR_* flags */
3990static int srv_iterate_initaddr(struct server *srv)
3991{
Christopher Fauletac1c60fd2020-10-26 10:31:17 +01003992 char *name = srv->hostname;
Willy Tarreau25e51522016-11-04 15:10:17 +01003993 int return_code = 0;
3994 int err_code;
3995 unsigned int methods;
3996
Christopher Fauletac1c60fd2020-10-26 10:31:17 +01003997 /* If no addr and no hostname set, get the name from the DNS SRV request */
3998 if (!name && srv->srvrq)
3999 name = srv->srvrq->name;
4000
Willy Tarreau25e51522016-11-04 15:10:17 +01004001 methods = srv->init_addr_methods;
Christopher Fauletac1c60fd2020-10-26 10:31:17 +01004002 if (!methods) {
4003 /* otherwise default to "last,libc" */
Willy Tarreau25e51522016-11-04 15:10:17 +01004004 srv_append_initaddr(&methods, SRV_IADDR_LAST);
4005 srv_append_initaddr(&methods, SRV_IADDR_LIBC);
Christopher Fauletac1c60fd2020-10-26 10:31:17 +01004006 if (srv->resolvers_id) {
4007 /* dns resolution is configured, add "none" to not fail on startup */
4008 srv_append_initaddr(&methods, SRV_IADDR_NONE);
4009 }
Willy Tarreau25e51522016-11-04 15:10:17 +01004010 }
4011
Willy Tarreau3eed10e2016-11-07 21:03:16 +01004012 /* "-dr" : always append "none" so that server addresses resolution
4013 * failures are silently ignored, this is convenient to validate some
4014 * configs out of their environment.
4015 */
4016 if (global.tune.options & GTUNE_RESOLVE_DONTFAIL)
4017 srv_append_initaddr(&methods, SRV_IADDR_NONE);
4018
Willy Tarreau25e51522016-11-04 15:10:17 +01004019 while (methods) {
4020 err_code = 0;
4021 switch (srv_get_next_initaddr(&methods)) {
4022 case SRV_IADDR_LAST:
4023 if (!srv->lastaddr)
4024 continue;
4025 if (srv_apply_lastaddr(srv, &err_code) == 0)
Olivier Houchard4e694042017-03-14 20:01:29 +01004026 goto out;
Willy Tarreau25e51522016-11-04 15:10:17 +01004027 return_code |= err_code;
4028 break;
4029
4030 case SRV_IADDR_LIBC:
4031 if (!srv->hostname)
4032 continue;
4033 if (srv_set_addr_via_libc(srv, &err_code) == 0)
Olivier Houchard4e694042017-03-14 20:01:29 +01004034 goto out;
Willy Tarreau25e51522016-11-04 15:10:17 +01004035 return_code |= err_code;
4036 break;
4037
Willy Tarreau37ebe122016-11-04 15:17:58 +01004038 case SRV_IADDR_NONE:
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02004039 srv_set_admin_flag(srv, SRV_ADMF_RMAINT, SRV_ADM_STCHGC_NONE);
Willy Tarreau465b6e52016-11-07 19:19:22 +01004040 if (return_code) {
Amaury Denoyelle9d0138a2021-05-28 11:01:52 +02004041 ha_warning("could not resolve address '%s', disabling server.\n",
4042 name);
Willy Tarreau465b6e52016-11-07 19:19:22 +01004043 }
Willy Tarreau37ebe122016-11-04 15:17:58 +01004044 return return_code;
4045
Willy Tarreau4310d362016-11-02 15:05:56 +01004046 case SRV_IADDR_IP:
4047 ipcpy(&srv->init_addr, &srv->addr);
4048 if (return_code) {
Amaury Denoyelle9d0138a2021-05-28 11:01:52 +02004049 ha_warning("could not resolve address '%s', falling back to configured address.\n",
4050 name);
Willy Tarreau4310d362016-11-02 15:05:56 +01004051 }
Olivier Houchard4e694042017-03-14 20:01:29 +01004052 goto out;
Willy Tarreau4310d362016-11-02 15:05:56 +01004053
Willy Tarreau25e51522016-11-04 15:10:17 +01004054 default: /* unhandled method */
4055 break;
4056 }
4057 }
4058
Amaury Denoyelle9d0138a2021-05-28 11:01:52 +02004059 if (!return_code)
4060 ha_alert("no method found to resolve address '%s'.\n", name);
4061 else
4062 ha_alert("could not resolve address '%s'.\n", name);
Willy Tarreau25e51522016-11-04 15:10:17 +01004063
4064 return_code |= ERR_ALERT | ERR_FATAL;
4065 return return_code;
Olivier Houchard4e694042017-03-14 20:01:29 +01004066out:
4067 srv_set_dyncookie(srv);
Amaury Denoyelle8ff04342021-06-08 15:19:51 +02004068 srv_set_addr_desc(srv, 1);
Olivier Houchard4e694042017-03-14 20:01:29 +01004069 return return_code;
Willy Tarreau25e51522016-11-04 15:10:17 +01004070}
4071
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01004072/*
4073 * This function parses all backends and all servers within each backend
4074 * and performs servers' addr resolution based on information provided by:
4075 * - configuration file
4076 * - server-state file (states provided by an 'old' haproxy process)
4077 *
4078 * Returns 0 if no error, otherwise, a combination of ERR_ flags.
4079 */
4080int srv_init_addr(void)
4081{
4082 struct proxy *curproxy;
4083 int return_code = 0;
4084
Olivier Houchardfbc74e82017-11-24 16:54:05 +01004085 curproxy = proxies_list;
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01004086 while (curproxy) {
4087 struct server *srv;
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01004088
4089 /* servers are in backend only */
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02004090 if (!(curproxy->cap & PR_CAP_BE) || (curproxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED)))
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01004091 goto srv_init_addr_next;
4092
Amaury Denoyelle9d0138a2021-05-28 11:01:52 +02004093 for (srv = curproxy->srv; srv; srv = srv->next) {
4094 set_usermsgs_ctx(srv->conf.file, srv->conf.line, &srv->obj_type);
Christopher Fauletac1c60fd2020-10-26 10:31:17 +01004095 if (srv->hostname || srv->srvrq)
Willy Tarreau3d609a72017-09-06 14:22:45 +02004096 return_code |= srv_iterate_initaddr(srv);
Amaury Denoyelle9d0138a2021-05-28 11:01:52 +02004097 reset_usermsgs_ctx();
4098 }
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01004099
4100 srv_init_addr_next:
4101 curproxy = curproxy->next;
4102 }
4103
4104 return return_code;
4105}
4106
Willy Tarreau46b7f532018-08-21 11:54:26 +02004107/*
4108 * Must be called with the server lock held.
4109 */
Christopher Faulet69beaa92021-02-16 12:07:47 +01004110const char *srv_update_fqdn(struct server *server, const char *fqdn, const char *updater, int resolv_locked)
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004111{
4112
Willy Tarreau83061a82018-07-13 11:56:34 +02004113 struct buffer *msg;
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004114
4115 msg = get_trash_chunk();
4116 chunk_reset(msg);
4117
Tim Duesterhuse5ff1412021-01-02 22:31:53 +01004118 if (server->hostname && strcmp(fqdn, server->hostname) == 0) {
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004119 chunk_appendf(msg, "no need to change the FDQN");
4120 goto out;
4121 }
4122
4123 if (strlen(fqdn) > DNS_MAX_NAME_SIZE || invalid_domainchar(fqdn)) {
4124 chunk_appendf(msg, "invalid fqdn '%s'", fqdn);
4125 goto out;
4126 }
4127
4128 chunk_appendf(msg, "%s/%s changed its FQDN from %s to %s",
4129 server->proxy->id, server->id, server->hostname, fqdn);
4130
Emeric Brun08622d32020-12-23 17:41:43 +01004131 if (srv_set_fqdn(server, fqdn, resolv_locked) < 0) {
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004132 chunk_reset(msg);
4133 chunk_appendf(msg, "could not update %s/%s FQDN",
4134 server->proxy->id, server->id);
4135 goto out;
4136 }
4137
4138 /* Flag as FQDN set from stats socket. */
Emeric Brun52a91d32017-08-31 14:41:55 +02004139 server->next_admin |= SRV_ADMF_HMAINT;
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004140
4141 out:
4142 if (updater)
4143 chunk_appendf(msg, " by '%s'", updater);
4144 chunk_appendf(msg, "\n");
4145
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004146 return msg->area;
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004147}
4148
4149
Willy Tarreau21b069d2016-11-23 17:15:08 +01004150/* Expects to find a backend and a server in <arg> under the form <backend>/<server>,
4151 * and returns the pointer to the server. Otherwise, display adequate error messages
Willy Tarreau3b6e5472016-11-24 15:53:53 +01004152 * on the CLI, sets the CLI's state to CLI_ST_PRINT and returns NULL. This is only
Willy Tarreau21b069d2016-11-23 17:15:08 +01004153 * used for CLI commands requiring a server name.
4154 * Important: the <arg> is modified to remove the '/'.
4155 */
4156struct server *cli_find_server(struct appctx *appctx, char *arg)
4157{
4158 struct proxy *px;
4159 struct server *sv;
4160 char *line;
4161
4162 /* split "backend/server" and make <line> point to server */
4163 for (line = arg; *line; line++)
4164 if (*line == '/') {
4165 *line++ = '\0';
4166 break;
4167 }
4168
4169 if (!*line || !*arg) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004170 cli_err(appctx, "Require 'backend/server'.\n");
Willy Tarreau21b069d2016-11-23 17:15:08 +01004171 return NULL;
4172 }
4173
4174 if (!get_backend_server(arg, line, &px, &sv)) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004175 cli_err(appctx, px ? "No such server.\n" : "No such backend.\n");
Willy Tarreau21b069d2016-11-23 17:15:08 +01004176 return NULL;
4177 }
4178
Christopher Fauletdfd10ab2021-10-06 14:24:19 +02004179 if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004180 cli_err(appctx, "Proxy is disabled.\n");
Willy Tarreau21b069d2016-11-23 17:15:08 +01004181 return NULL;
4182 }
4183
4184 return sv;
4185}
4186
William Lallemand222baf22016-11-19 02:00:33 +01004187
Willy Tarreau46b7f532018-08-21 11:54:26 +02004188/* grabs the server lock */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004189static int cli_parse_set_server(char **args, char *payload, struct appctx *appctx, void *private)
William Lallemand222baf22016-11-19 02:00:33 +01004190{
4191 struct server *sv;
4192 const char *warning;
4193
4194 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4195 return 1;
4196
4197 sv = cli_find_server(appctx, args[2]);
4198 if (!sv)
4199 return 1;
4200
4201 if (strcmp(args[3], "weight") == 0) {
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004202 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
William Lallemand222baf22016-11-19 02:00:33 +01004203 warning = server_parse_weight_change_request(sv, args[4]);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004204 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau9d008692019-08-09 11:21:01 +02004205 if (warning)
4206 cli_err(appctx, warning);
William Lallemand222baf22016-11-19 02:00:33 +01004207 }
4208 else if (strcmp(args[3], "state") == 0) {
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004209 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
William Lallemand222baf22016-11-19 02:00:33 +01004210 if (strcmp(args[4], "ready") == 0)
4211 srv_adm_set_ready(sv);
4212 else if (strcmp(args[4], "drain") == 0)
4213 srv_adm_set_drain(sv);
4214 else if (strcmp(args[4], "maint") == 0)
4215 srv_adm_set_maint(sv);
Willy Tarreau9d008692019-08-09 11:21:01 +02004216 else
4217 cli_err(appctx, "'set server <srv> state' expects 'ready', 'drain' and 'maint'.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004218 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Lallemand222baf22016-11-19 02:00:33 +01004219 }
4220 else if (strcmp(args[3], "health") == 0) {
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004221 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau9d008692019-08-09 11:21:01 +02004222 if (sv->track)
4223 cli_err(appctx, "cannot change health on a tracking server.\n");
William Lallemand222baf22016-11-19 02:00:33 +01004224 else if (strcmp(args[4], "up") == 0) {
4225 sv->check.health = sv->check.rise + sv->check.fall - 1;
Emeric Brun5a133512017-10-19 14:42:30 +02004226 srv_set_running(sv, "changed from CLI", NULL);
William Lallemand222baf22016-11-19 02:00:33 +01004227 }
4228 else if (strcmp(args[4], "stopping") == 0) {
4229 sv->check.health = sv->check.rise + sv->check.fall - 1;
Emeric Brun5a133512017-10-19 14:42:30 +02004230 srv_set_stopping(sv, "changed from CLI", NULL);
William Lallemand222baf22016-11-19 02:00:33 +01004231 }
4232 else if (strcmp(args[4], "down") == 0) {
4233 sv->check.health = 0;
Emeric Brun5a133512017-10-19 14:42:30 +02004234 srv_set_stopped(sv, "changed from CLI", NULL);
William Lallemand222baf22016-11-19 02:00:33 +01004235 }
Willy Tarreau9d008692019-08-09 11:21:01 +02004236 else
4237 cli_err(appctx, "'set server <srv> health' expects 'up', 'stopping', or 'down'.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004238 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Lallemand222baf22016-11-19 02:00:33 +01004239 }
4240 else if (strcmp(args[3], "agent") == 0) {
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004241 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau9d008692019-08-09 11:21:01 +02004242 if (!(sv->agent.state & CHK_ST_ENABLED))
4243 cli_err(appctx, "agent checks are not enabled on this server.\n");
William Lallemand222baf22016-11-19 02:00:33 +01004244 else if (strcmp(args[4], "up") == 0) {
4245 sv->agent.health = sv->agent.rise + sv->agent.fall - 1;
Emeric Brun5a133512017-10-19 14:42:30 +02004246 srv_set_running(sv, "changed from CLI", NULL);
William Lallemand222baf22016-11-19 02:00:33 +01004247 }
4248 else if (strcmp(args[4], "down") == 0) {
4249 sv->agent.health = 0;
Emeric Brun5a133512017-10-19 14:42:30 +02004250 srv_set_stopped(sv, "changed from CLI", NULL);
William Lallemand222baf22016-11-19 02:00:33 +01004251 }
Willy Tarreau9d008692019-08-09 11:21:01 +02004252 else
4253 cli_err(appctx, "'set server <srv> agent' expects 'up' or 'down'.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004254 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Lallemand222baf22016-11-19 02:00:33 +01004255 }
Misiek2da082d2017-01-09 09:40:42 +01004256 else if (strcmp(args[3], "agent-addr") == 0) {
William Dauchy7cabc062021-02-11 22:51:24 +01004257 char *addr = NULL;
4258 char *port = NULL;
4259 if (strlen(args[4]) == 0) {
4260 cli_err(appctx, "set server <b>/<s> agent-addr requires"
4261 " an address and optionally a port.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004262 goto out;
William Dauchy7cabc062021-02-11 22:51:24 +01004263 }
4264 addr = args[4];
4265 if (strcmp(args[5], "port") == 0)
4266 port = args[6];
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004267 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Christopher Faulet69beaa92021-02-16 12:07:47 +01004268 warning = srv_update_agent_addr_port(sv, addr, port);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004269 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Dauchy7cabc062021-02-11 22:51:24 +01004270 if (warning)
4271 cli_msg(appctx, LOG_WARNING, warning);
4272 }
4273 else if (strcmp(args[3], "agent-port") == 0) {
4274 char *port = NULL;
4275 if (strlen(args[4]) == 0) {
4276 cli_err(appctx, "set server <b>/<s> agent-port requires"
4277 " a port.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004278 goto out;
William Dauchy7cabc062021-02-11 22:51:24 +01004279 }
4280 port = args[4];
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004281 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Christopher Faulet69beaa92021-02-16 12:07:47 +01004282 warning = srv_update_agent_addr_port(sv, NULL, port);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004283 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Dauchy7cabc062021-02-11 22:51:24 +01004284 if (warning)
4285 cli_msg(appctx, LOG_WARNING, warning);
Misiek2da082d2017-01-09 09:40:42 +01004286 }
4287 else if (strcmp(args[3], "agent-send") == 0) {
Christopher Faulet0ba54bb2021-06-18 08:47:14 +02004288 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau9d008692019-08-09 11:21:01 +02004289 if (!(sv->agent.state & CHK_ST_ENABLED))
4290 cli_err(appctx, "agent checks are not enabled on this server.\n");
4291 else {
Christopher Faulet0ae3d1d2020-04-06 17:54:24 +02004292 if (!set_srv_agent_send(sv, args[4]))
Willy Tarreau9d008692019-08-09 11:21:01 +02004293 cli_err(appctx, "cannot allocate memory for new string.\n");
Misiek2da082d2017-01-09 09:40:42 +01004294 }
Christopher Faulet0ba54bb2021-06-18 08:47:14 +02004295 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Misiek2da082d2017-01-09 09:40:42 +01004296 }
William Dauchyb456e1f2021-02-11 22:51:23 +01004297 else if (strcmp(args[3], "check-addr") == 0) {
4298 char *addr = NULL;
4299 char *port = NULL;
4300 if (strlen(args[4]) == 0) {
4301 cli_err(appctx, "set server <b>/<s> check-addr requires"
4302 " an address and optionally a port.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004303 goto out;
William Lallemand222baf22016-11-19 02:00:33 +01004304 }
William Dauchyb456e1f2021-02-11 22:51:23 +01004305 addr = args[4];
4306 if (strcmp(args[5], "port") == 0)
4307 port = args[6];
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004308 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Christopher Faulet69beaa92021-02-16 12:07:47 +01004309 warning = srv_update_check_addr_port(sv, addr, port);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004310 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Dauchyb456e1f2021-02-11 22:51:23 +01004311 if (warning)
4312 cli_msg(appctx, LOG_WARNING, warning);
4313 }
4314 else if (strcmp(args[3], "check-port") == 0) {
4315 char *port = NULL;
4316 if (strlen(args[4]) == 0) {
4317 cli_err(appctx, "set server <b>/<s> check-port requires"
4318 " a port.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004319 goto out;
William Lallemand222baf22016-11-19 02:00:33 +01004320 }
William Dauchyb456e1f2021-02-11 22:51:23 +01004321 port = args[4];
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004322 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Christopher Faulet69beaa92021-02-16 12:07:47 +01004323 warning = srv_update_check_addr_port(sv, NULL, port);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004324 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Dauchyb456e1f2021-02-11 22:51:23 +01004325 if (warning)
4326 cli_msg(appctx, LOG_WARNING, warning);
William Lallemand222baf22016-11-19 02:00:33 +01004327 }
4328 else if (strcmp(args[3], "addr") == 0) {
4329 char *addr = NULL;
4330 char *port = NULL;
4331 if (strlen(args[4]) == 0) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004332 cli_err(appctx, "set server <b>/<s> addr requires an address and optionally a port.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004333 goto out;
William Lallemand222baf22016-11-19 02:00:33 +01004334 }
4335 else {
4336 addr = args[4];
4337 }
4338 if (strcmp(args[5], "port") == 0) {
4339 port = args[6];
4340 }
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004341 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Christopher Faulet69beaa92021-02-16 12:07:47 +01004342 warning = srv_update_addr_port(sv, addr, port, "stats socket command");
Willy Tarreau9d008692019-08-09 11:21:01 +02004343 if (warning)
4344 cli_msg(appctx, LOG_WARNING, warning);
William Lallemand222baf22016-11-19 02:00:33 +01004345 srv_clr_admin_flag(sv, SRV_ADMF_RMAINT);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004346 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Lallemand222baf22016-11-19 02:00:33 +01004347 }
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004348 else if (strcmp(args[3], "fqdn") == 0) {
4349 if (!*args[4]) {
Willy Tarreau9d008692019-08-09 11:21:01 +02004350 cli_err(appctx, "set server <b>/<s> fqdn requires a FQDN.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004351 goto out;
4352 }
4353 if (!sv->resolvers) {
4354 cli_err(appctx, "set server <b>/<s> fqdn failed because no resolution is configured.\n");
4355 goto out;
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004356 }
Christopher Fauleta386e782021-06-15 11:37:40 +02004357 if (sv->srvrq) {
4358 cli_err(appctx, "set server <b>/<s> fqdn failed because SRV resolution is configured.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004359 goto out;
Christopher Fauleta386e782021-06-15 11:37:40 +02004360 }
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004361 HA_SPIN_LOCK(DNS_LOCK, &sv->resolvers->lock);
4362 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Baptiste Assmann13a92322019-06-07 09:40:55 +02004363 /* ensure runtime resolver will process this new fqdn */
4364 if (sv->flags & SRV_F_NO_RESOLUTION) {
4365 sv->flags &= ~SRV_F_NO_RESOLUTION;
4366 }
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004367 warning = srv_update_fqdn(sv, args[4], "stats socket command", 1);
Christopher Faulet0ba54bb2021-06-18 08:47:14 +02004368 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004369 HA_SPIN_UNLOCK(DNS_LOCK, &sv->resolvers->lock);
Willy Tarreau9d008692019-08-09 11:21:01 +02004370 if (warning)
4371 cli_msg(appctx, LOG_WARNING, warning);
Frédéric Lécailleb418c122017-04-26 11:24:02 +02004372 }
William Dauchyf6370442020-11-14 19:25:33 +01004373 else if (strcmp(args[3], "ssl") == 0) {
4374#ifdef USE_OPENSSL
Amaury Denoyelleb89d3d32021-05-19 15:00:54 +02004375 if (sv->flags & SRV_F_DYNAMIC) {
4376 cli_err(appctx, "'set server <srv> ssl' not supported on dynamic servers\n");
4377 goto out;
4378 }
4379
William Dauchyf6370442020-11-14 19:25:33 +01004380 if (sv->ssl_ctx.ctx == NULL) {
4381 cli_err(appctx, "'set server <srv> ssl' cannot be set. "
4382 " default-server should define ssl settings\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004383 goto out;
4384 }
4385
4386 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
4387 if (strcmp(args[4], "on") == 0) {
Willy Tarreaua8a72c62021-10-06 11:48:34 +02004388 srv_set_ssl(sv, 1);
William Dauchyf6370442020-11-14 19:25:33 +01004389 } else if (strcmp(args[4], "off") == 0) {
Willy Tarreaua8a72c62021-10-06 11:48:34 +02004390 srv_set_ssl(sv, 0);
William Dauchyf6370442020-11-14 19:25:33 +01004391 } else {
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004392 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Dauchyf6370442020-11-14 19:25:33 +01004393 cli_err(appctx, "'set server <srv> ssl' expects 'on' or 'off'.\n");
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004394 goto out;
William Dauchyf6370442020-11-14 19:25:33 +01004395 }
4396 srv_cleanup_connections(sv);
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004397 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
William Dauchyf6370442020-11-14 19:25:33 +01004398 cli_msg(appctx, LOG_NOTICE, "server ssl setting updated.\n");
4399#else
4400 cli_msg(appctx, LOG_NOTICE, "server ssl setting not supported.\n");
4401#endif
4402 } else {
Willy Tarreau9d008692019-08-09 11:21:01 +02004403 cli_err(appctx,
William Dauchy3f4ec7d2021-02-15 17:22:16 +01004404 "usage: set server <backend>/<server> "
4405 "addr | agent | agent-addr | agent-port | agent-send | "
4406 "check-addr | check-port | fqdn | health | ssl | "
4407 "state | weight\n");
William Lallemand222baf22016-11-19 02:00:33 +01004408 }
Christopher Fauletc7b391a2021-06-15 12:01:29 +02004409 out:
William Lallemand222baf22016-11-19 02:00:33 +01004410 return 1;
4411}
4412
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004413static int cli_parse_get_weight(char **args, char *payload, struct appctx *appctx, void *private)
William Lallemand6b160942016-11-22 12:34:35 +01004414{
William Lallemand6b160942016-11-22 12:34:35 +01004415 struct proxy *px;
4416 struct server *sv;
4417 char *line;
4418
4419
4420 /* split "backend/server" and make <line> point to server */
4421 for (line = args[2]; *line; line++)
4422 if (*line == '/') {
4423 *line++ = '\0';
4424 break;
4425 }
4426
Willy Tarreau9d008692019-08-09 11:21:01 +02004427 if (!*line)
4428 return cli_err(appctx, "Require 'backend/server'.\n");
William Lallemand6b160942016-11-22 12:34:35 +01004429
Willy Tarreau9d008692019-08-09 11:21:01 +02004430 if (!get_backend_server(args[2], line, &px, &sv))
4431 return cli_err(appctx, px ? "No such server.\n" : "No such backend.\n");
William Lallemand6b160942016-11-22 12:34:35 +01004432
4433 /* return server's effective weight at the moment */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02004434 snprintf(trash.area, trash.size, "%d (initial %d)\n", sv->uweight,
4435 sv->iweight);
Willy Tarreaud0a06d52022-05-18 15:07:19 +02004436 if (applet_putstr(appctx, trash.area) == -1)
Christopher Faulet90b5abe2016-12-05 14:25:08 +01004437 return 0;
William Lallemand6b160942016-11-22 12:34:35 +01004438 return 1;
4439}
4440
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004441/* Parse a "set weight" command.
4442 *
4443 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004444 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004445static int cli_parse_set_weight(char **args, char *payload, struct appctx *appctx, void *private)
William Lallemand6b160942016-11-22 12:34:35 +01004446{
4447 struct server *sv;
4448 const char *warning;
4449
4450 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4451 return 1;
4452
4453 sv = cli_find_server(appctx, args[2]);
4454 if (!sv)
4455 return 1;
4456
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004457 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
4458
William Lallemand6b160942016-11-22 12:34:35 +01004459 warning = server_parse_weight_change_request(sv, args[3]);
Willy Tarreau9d008692019-08-09 11:21:01 +02004460 if (warning)
4461 cli_err(appctx, warning);
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004462
4463 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
4464
William Lallemand6b160942016-11-22 12:34:35 +01004465 return 1;
4466}
4467
Willy Tarreau46b7f532018-08-21 11:54:26 +02004468/* parse a "set maxconn server" command. It always returns 1.
4469 *
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004470 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004471 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004472static int cli_parse_set_maxconn_server(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreaub8026272016-11-23 11:26:56 +01004473{
4474 struct server *sv;
4475 const char *warning;
4476
4477 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4478 return 1;
4479
4480 sv = cli_find_server(appctx, args[3]);
4481 if (!sv)
4482 return 1;
4483
Amaury Denoyelle02742862021-06-18 11:11:36 +02004484 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
4485
Willy Tarreaub8026272016-11-23 11:26:56 +01004486 warning = server_parse_maxconn_change_request(sv, args[4]);
Willy Tarreau9d008692019-08-09 11:21:01 +02004487 if (warning)
4488 cli_err(appctx, warning);
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004489
Amaury Denoyelle02742862021-06-18 11:11:36 +02004490 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
4491
Willy Tarreaub8026272016-11-23 11:26:56 +01004492 return 1;
4493}
William Lallemand6b160942016-11-22 12:34:35 +01004494
Willy Tarreau46b7f532018-08-21 11:54:26 +02004495/* parse a "disable agent" command. It always returns 1.
4496 *
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004497 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004498 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004499static int cli_parse_disable_agent(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004500{
4501 struct server *sv;
4502
4503 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4504 return 1;
4505
4506 sv = cli_find_server(appctx, args[2]);
4507 if (!sv)
4508 return 1;
4509
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004510 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004511 sv->agent.state &= ~CHK_ST_ENABLED;
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004512 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004513 return 1;
4514}
4515
Willy Tarreau46b7f532018-08-21 11:54:26 +02004516/* parse a "disable health" command. It always returns 1.
4517 *
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004518 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004519 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004520static int cli_parse_disable_health(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004521{
4522 struct server *sv;
4523
4524 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4525 return 1;
4526
4527 sv = cli_find_server(appctx, args[2]);
4528 if (!sv)
4529 return 1;
4530
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004531 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004532 sv->check.state &= ~CHK_ST_ENABLED;
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004533 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004534 return 1;
4535}
4536
Willy Tarreau46b7f532018-08-21 11:54:26 +02004537/* parse a "disable server" command. It always returns 1.
4538 *
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004539 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004540 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004541static int cli_parse_disable_server(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauffb4d582016-11-24 12:47:00 +01004542{
4543 struct server *sv;
4544
4545 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4546 return 1;
4547
4548 sv = cli_find_server(appctx, args[2]);
4549 if (!sv)
4550 return 1;
4551
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004552 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreauffb4d582016-11-24 12:47:00 +01004553 srv_adm_set_maint(sv);
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004554 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Willy Tarreauffb4d582016-11-24 12:47:00 +01004555 return 1;
4556}
4557
Willy Tarreau46b7f532018-08-21 11:54:26 +02004558/* parse a "enable agent" command. It always returns 1.
4559 *
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004560 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004561 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004562static int cli_parse_enable_agent(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004563{
4564 struct server *sv;
4565
4566 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4567 return 1;
4568
4569 sv = cli_find_server(appctx, args[2]);
4570 if (!sv)
4571 return 1;
4572
Willy Tarreau9d008692019-08-09 11:21:01 +02004573 if (!(sv->agent.state & CHK_ST_CONFIGURED))
4574 return cli_err(appctx, "Agent was not configured on this server, cannot enable.\n");
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004575
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004576 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004577 sv->agent.state |= CHK_ST_ENABLED;
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004578 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau58d9cb72016-11-24 12:56:01 +01004579 return 1;
4580}
4581
Willy Tarreau46b7f532018-08-21 11:54:26 +02004582/* parse a "enable health" command. It always returns 1.
4583 *
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004584 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004585 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004586static int cli_parse_enable_health(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004587{
4588 struct server *sv;
4589
4590 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4591 return 1;
4592
4593 sv = cli_find_server(appctx, args[2]);
4594 if (!sv)
4595 return 1;
4596
Amaury Denoyelle0f456d52021-09-21 10:29:09 +02004597 if (!(sv->check.state & CHK_ST_CONFIGURED))
4598 return cli_err(appctx, "Health check was not configured on this server, cannot enable.\n");
4599
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004600 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004601 sv->check.state |= CHK_ST_ENABLED;
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004602 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Willy Tarreau2c04eda2016-11-24 12:51:04 +01004603 return 1;
4604}
4605
Willy Tarreau46b7f532018-08-21 11:54:26 +02004606/* parse a "enable server" command. It always returns 1.
4607 *
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004608 * Grabs the server lock.
Willy Tarreau46b7f532018-08-21 11:54:26 +02004609 */
Aurélien Nephtaliabbf6072018-04-18 13:26:46 +02004610static int cli_parse_enable_server(char **args, char *payload, struct appctx *appctx, void *private)
Willy Tarreauffb4d582016-11-24 12:47:00 +01004611{
4612 struct server *sv;
4613
4614 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4615 return 1;
4616
4617 sv = cli_find_server(appctx, args[2]);
4618 if (!sv)
4619 return 1;
4620
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004621 HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
Willy Tarreauffb4d582016-11-24 12:47:00 +01004622 srv_adm_set_ready(sv);
Olivier Houcharde9bad0a2018-01-17 17:39:34 +01004623 if (!(sv->flags & SRV_F_COOKIESET)
4624 && (sv->proxy->ck_opts & PR_CK_DYNAMIC) &&
4625 sv->cookie)
4626 srv_check_for_dup_dyncookie(sv);
Willy Tarreau3bcc2692018-08-21 15:35:31 +02004627 HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
Willy Tarreauffb4d582016-11-24 12:47:00 +01004628 return 1;
4629}
4630
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004631/* Allocates data structure related to load balancing for the server <sv>. It
4632 * is only required for dynamic servers.
4633 *
4634 * At the moment, the server lock is not used as this function is only called
4635 * for a dynamic server not yet registered.
4636 *
4637 * Returns 1 on success, 0 on allocation failure.
4638 */
4639static int srv_alloc_lb(struct server *sv, struct proxy *be)
4640{
4641 int node;
4642
4643 sv->lb_tree = (sv->flags & SRV_F_BACKUP) ?
4644 &be->lbprm.chash.bck : &be->lbprm.chash.act;
4645 sv->lb_nodes_tot = sv->uweight * BE_WEIGHT_SCALE;
4646 sv->lb_nodes_now = 0;
4647
Willy Tarreaudcb121f2021-04-20 11:37:45 +02004648 if (((be->lbprm.algo & (BE_LB_KIND | BE_LB_PARM)) == (BE_LB_KIND_RR | BE_LB_RR_RANDOM)) ||
4649 ((be->lbprm.algo & (BE_LB_KIND | BE_LB_HASH_TYPE)) == (BE_LB_KIND_HI | BE_LB_HASH_CONS))) {
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004650 sv->lb_nodes = calloc(sv->lb_nodes_tot, sizeof(*sv->lb_nodes));
4651
4652 if (!sv->lb_nodes)
4653 return 0;
4654
4655 for (node = 0; node < sv->lb_nodes_tot; node++) {
4656 sv->lb_nodes[node].server = sv;
4657 sv->lb_nodes[node].node.key = full_hash(sv->puid * SRV_EWGHT_RANGE + node);
4658 }
4659 }
4660
4661 return 1;
4662}
4663
Amaury Denoyelle29d1ac12021-09-21 11:51:29 +02004664/* updates the server's weight during a warmup stage. Once the final weight is
4665 * reached, the task automatically stops. Note that any server status change
4666 * must have updated s->last_change accordingly.
4667 */
4668static struct task *server_warmup(struct task *t, void *context, unsigned int state)
4669{
4670 struct server *s = context;
4671
4672 /* by default, plan on stopping the task */
4673 t->expire = TICK_ETERNITY;
4674 if ((s->next_admin & SRV_ADMF_MAINT) ||
4675 (s->next_state != SRV_ST_STARTING))
4676 return t;
4677
4678 HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
4679
4680 /* recalculate the weights and update the state */
4681 server_recalc_eweight(s, 1);
4682
4683 /* probably that we can refill this server with a bit more connections */
4684 pendconn_grab_from_px(s);
4685
4686 HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
4687
4688 /* get back there in 1 second or 1/20th of the slowstart interval,
4689 * whichever is greater, resulting in small 5% steps.
4690 */
4691 if (s->next_state == SRV_ST_STARTING)
4692 t->expire = tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20)));
4693 return t;
4694}
4695
4696/* Allocate the slowstart task if the server is configured with a slowstart
4697 * timer. If server next_state is SRV_ST_STARTING, the task is scheduled.
4698 *
4699 * Returns 0 on success else non-zero.
4700 */
4701static int init_srv_slowstart(struct server *srv)
4702{
4703 struct task *t;
4704
4705 if (srv->slowstart) {
Willy Tarreaubeeabf52021-10-01 18:23:30 +02004706 if ((t = task_new_anywhere()) == NULL) {
Amaury Denoyelle29d1ac12021-09-21 11:51:29 +02004707 ha_alert("Cannot activate slowstart for server %s/%s: out of memory.\n", srv->proxy->id, srv->id);
4708 return ERR_ALERT | ERR_FATAL;
4709 }
4710
4711 /* We need a warmup task that will be called when the server
4712 * state switches from down to up.
4713 */
4714 srv->warmup = t;
4715 t->process = server_warmup;
4716 t->context = srv;
4717
4718 /* server can be in this state only because of */
4719 if (srv->next_state == SRV_ST_STARTING) {
4720 task_schedule(srv->warmup,
4721 tick_add(now_ms,
4722 MS_TO_TICKS(MAX(1000, (now.tv_sec - srv->last_change)) / 20)));
4723 }
4724 }
4725
4726 return ERR_NONE;
4727}
4728REGISTER_POST_SERVER_CHECK(init_srv_slowstart);
4729
Miroslav Zagorac8a8f2702021-06-15 15:33:20 +02004730/* Memory allocation and initialization of the per_thr field.
4731 * Returns 0 if the field has been successfully initialized, -1 on failure.
4732 */
4733int srv_init_per_thr(struct server *srv)
4734{
4735 int i;
4736
4737 srv->per_thr = calloc(global.nbthread, sizeof(*srv->per_thr));
Willy Tarreauc21a1872022-11-21 14:14:06 +01004738 srv->per_tgrp = calloc(global.nbtgroups, sizeof(*srv->per_tgrp));
4739 if (!srv->per_thr || !srv->per_tgrp)
Miroslav Zagorac8a8f2702021-06-15 15:33:20 +02004740 return -1;
4741
4742 for (i = 0; i < global.nbthread; i++) {
4743 srv->per_thr[i].idle_conns = EB_ROOT;
4744 srv->per_thr[i].safe_conns = EB_ROOT;
4745 srv->per_thr[i].avail_conns = EB_ROOT;
4746 MT_LIST_INIT(&srv->per_thr[i].streams);
4747 }
4748
4749 return 0;
4750}
4751
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004752/* Parse a "add server" command
4753 * Returns 0 if the server has been successfully initialized, 1 on failure.
4754 */
4755static int cli_parse_add_server(char **args, char *payload, struct appctx *appctx, void *private)
4756{
4757 struct proxy *be;
4758 struct server *srv;
4759 char *be_name, *sv_name;
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004760 int errcode, argc;
Miroslav Zagorac8a8f2702021-06-15 15:33:20 +02004761 int next_id;
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004762 const int parse_flags = SRV_PARSE_DYNAMIC|SRV_PARSE_PARSE_ADDR;
4763
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004764 usermsgs_clr("CLI");
4765
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004766 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4767 return 1;
4768
4769 ++args;
4770
4771 sv_name = be_name = args[1];
4772 /* split backend/server arg */
4773 while (*sv_name && *(++sv_name)) {
4774 if (*sv_name == '/') {
4775 *sv_name = '\0';
4776 ++sv_name;
4777 break;
4778 }
4779 }
4780
4781 if (!*sv_name)
4782 return cli_err(appctx, "Require 'backend/server'.");
4783
Amaury Denoyellecece9182021-04-20 17:09:08 +02004784 be = proxy_be_by_name(be_name);
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004785 if (!be)
4786 return cli_err(appctx, "No such backend.");
4787
4788 if (!(be->lbprm.algo & BE_LB_PROP_DYN)) {
Amaury Denoyelleeafd7012021-04-29 14:59:42 +02004789 cli_err(appctx, "Backend must use a dynamic load balancing to support dynamic servers.");
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004790 return 1;
4791 }
4792
Amaury Denoyelle31ddd762021-06-10 15:26:44 +02004793 /* At this point, some operations might not be thread-safe anymore. This
4794 * might be the case for parsing handlers which were designed to run
4795 * only at the starting stage on single-thread mode.
4796 *
4797 * Activate thread isolation to ensure thread-safety.
4798 */
4799 thread_isolate();
4800
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004801 args[1] = sv_name;
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004802 errcode = _srv_parse_init(&srv, args, &argc, be, parse_flags);
4803 if (errcode)
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004804 goto out;
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004805
4806 while (*args[argc]) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004807 errcode = _srv_parse_kw(srv, args, &argc, be, parse_flags);
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004808
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004809 if (errcode)
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004810 goto out;
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004811 }
4812
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004813 errcode = _srv_parse_finalize(args, argc, srv, be, parse_flags);
4814 if (errcode)
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004815 goto out;
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004816
Amaury Denoyelleefbf35c2021-06-10 17:34:10 +02004817 /* A dynamic server does not currently support resolution.
4818 *
4819 * Initialize it explicitly to the "none" method to ensure no
4820 * resolution will ever be executed.
4821 */
4822 srv->init_addr_methods = SRV_IADDR_NONE;
4823
Amaury Denoyelle30467232021-03-12 18:03:27 +01004824 if (srv->mux_proto) {
4825 if (!conn_get_best_mux_entry(srv->mux_proto->token, PROTO_SIDE_BE, be->mode)) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004826 ha_alert("MUX protocol is not usable for server.\n");
Amaury Denoyelle30467232021-03-12 18:03:27 +01004827 goto out;
4828 }
4829 }
4830
Miroslav Zagorac8a8f2702021-06-15 15:33:20 +02004831 if (srv_init_per_thr(srv) == -1) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004832 ha_alert("failed to allocate per-thread lists for server.\n");
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004833 goto out;
4834 }
4835
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004836 if (srv->max_idle_conns != 0) {
4837 srv->curr_idle_thr = calloc(global.nbthread, sizeof(*srv->curr_idle_thr));
4838 if (!srv->curr_idle_thr) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004839 ha_alert("failed to allocate counters for server.\n");
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004840 goto out;
4841 }
4842 }
4843
4844 if (!srv_alloc_lb(srv, be)) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004845 ha_alert("Failed to initialize load-balancing data.\n");
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004846 goto out;
4847 }
4848
4849 if (!stats_allocate_proxy_counters_internal(&srv->extra_counters,
4850 COUNTERS_SV,
4851 STATS_PX_CAP_SRV)) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004852 ha_alert("failed to allocate extra counters for server.\n");
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004853 goto out;
4854 }
4855
Aurelien DARRAGON86207e72023-02-08 11:55:08 +01004856 /* ensure minconn/maxconn consistency */
4857 srv_minmax_conn_apply(srv);
4858
Amaury Denoyelle79b90e82021-09-20 15:15:19 +02004859 if (srv->use_ssl == 1 || (srv->proxy->options & PR_O_TCPCHK_SSL) ||
4860 srv->check.use_ssl == 1) {
Amaury Denoyelle34897d22021-05-19 09:49:41 +02004861 if (xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv) {
4862 if (xprt_get(XPRT_SSL)->prepare_srv(srv))
4863 goto out;
4864 }
4865 }
4866
Amaury Denoyelle56eb8ed2021-07-13 10:36:03 +02004867 if (srv->trackit) {
4868 if (srv_apply_track(srv, be))
4869 goto out;
4870 }
4871
Amaury Denoyelleb65f4ca2021-08-04 11:33:14 +02004872 /* Init check/agent if configured. The check is manually disabled
4873 * because a dynamic server is started in a disable state. It must be
4874 * manually activated via a "enable health/agent" command.
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02004875 */
4876 if (srv->do_check) {
4877 if (init_srv_check(srv))
4878 goto out;
4879
4880 srv->check.state &= ~CHK_ST_ENABLED;
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02004881 }
Amaury Denoyelle3eb42f92021-08-10 16:24:36 +02004882
4883 if (srv->do_agent) {
Amaury Denoyelleb65f4ca2021-08-04 11:33:14 +02004884 if (init_srv_agent_check(srv))
4885 goto out;
4886
4887 srv->agent.state &= ~CHK_ST_ENABLED;
Amaury Denoyelleb65f4ca2021-08-04 11:33:14 +02004888 }
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02004889
Amaury Denoyellecd8a6f22021-09-21 11:51:54 +02004890 /* Init slowstart if needed. */
4891 if (init_srv_slowstart(srv))
4892 goto out;
4893
Amaury Denoyelle31ddd762021-06-10 15:26:44 +02004894 /* Attach the server to the end of the proxy linked list. Note that this
4895 * operation is not thread-safe so this is executed under thread
4896 * isolation.
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004897 *
Amaury Denoyelle31ddd762021-06-10 15:26:44 +02004898 * If a server with the same name is found, reject the new one.
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004899 */
Amaury Denoyellecece9182021-04-20 17:09:08 +02004900
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004901 /* TODO use a double-linked list for px->srv */
4902 if (be->srv) {
Amaury Denoyellecece9182021-04-20 17:09:08 +02004903 struct server *next = be->srv;
4904
4905 while (1) {
4906 /* check for duplicate server */
Tim Duesterhusc5aa1132021-10-16 17:48:15 +02004907 if (strcmp(srv->id, next->id) == 0) {
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004908 ha_alert("Already exists a server with the same name in backend.\n");
Amaury Denoyellecece9182021-04-20 17:09:08 +02004909 goto out;
4910 }
4911
4912 if (!next->next)
4913 break;
4914
4915 next = next->next;
4916 }
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004917
4918 next->next = srv;
4919 }
4920 else {
4921 srv->next = be->srv;
4922 be->srv = srv;
4923 }
Amaury Denoyellecece9182021-04-20 17:09:08 +02004924
Amaury Denoyelle406aaef2021-06-09 09:58:47 +02004925 /* generate the server id if not manually specified */
4926 if (!srv->puid) {
4927 next_id = get_next_id(&be->conf.used_server_id, 1);
4928 if (!next_id) {
4929 ha_alert("Cannot attach server : no id left in proxy\n");
4930 goto out;
4931 }
4932
4933 srv->conf.id.key = srv->puid = next_id;
Amaury Denoyelle406aaef2021-06-09 09:58:47 +02004934 }
Christopher Faulet70f89482021-12-07 18:49:44 +01004935 srv->conf.name.key = srv->id;
Amaury Denoyelle406aaef2021-06-09 09:58:47 +02004936
4937 /* insert the server in the backend trees */
Amaury Denoyelle1613b4a2021-06-08 17:00:20 +02004938 eb32_insert(&be->conf.used_server_id, &srv->conf.id);
4939 ebis_insert(&be->conf.used_server_name, &srv->conf.name);
Aurelien DARRAGON8d0ff282022-09-16 14:27:53 +02004940 /* addr_node.key could be NULL if FQDN resolution is postponed (ie: add server from cli) */
4941 if (srv->addr_node.key)
4942 ebis_insert(&be->used_server_addr, &srv->addr_node);
Amaury Denoyelle406aaef2021-06-09 09:58:47 +02004943
Aurelien DARRAGON61e38942022-11-17 16:10:35 +01004944 /* check if LSB bit (odd bit) is set for reuse_cnt */
4945 if (srv_id_reuse_cnt & 1) {
4946 /* cnt must be increased */
4947 srv_id_reuse_cnt++;
4948 }
4949 /* srv_id_reuse_cnt is always even at this stage, divide by 2 to
4950 * save some space
4951 * (sizeof(srv->rid) is half of sizeof(srv_id_reuse_cnt))
4952 */
4953 srv->rid = (srv_id_reuse_cnt) ? (srv_id_reuse_cnt / 2) : 0;
4954
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +01004955 /* adding server cannot fail when we reach this:
4956 * publishing EVENT_HDL_SUB_SERVER_ADD
4957 */
4958 srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_ADD, srv, 1);
4959
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004960 thread_release();
4961
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02004962 /* Start the check task. The server must be fully initialized.
4963 *
4964 * <srvpos> and <nbcheck> parameters are set to 1 as there should be no
4965 * need to randomly spread the task interval for dynamic servers.
4966 */
4967 if (srv->check.state & CHK_ST_CONFIGURED) {
4968 if (!start_check_task(&srv->check, 0, 1, 1))
4969 ha_alert("System might be unstable, consider to execute a reload");
4970 }
Amaury Denoyelle3eb42f92021-08-10 16:24:36 +02004971 if (srv->agent.state & CHK_ST_CONFIGURED) {
Amaury Denoyelleb65f4ca2021-08-04 11:33:14 +02004972 if (!start_check_task(&srv->agent, 0, 1, 1))
4973 ha_alert("System might be unstable, consider to execute a reload");
4974 }
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02004975
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02004976 ha_notice("New server registered.\n");
Amaury Denoyelle30fc6da2022-11-10 15:16:49 +01004977 cli_umsg(appctx, LOG_INFO);
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01004978
4979 return 0;
4980
4981out:
Amaury Denoyellebd8dd842021-08-04 11:20:05 +02004982 if (srv) {
4983 if (srv->track)
4984 release_server_track(srv);
4985
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02004986 if (srv->check.state & CHK_ST_CONFIGURED)
4987 free_check(&srv->check);
Amaury Denoyelle3eb42f92021-08-10 16:24:36 +02004988 if (srv->agent.state & CHK_ST_CONFIGURED)
Amaury Denoyelleb65f4ca2021-08-04 11:33:14 +02004989 free_check(&srv->agent);
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02004990
Amaury Denoyellebd8dd842021-08-04 11:20:05 +02004991 /* remove the server from the proxy linked list */
4992 if (be->srv == srv) {
4993 be->srv = srv->next;
4994 }
4995 else {
4996 struct server *prev;
4997 for (prev = be->srv; prev && prev->next != srv; prev = prev->next)
4998 ;
4999 if (prev)
5000 prev->next = srv->next;
5001 }
5002
5003 }
Amaury Denoyelle08be72b2021-07-28 10:06:52 +02005004
Amaury Denoyelle31ddd762021-06-10 15:26:44 +02005005 thread_release();
5006
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02005007 if (!usermsgs_empty())
Amaury Denoyelle30fc6da2022-11-10 15:16:49 +01005008 cli_umsgerr(appctx);
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02005009
Amaury Denoyelle08be72b2021-07-28 10:06:52 +02005010 if (srv)
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +02005011 srv_drop(srv);
Amaury Denoyelle56eb8ed2021-07-13 10:36:03 +02005012
Amaury Denoyellef99f77a2021-03-08 17:13:32 +01005013 return 1;
5014}
5015
Amaury Denoyellee5580432021-04-15 14:41:20 +02005016/* Parse a "del server" command
5017 * Returns 0 if the server has been successfully initialized, 1 on failure.
5018 */
5019static int cli_parse_delete_server(char **args, char *payload, struct appctx *appctx, void *private)
5020{
5021 struct proxy *be;
5022 struct server *srv;
5023 char *be_name, *sv_name;
Aurelien DARRAGONf175b082023-02-01 17:22:32 +01005024 struct server *prev_del;
Amaury Denoyellee5580432021-04-15 14:41:20 +02005025
5026 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
5027 return 1;
5028
5029 ++args;
5030
5031 sv_name = be_name = args[1];
5032 /* split backend/server arg */
5033 while (*sv_name && *(++sv_name)) {
5034 if (*sv_name == '/') {
5035 *sv_name = '\0';
5036 ++sv_name;
5037 break;
5038 }
5039 }
5040
5041 if (!*sv_name)
5042 return cli_err(appctx, "Require 'backend/server'.");
5043
5044 /* The proxy servers list is currently not protected by a lock so this
Willy Tarreauba3ab792021-08-04 14:42:37 +02005045 * requires thread isolation. In addition, any place referencing the
5046 * server about to be deleted would be unsafe after our operation, so
5047 * we must be certain to be alone so that no other thread has even
5048 * started to grab a temporary reference to this server.
Amaury Denoyellee5580432021-04-15 14:41:20 +02005049 */
Willy Tarreauba3ab792021-08-04 14:42:37 +02005050 thread_isolate_full();
Amaury Denoyellee5580432021-04-15 14:41:20 +02005051
5052 get_backend_server(be_name, sv_name, &be, &srv);
5053 if (!be) {
5054 cli_err(appctx, "No such backend.");
5055 goto out;
5056 }
5057
5058 if (!srv) {
5059 cli_err(appctx, "No such server.");
5060 goto out;
5061 }
5062
Amaury Denoyelle14c3c5c2021-08-23 14:10:51 +02005063 if (srv->flags & SRV_F_NON_PURGEABLE) {
5064 cli_err(appctx, "This server cannot be removed at runtime due to other configuration elements pointing to it.");
Amaury Denoyellee5580432021-04-15 14:41:20 +02005065 goto out;
5066 }
5067
5068 /* Only servers in maintenance can be deleted. This ensures that the
5069 * server is not present anymore in the lb structures (through
5070 * lbprm.set_server_status_down).
5071 */
5072 if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
5073 cli_err(appctx, "Only servers in maintenance mode can be deleted.");
5074 goto out;
5075 }
5076
5077 /* Ensure that there is no active/idle/pending connection on the server.
5078 *
5079 * TODO idle connections should not prevent server deletion. A proper
5080 * cleanup function should be implemented to be used here.
5081 */
5082 if (srv->cur_sess || srv->curr_idle_conns ||
Willy Tarreaua0570452021-06-18 09:30:30 +02005083 !eb_is_empty(&srv->queue.head)) {
Amaury Denoyellee5580432021-04-15 14:41:20 +02005084 cli_err(appctx, "Server still has connections attached to it, cannot remove it.");
5085 goto out;
5086 }
5087
Aurelien DARRAGON129ecf42022-11-17 10:37:58 +01005088 /* removing cannot fail anymore when we reach this:
5089 * publishing EVENT_HDL_SUB_SERVER_DEL
5090 */
5091 srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_DEL, srv, 1);
5092
Amaury Denoyelle56eb8ed2021-07-13 10:36:03 +02005093 /* remove srv from tracking list */
5094 if (srv->track)
5095 release_server_track(srv);
5096
Amaury Denoyelle2fc4d392021-07-22 16:04:59 +02005097 /* stop the check task if running */
5098 if (srv->check.state & CHK_ST_CONFIGURED)
5099 check_purge(&srv->check);
Amaury Denoyelle3eb42f92021-08-10 16:24:36 +02005100 if (srv->agent.state & CHK_ST_CONFIGURED)
Amaury Denoyelleb65f4ca2021-08-04 11:33:14 +02005101 check_purge(&srv->agent);
Amaury Denoyellee5580432021-04-15 14:41:20 +02005102
5103 /* detach the server from the proxy linked list
5104 * The proxy servers list is currently not protected by a lock, so this
5105 * requires thread_isolate/release.
5106 */
5107
5108 /* be->srv cannot be empty since we have already found the server with
5109 * get_backend_server */
5110 BUG_ON(!be->srv);
5111 if (be->srv == srv) {
5112 be->srv = srv->next;
5113 }
5114 else {
5115 struct server *next;
Amaury Denoyelled6b4b6d2021-04-21 11:50:26 +02005116 for (next = be->srv; srv != next->next; next = next->next) {
5117 /* srv cannot be not found since we have already found
5118 * it with get_backend_server */
5119 BUG_ON(!next);
5120 }
Amaury Denoyellee5580432021-04-15 14:41:20 +02005121
Amaury Denoyellee5580432021-04-15 14:41:20 +02005122 next->next = srv->next;
5123 }
5124
Aurelien DARRAGONf175b082023-02-01 17:22:32 +01005125 /* Some deleted servers could still point to us using their 'next',
5126 * update them as needed
5127 * Please note the small race between the POP and APPEND, although in
5128 * this situation this is not an issue as we are under full thread
5129 * isolation
5130 */
5131 while ((prev_del = MT_LIST_POP(&srv->prev_deleted, struct server *, prev_deleted))) {
5132 /* update its 'next' ptr */
5133 prev_del->next = srv->next;
5134 if (srv->next) {
5135 /* now it is our 'next' responsibility */
5136 MT_LIST_APPEND(&srv->next->prev_deleted, &prev_del->prev_deleted);
5137 }
5138 }
5139
5140 /* we ourselves need to inform our 'next' that we will still point it */
5141 if (srv->next)
5142 MT_LIST_APPEND(&srv->next->prev_deleted, &srv->prev_deleted);
5143
Amaury Denoyellee5580432021-04-15 14:41:20 +02005144 /* remove srv from addr_node tree */
Amaury Denoyelle82d7f772021-06-09 16:00:43 +02005145 eb32_delete(&srv->conf.id);
5146 ebpt_delete(&srv->conf.name);
Aurelien DARRAGON8d0ff282022-09-16 14:27:53 +02005147 if (srv->addr_node.key)
5148 ebpt_delete(&srv->addr_node);
Amaury Denoyellee5580432021-04-15 14:41:20 +02005149
5150 /* remove srv from idle_node tree for idle conn cleanup */
5151 eb32_delete(&srv->idle_node);
5152
Aurelien DARRAGON75b9d1c2023-01-24 14:40:01 +01005153 /* flag the server as deleted
5154 * (despite the server being removed from primary server list,
5155 * one could still access the server data from a valid ptr)
5156 * Deleted flag helps detecting when a server is in transient removal
5157 * state.
5158 * ie: removed from the list but not yet freed/purged from memory.
5159 */
5160 srv->flags |= SRV_F_DELETED;
5161
Aurelien DARRAGON61e38942022-11-17 16:10:35 +01005162 /* set LSB bit (odd bit) for reuse_cnt */
5163 srv_id_reuse_cnt |= 1;
5164
Amaury Denoyellee5580432021-04-15 14:41:20 +02005165 thread_release();
5166
Amaury Denoyelle5e560e82021-05-28 16:35:05 +02005167 ha_notice("Server deleted.\n");
Amaury Denoyellebc2ebfa2021-08-25 15:34:53 +02005168 srv_drop(srv);
Amaury Denoyellee5580432021-04-15 14:41:20 +02005169
5170 cli_msg(appctx, LOG_INFO, "Server deleted.");
5171
5172 return 0;
5173
5174out:
5175 thread_release();
5176
5177 return 1;
5178}
5179
William Lallemand222baf22016-11-19 02:00:33 +01005180/* register cli keywords */
5181static struct cli_kw_list cli_kws = {{ },{
Amaury Denoyellec755efd2021-08-03 18:05:37 +02005182 { { "disable", "agent", NULL }, "disable agent : disable agent checks", cli_parse_disable_agent, NULL },
5183 { { "disable", "health", NULL }, "disable health : disable health checks", cli_parse_disable_health, NULL },
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005184 { { "disable", "server", NULL }, "disable server (DEPRECATED) : disable a server for maintenance (use 'set server' instead)", cli_parse_disable_server, NULL },
Amaury Denoyellec755efd2021-08-03 18:05:37 +02005185 { { "enable", "agent", NULL }, "enable agent : enable agent checks", cli_parse_enable_agent, NULL },
5186 { { "enable", "health", NULL }, "enable health : enable health checks", cli_parse_enable_health, NULL },
Willy Tarreaub205bfd2021-05-07 11:38:37 +02005187 { { "enable", "server", NULL }, "enable server (DEPRECATED) : enable a disabled server (use 'set server' instead)", cli_parse_enable_server, NULL },
5188 { { "set", "maxconn", "server", NULL }, "set maxconn server <bk>/<srv> : change a server's maxconn setting", cli_parse_set_maxconn_server, NULL },
5189 { { "set", "server", NULL }, "set server <bk>/<srv> [opts] : change a server's state, weight, address or ssl", cli_parse_set_server },
5190 { { "get", "weight", NULL }, "get weight <bk>/<srv> : report a server's current weight", cli_parse_get_weight },
5191 { { "set", "weight", NULL }, "set weight <bk>/<srv> (DEPRECATED) : change a server's weight (use 'set server' instead)", cli_parse_set_weight },
Amaury Denoyelle76e8b702022-03-09 15:07:31 +01005192 { { "add", "server", NULL }, "add server <bk>/<srv> : create a new server", cli_parse_add_server, NULL },
5193 { { "del", "server", NULL }, "del server <bk>/<srv> : remove a dynamically added server", cli_parse_delete_server, NULL },
William Lallemand222baf22016-11-19 02:00:33 +01005194 {{},}
5195}};
5196
Willy Tarreau0108d902018-11-25 19:14:37 +01005197INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
Baptiste Assmann83cbaa52016-11-02 15:34:05 +01005198
Amaury Denoyelle669b6202021-07-13 10:35:23 +02005199/* Prepare a server <srv> to track check status of another one. <srv>.<trackit>
5200 * field is used to retrieve the identifier of the tracked server, either with
5201 * the format "proxy/server" or just "server". <curproxy> must point to the
5202 * backend owning <srv>; if no proxy is specified in <trackit>, it will be used
5203 * to find the tracked server.
5204 *
5205 * Returns 0 if the server track has been activated else non-zero.
5206 *
5207 * Not thread-safe.
5208 */
5209int srv_apply_track(struct server *srv, struct proxy *curproxy)
5210{
5211 struct proxy *px;
5212 struct server *strack, *loop;
5213 char *pname, *sname;
5214
5215 if (!srv->trackit)
5216 return 1;
5217
5218 pname = srv->trackit;
5219 sname = strrchr(pname, '/');
5220
5221 if (sname) {
5222 *sname++ = '\0';
5223 }
5224 else {
5225 sname = pname;
5226 pname = NULL;
5227 }
5228
5229 if (pname) {
5230 px = proxy_be_by_name(pname);
5231 if (!px) {
5232 ha_alert("unable to find required proxy '%s' for tracking.\n",
5233 pname);
5234 return 1;
5235 }
5236 }
5237 else {
5238 px = curproxy;
5239 }
5240
5241 strack = findserver(px, sname);
5242 if (!strack) {
5243 ha_alert("unable to find required server '%s' for tracking.\n",
5244 sname);
5245 return 1;
5246 }
5247
Amaury Denoyelle79f68be2021-07-13 10:35:50 +02005248 if (strack->flags & SRV_F_DYNAMIC) {
5249 ha_alert("unable to use %s/%s for tracking as it is a dynamic server.\n",
5250 px->id, strack->id);
5251 return 1;
5252 }
5253
Amaury Denoyelle669b6202021-07-13 10:35:23 +02005254 if (!strack->do_check && !strack->do_agent && !strack->track &&
5255 !strack->trackit) {
5256 ha_alert("unable to use %s/%s for "
5257 "tracking as it does not have any check nor agent enabled.\n",
5258 px->id, strack->id);
5259 return 1;
5260 }
5261
5262 for (loop = strack->track; loop && loop != srv; loop = loop->track)
5263 ;
5264
5265 if (srv == strack || loop) {
5266 ha_alert("unable to track %s/%s as it "
5267 "belongs to a tracking chain looping back to %s/%s.\n",
5268 px->id, strack->id, px->id,
5269 srv == strack ? strack->id : loop->id);
5270 return 1;
5271 }
5272
5273 if (curproxy != px &&
5274 (curproxy->options & PR_O_DISABLE404) != (px->options & PR_O_DISABLE404)) {
5275 ha_alert("unable to use %s/%s for"
5276 "tracking: disable-on-404 option inconsistency.\n",
5277 px->id, strack->id);
5278 return 1;
5279 }
5280
5281 srv->track = strack;
5282 srv->tracknext = strack->trackers;
5283 strack->trackers = srv;
Amaury Denoyelle06269612021-08-23 14:05:07 +02005284 strack->flags |= SRV_F_NON_PURGEABLE;
Amaury Denoyelle669b6202021-07-13 10:35:23 +02005285
5286 ha_free(&srv->trackit);
5287
5288 return 0;
5289}
5290
Aurelien DARRAGON8bbe6432023-04-17 13:53:56 +02005291/* This function propagates srv state change to lb algorithms */
5292static void srv_lb_propagate(struct server *s)
5293{
5294 struct proxy *px = s->proxy;
5295
5296 if (px->lbprm.update_server_eweight)
5297 px->lbprm.update_server_eweight(s);
5298 else if (srv_willbe_usable(s)) {
5299 if (px->lbprm.set_server_status_up)
5300 px->lbprm.set_server_status_up(s);
5301 }
5302 else {
5303 if (px->lbprm.set_server_status_down)
5304 px->lbprm.set_server_status_down(s);
5305 }
5306}
5307
Emeric Brun64cc49c2017-10-03 14:46:45 +02005308/*
Aurelien DARRAGON0ddf0522023-03-27 11:57:28 +02005309 * This function applies server's status changes.
Emeric Brun64cc49c2017-10-03 14:46:45 +02005310 *
Willy Tarreau1e690bb2020-10-22 11:30:59 +02005311 * Must be called with the server lock held. This may also be called at init
5312 * time as the result of parsing the state file, in which case no lock will be
5313 * held, and the server's warmup task can be null.
Emeric Brun64cc49c2017-10-03 14:46:45 +02005314 */
Willy Tarreau3ff577e2018-08-02 11:48:52 +02005315static void srv_update_status(struct server *s)
Emeric Brun64cc49c2017-10-03 14:46:45 +02005316{
5317 struct check *check = &s->check;
5318 int xferred;
5319 struct proxy *px = s->proxy;
5320 int prev_srv_count = s->proxy->srv_bck + s->proxy->srv_act;
5321 int srv_was_stopping = (s->cur_state == SRV_ST_STOPPING) || (s->cur_admin & SRV_ADMF_DRAIN);
Aurelien DARRAGON9f5853f2023-04-18 13:52:27 +02005322 enum srv_state srv_prev_state = s->cur_state;
Emeric Brun64cc49c2017-10-03 14:46:45 +02005323 int log_level;
Willy Tarreau83061a82018-07-13 11:56:34 +02005324 struct buffer *tmptrash = NULL;
Emeric Brun64cc49c2017-10-03 14:46:45 +02005325
Emeric Brun64cc49c2017-10-03 14:46:45 +02005326 /* If currently main is not set we try to apply pending state changes */
5327 if (!(s->cur_admin & SRV_ADMF_MAINT)) {
5328 int next_admin;
5329
5330 /* Backup next admin */
5331 next_admin = s->next_admin;
5332
5333 /* restore current admin state */
5334 s->next_admin = s->cur_admin;
5335
5336 if ((s->cur_state != SRV_ST_STOPPED) && (s->next_state == SRV_ST_STOPPED)) {
Aurelien DARRAGON85b91372023-04-18 12:02:48 +02005337 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005338
5339 if (s->onmarkeddown & HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS)
5340 srv_shutdown_streams(s, SF_ERR_DOWN);
5341
5342 /* we might have streams queued on this server and waiting for
5343 * a connection. Those which are redispatchable will be queued
5344 * to another server or to the proxy itself.
5345 */
5346 xferred = pendconn_redistribute(s);
5347
Aurelien DARRAGONa63f4902023-03-23 14:39:51 +01005348 /* no maintenance + server DOWN: publish event SERVER DOWN */
5349 srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_DOWN, s, 0);
5350
Emeric Brun64cc49c2017-10-03 14:46:45 +02005351 tmptrash = alloc_trash_chunk();
5352 if (tmptrash) {
5353 chunk_printf(tmptrash,
5354 "%sServer %s/%s is DOWN", s->flags & SRV_F_BACKUP ? "Backup " : "",
5355 s->proxy->id, s->id);
5356
Emeric Brun5a133512017-10-19 14:42:30 +02005357 srv_append_status(tmptrash, s, NULL, xferred, 0);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005358 ha_warning("%s.\n", tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005359
5360 /* we don't send an alert if the server was previously paused */
5361 log_level = srv_was_stopping ? LOG_NOTICE : LOG_ALERT;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005362 send_log(s->proxy, log_level, "%s.\n",
5363 tmptrash->area);
5364 send_email_alert(s, log_level, "%s",
5365 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005366 free_trash_chunk(tmptrash);
5367 tmptrash = NULL;
5368 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005369 }
5370 else if ((s->cur_state != SRV_ST_STOPPING) && (s->next_state == SRV_ST_STOPPING)) {
Aurelien DARRAGON85b91372023-04-18 12:02:48 +02005371 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005372
5373 /* we might have streams queued on this server and waiting for
5374 * a connection. Those which are redispatchable will be queued
5375 * to another server or to the proxy itself.
5376 */
5377 xferred = pendconn_redistribute(s);
5378
5379 tmptrash = alloc_trash_chunk();
5380 if (tmptrash) {
5381 chunk_printf(tmptrash,
5382 "%sServer %s/%s is stopping", s->flags & SRV_F_BACKUP ? "Backup " : "",
5383 s->proxy->id, s->id);
5384
Emeric Brun5a133512017-10-19 14:42:30 +02005385 srv_append_status(tmptrash, s, NULL, xferred, 0);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005386
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005387 ha_warning("%s.\n", tmptrash->area);
5388 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5389 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005390 free_trash_chunk(tmptrash);
5391 tmptrash = NULL;
5392 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005393 }
5394 else if (((s->cur_state != SRV_ST_RUNNING) && (s->next_state == SRV_ST_RUNNING))
5395 || ((s->cur_state != SRV_ST_STARTING) && (s->next_state == SRV_ST_STARTING))) {
Emeric Brun64cc49c2017-10-03 14:46:45 +02005396
Willy Tarreau1e690bb2020-10-22 11:30:59 +02005397 if (s->next_state == SRV_ST_STARTING && s->warmup)
Emeric Brun64cc49c2017-10-03 14:46:45 +02005398 task_schedule(s->warmup, tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))));
5399
Willy Tarreau3ff577e2018-08-02 11:48:52 +02005400 server_recalc_eweight(s, 0);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005401 /* now propagate the status change to any LB algorithms */
Aurelien DARRAGON8bbe6432023-04-17 13:53:56 +02005402 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005403
5404 /* If the server is set with "on-marked-up shutdown-backup-sessions",
5405 * and it's not a backup server and its effective weight is > 0,
5406 * then it can accept new connections, so we shut down all streams
5407 * on all backup servers.
5408 */
5409 if ((s->onmarkedup & HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS) &&
5410 !(s->flags & SRV_F_BACKUP) && s->next_eweight)
5411 srv_shutdown_backup_streams(s->proxy, SF_ERR_UP);
5412
5413 /* check if we can handle some connections queued at the proxy. We
5414 * will take as many as we can handle.
5415 */
5416 xferred = pendconn_grab_from_px(s);
5417
Aurelien DARRAGONa63f4902023-03-23 14:39:51 +01005418 /* no maintenance + server going UP: publish event SERVER UP */
5419 srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_UP, s, 0);
5420
Emeric Brun64cc49c2017-10-03 14:46:45 +02005421 tmptrash = alloc_trash_chunk();
5422 if (tmptrash) {
5423 chunk_printf(tmptrash,
5424 "%sServer %s/%s is UP", s->flags & SRV_F_BACKUP ? "Backup " : "",
5425 s->proxy->id, s->id);
5426
Emeric Brun5a133512017-10-19 14:42:30 +02005427 srv_append_status(tmptrash, s, NULL, xferred, 0);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005428 ha_warning("%s.\n", tmptrash->area);
5429 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5430 tmptrash->area);
5431 send_email_alert(s, LOG_NOTICE, "%s",
5432 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005433 free_trash_chunk(tmptrash);
5434 tmptrash = NULL;
5435 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005436 }
5437 else if (s->cur_eweight != s->next_eweight) {
5438 /* now propagate the status change to any LB algorithms */
Aurelien DARRAGON8bbe6432023-04-17 13:53:56 +02005439 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005440 }
5441
5442 s->next_admin = next_admin;
5443 }
5444
Emeric Brun5a133512017-10-19 14:42:30 +02005445 /* reset operational state change */
5446 *s->op_st_chg.reason = 0;
5447 s->op_st_chg.status = s->op_st_chg.code = -1;
5448 s->op_st_chg.duration = 0;
Emeric Brun64cc49c2017-10-03 14:46:45 +02005449
5450 /* Now we try to apply pending admin changes */
5451
5452 /* Maintenance must also disable health checks */
5453 if (!(s->cur_admin & SRV_ADMF_MAINT) && (s->next_admin & SRV_ADMF_MAINT)) {
5454 if (s->check.state & CHK_ST_ENABLED) {
5455 s->check.state |= CHK_ST_PAUSED;
5456 check->health = 0;
5457 }
5458
5459 if (s->cur_state == SRV_ST_STOPPED) { /* server was already down */
Olivier Houchard796a2b32017-10-24 17:42:47 +02005460 tmptrash = alloc_trash_chunk();
5461 if (tmptrash) {
5462 chunk_printf(tmptrash,
5463 "%sServer %s/%s was DOWN and now enters maintenance%s%s%s",
5464 s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id,
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02005465 (s->adm_st_chg_cause) ? " (" : "",
5466 srv_adm_st_chg_cause(s->adm_st_chg_cause),
5467 (s->adm_st_chg_cause) ? ")" : "");
Emeric Brun64cc49c2017-10-03 14:46:45 +02005468
Olivier Houchard796a2b32017-10-24 17:42:47 +02005469 srv_append_status(tmptrash, s, NULL, -1, (s->next_admin & SRV_ADMF_FMAINT));
Emeric Brun64cc49c2017-10-03 14:46:45 +02005470
Olivier Houchard796a2b32017-10-24 17:42:47 +02005471 if (!(global.mode & MODE_STARTING)) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005472 ha_warning("%s.\n", tmptrash->area);
5473 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5474 tmptrash->area);
Olivier Houchard796a2b32017-10-24 17:42:47 +02005475 }
5476 free_trash_chunk(tmptrash);
5477 tmptrash = NULL;
Emeric Brun64cc49c2017-10-03 14:46:45 +02005478 }
5479 }
5480 else { /* server was still running */
5481 check->health = 0; /* failure */
Emeric Brune3114802017-12-21 14:42:26 +01005482
5483 s->next_state = SRV_ST_STOPPED;
Aurelien DARRAGON85b91372023-04-18 12:02:48 +02005484 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005485
Emeric Brun64cc49c2017-10-03 14:46:45 +02005486 if (s->onmarkeddown & HANA_ONMARKEDDOWN_SHUTDOWNSESSIONS)
5487 srv_shutdown_streams(s, SF_ERR_DOWN);
5488
William Dauchy6318d332020-05-02 21:52:36 +02005489 /* force connection cleanup on the given server */
5490 srv_cleanup_connections(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005491 /* we might have streams queued on this server and waiting for
5492 * a connection. Those which are redispatchable will be queued
5493 * to another server or to the proxy itself.
5494 */
5495 xferred = pendconn_redistribute(s);
5496
Aurelien DARRAGONa63f4902023-03-23 14:39:51 +01005497 /* maintenance on previously running server: publish event SERVER DOWN */
5498 srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_DOWN, s, 0);
5499
Emeric Brun64cc49c2017-10-03 14:46:45 +02005500 tmptrash = alloc_trash_chunk();
5501 if (tmptrash) {
5502 chunk_printf(tmptrash,
5503 "%sServer %s/%s is going DOWN for maintenance%s%s%s",
5504 s->flags & SRV_F_BACKUP ? "Backup " : "",
5505 s->proxy->id, s->id,
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02005506 (s->adm_st_chg_cause) ? " (" : "",
5507 srv_adm_st_chg_cause(s->adm_st_chg_cause),
5508 (s->adm_st_chg_cause) ? ")" : "");
Emeric Brun64cc49c2017-10-03 14:46:45 +02005509
5510 srv_append_status(tmptrash, s, NULL, xferred, (s->next_admin & SRV_ADMF_FMAINT));
5511
5512 if (!(global.mode & MODE_STARTING)) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005513 ha_warning("%s.\n", tmptrash->area);
5514 send_log(s->proxy, srv_was_stopping ? LOG_NOTICE : LOG_ALERT, "%s.\n",
5515 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005516 }
5517 free_trash_chunk(tmptrash);
5518 tmptrash = NULL;
5519 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005520 }
5521 }
5522 else if ((s->cur_admin & SRV_ADMF_MAINT) && !(s->next_admin & SRV_ADMF_MAINT)) {
5523 /* OK here we're leaving maintenance, we have many things to check,
5524 * because the server might possibly be coming back up depending on
5525 * its state. In practice, leaving maintenance means that we should
5526 * immediately turn to UP (more or less the slowstart) under the
5527 * following conditions :
5528 * - server is neither checked nor tracked
5529 * - server tracks another server which is not checked
5530 * - server tracks another server which is already up
5531 * Which sums up as something simpler :
5532 * "either the tracking server is up or the server's checks are disabled
5533 * or up". Otherwise we only re-enable health checks. There's a special
5534 * case associated to the stopping state which can be inherited. Note
5535 * that the server might still be in drain mode, which is naturally dealt
5536 * with by the lower level functions.
5537 */
Emeric Brun64cc49c2017-10-03 14:46:45 +02005538 if (s->check.state & CHK_ST_ENABLED) {
5539 s->check.state &= ~CHK_ST_PAUSED;
5540 check->health = check->rise; /* start OK but check immediately */
5541 }
5542
5543 if ((!s->track || s->track->next_state != SRV_ST_STOPPED) &&
5544 (!(s->agent.state & CHK_ST_ENABLED) || (s->agent.health >= s->agent.rise)) &&
5545 (!(s->check.state & CHK_ST_ENABLED) || (s->check.health >= s->check.rise))) {
5546 if (s->track && s->track->next_state == SRV_ST_STOPPING) {
5547 s->next_state = SRV_ST_STOPPING;
5548 }
5549 else {
5550 s->next_state = SRV_ST_STARTING;
Willy Tarreau1e690bb2020-10-22 11:30:59 +02005551 if (s->slowstart > 0) {
5552 if (s->warmup)
5553 task_schedule(s->warmup, tick_add(now_ms, MS_TO_TICKS(MAX(1000, s->slowstart / 20))));
5554 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005555 else
5556 s->next_state = SRV_ST_RUNNING;
5557 }
5558
5559 }
5560
Aurelien DARRAGON22f82f82022-11-25 18:07:49 +01005561 /* ignore if server stays down when leaving maintenance mode */
5562 if (s->next_state != SRV_ST_STOPPED) {
5563 /* leaving maintenance + server UP: publish event SERVER UP */
5564 srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_UP, s, 0);
5565 }
5566
Emeric Brun64cc49c2017-10-03 14:46:45 +02005567 tmptrash = alloc_trash_chunk();
5568 if (tmptrash) {
5569 if (!(s->next_admin & SRV_ADMF_FMAINT) && (s->cur_admin & SRV_ADMF_FMAINT)) {
5570 chunk_printf(tmptrash,
5571 "%sServer %s/%s is %s/%s (leaving forced maintenance)",
5572 s->flags & SRV_F_BACKUP ? "Backup " : "",
5573 s->proxy->id, s->id,
5574 (s->next_state == SRV_ST_STOPPED) ? "DOWN" : "UP",
5575 (s->next_admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
5576 }
5577 if (!(s->next_admin & SRV_ADMF_RMAINT) && (s->cur_admin & SRV_ADMF_RMAINT)) {
5578 chunk_printf(tmptrash,
5579 "%sServer %s/%s ('%s') is %s/%s (resolves again)",
5580 s->flags & SRV_F_BACKUP ? "Backup " : "",
5581 s->proxy->id, s->id, s->hostname,
5582 (s->next_state == SRV_ST_STOPPED) ? "DOWN" : "UP",
5583 (s->next_admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
5584 }
5585 if (!(s->next_admin & SRV_ADMF_IMAINT) && (s->cur_admin & SRV_ADMF_IMAINT)) {
5586 chunk_printf(tmptrash,
5587 "%sServer %s/%s is %s/%s (leaving maintenance)",
5588 s->flags & SRV_F_BACKUP ? "Backup " : "",
5589 s->proxy->id, s->id,
5590 (s->next_state == SRV_ST_STOPPED) ? "DOWN" : "UP",
5591 (s->next_admin & SRV_ADMF_DRAIN) ? "DRAIN" : "READY");
5592 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005593 ha_warning("%s.\n", tmptrash->area);
5594 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5595 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005596 free_trash_chunk(tmptrash);
5597 tmptrash = NULL;
5598 }
5599
Willy Tarreau3ff577e2018-08-02 11:48:52 +02005600 server_recalc_eweight(s, 0);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005601 /* now propagate the status change to any LB algorithms */
Aurelien DARRAGON8bbe6432023-04-17 13:53:56 +02005602 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005603
Willy Tarreau6a78e612018-08-07 10:14:53 +02005604 /* If the server is set with "on-marked-up shutdown-backup-sessions",
5605 * and it's not a backup server and its effective weight is > 0,
5606 * then it can accept new connections, so we shut down all streams
5607 * on all backup servers.
5608 */
5609 if ((s->onmarkedup & HANA_ONMARKEDUP_SHUTDOWNBACKUPSESSIONS) &&
5610 !(s->flags & SRV_F_BACKUP) && s->next_eweight)
5611 srv_shutdown_backup_streams(s->proxy, SF_ERR_UP);
5612
5613 /* check if we can handle some connections queued at the proxy. We
5614 * will take as many as we can handle.
5615 */
5616 xferred = pendconn_grab_from_px(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005617 }
5618 else if (s->next_admin & SRV_ADMF_MAINT) {
5619 /* remaining in maintenance mode, let's inform precisely about the
5620 * situation.
5621 */
5622 if (!(s->next_admin & SRV_ADMF_FMAINT) && (s->cur_admin & SRV_ADMF_FMAINT)) {
5623 tmptrash = alloc_trash_chunk();
5624 if (tmptrash) {
5625 chunk_printf(tmptrash,
5626 "%sServer %s/%s is leaving forced maintenance but remains in maintenance",
5627 s->flags & SRV_F_BACKUP ? "Backup " : "",
5628 s->proxy->id, s->id);
5629
5630 if (s->track) /* normally it's mandatory here */
5631 chunk_appendf(tmptrash, " via %s/%s",
5632 s->track->proxy->id, s->track->id);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005633 ha_warning("%s.\n", tmptrash->area);
5634 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5635 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005636 free_trash_chunk(tmptrash);
5637 tmptrash = NULL;
5638 }
5639 }
5640 if (!(s->next_admin & SRV_ADMF_RMAINT) && (s->cur_admin & SRV_ADMF_RMAINT)) {
5641 tmptrash = alloc_trash_chunk();
5642 if (tmptrash) {
5643 chunk_printf(tmptrash,
5644 "%sServer %s/%s ('%s') resolves again but remains in maintenance",
5645 s->flags & SRV_F_BACKUP ? "Backup " : "",
5646 s->proxy->id, s->id, s->hostname);
5647
5648 if (s->track) /* normally it's mandatory here */
5649 chunk_appendf(tmptrash, " via %s/%s",
5650 s->track->proxy->id, s->track->id);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005651 ha_warning("%s.\n", tmptrash->area);
5652 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5653 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005654 free_trash_chunk(tmptrash);
5655 tmptrash = NULL;
5656 }
5657 }
5658 else if (!(s->next_admin & SRV_ADMF_IMAINT) && (s->cur_admin & SRV_ADMF_IMAINT)) {
5659 tmptrash = alloc_trash_chunk();
5660 if (tmptrash) {
5661 chunk_printf(tmptrash,
5662 "%sServer %s/%s remains in forced maintenance",
5663 s->flags & SRV_F_BACKUP ? "Backup " : "",
5664 s->proxy->id, s->id);
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005665 ha_warning("%s.\n", tmptrash->area);
5666 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5667 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005668 free_trash_chunk(tmptrash);
5669 tmptrash = NULL;
5670 }
5671 }
5672 /* don't report anything when leaving drain mode and remaining in maintenance */
Emeric Brun64cc49c2017-10-03 14:46:45 +02005673 }
5674
5675 if (!(s->next_admin & SRV_ADMF_MAINT)) {
5676 if (!(s->cur_admin & SRV_ADMF_DRAIN) && (s->next_admin & SRV_ADMF_DRAIN)) {
5677 /* drain state is applied only if not yet in maint */
5678
Aurelien DARRAGON85b91372023-04-18 12:02:48 +02005679 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005680
5681 /* we might have streams queued on this server and waiting for
5682 * a connection. Those which are redispatchable will be queued
5683 * to another server or to the proxy itself.
5684 */
5685 xferred = pendconn_redistribute(s);
5686
5687 tmptrash = alloc_trash_chunk();
5688 if (tmptrash) {
5689 chunk_printf(tmptrash, "%sServer %s/%s enters drain state%s%s%s",
5690 s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id,
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02005691 (s->adm_st_chg_cause) ? " (" : "",
5692 srv_adm_st_chg_cause(s->adm_st_chg_cause),
5693 (s->adm_st_chg_cause) ? ")" : "");
Emeric Brun64cc49c2017-10-03 14:46:45 +02005694
5695 srv_append_status(tmptrash, s, NULL, xferred, (s->next_admin & SRV_ADMF_FDRAIN));
5696
5697 if (!(global.mode & MODE_STARTING)) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005698 ha_warning("%s.\n", tmptrash->area);
5699 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5700 tmptrash->area);
5701 send_email_alert(s, LOG_NOTICE, "%s",
5702 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005703 }
5704 free_trash_chunk(tmptrash);
5705 tmptrash = NULL;
5706 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005707 }
5708 else if ((s->cur_admin & SRV_ADMF_DRAIN) && !(s->next_admin & SRV_ADMF_DRAIN)) {
5709 /* OK completely leaving drain mode */
Willy Tarreau3ff577e2018-08-02 11:48:52 +02005710 server_recalc_eweight(s, 0);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005711
5712 tmptrash = alloc_trash_chunk();
5713 if (tmptrash) {
Aurelien DARRAGON9a1df022023-03-27 10:17:31 +02005714 if (s->cur_admin & SRV_ADMF_FDRAIN) {
Emeric Brun64cc49c2017-10-03 14:46:45 +02005715 chunk_printf(tmptrash,
5716 "%sServer %s/%s is %s (leaving forced drain)",
5717 s->flags & SRV_F_BACKUP ? "Backup " : "",
5718 s->proxy->id, s->id,
5719 (s->next_state == SRV_ST_STOPPED) ? "DOWN" : "UP");
5720 }
5721 else {
5722 chunk_printf(tmptrash,
5723 "%sServer %s/%s is %s (leaving drain)",
5724 s->flags & SRV_F_BACKUP ? "Backup " : "",
5725 s->proxy->id, s->id,
5726 (s->next_state == SRV_ST_STOPPED) ? "DOWN" : "UP");
5727 if (s->track) /* normally it's mandatory here */
5728 chunk_appendf(tmptrash, " via %s/%s",
5729 s->track->proxy->id, s->track->id);
5730 }
5731
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005732 ha_warning("%s.\n", tmptrash->area);
5733 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5734 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005735 free_trash_chunk(tmptrash);
5736 tmptrash = NULL;
5737 }
5738
5739 /* now propagate the status change to any LB algorithms */
Aurelien DARRAGON8bbe6432023-04-17 13:53:56 +02005740 srv_lb_propagate(s);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005741 }
5742 else if ((s->next_admin & SRV_ADMF_DRAIN)) {
5743 /* remaining in drain mode after removing one of its flags */
5744
5745 tmptrash = alloc_trash_chunk();
5746 if (tmptrash) {
5747 if (!(s->next_admin & SRV_ADMF_FDRAIN)) {
5748 chunk_printf(tmptrash,
5749 "%sServer %s/%s is leaving forced drain but remains in drain mode",
5750 s->flags & SRV_F_BACKUP ? "Backup " : "",
5751 s->proxy->id, s->id);
5752
5753 if (s->track) /* normally it's mandatory here */
5754 chunk_appendf(tmptrash, " via %s/%s",
5755 s->track->proxy->id, s->track->id);
5756 }
5757 else {
5758 chunk_printf(tmptrash,
5759 "%sServer %s/%s remains in forced drain mode",
5760 s->flags & SRV_F_BACKUP ? "Backup " : "",
5761 s->proxy->id, s->id);
5762 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02005763 ha_warning("%s.\n", tmptrash->area);
5764 send_log(s->proxy, LOG_NOTICE, "%s.\n",
5765 tmptrash->area);
Emeric Brun64cc49c2017-10-03 14:46:45 +02005766 free_trash_chunk(tmptrash);
5767 tmptrash = NULL;
5768 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005769 }
5770 }
5771
Aurelien DARRAGON9b1ccd72023-04-03 17:40:28 +02005772 /* Re-set adm st change to none */
5773 s->adm_st_chg_cause = SRV_ADM_STCHGC_NONE;
Aurelien DARRAGON22151c72023-04-17 17:45:58 +02005774
5775 /* explicitly commit state changes (even if it was already applied implicitly
5776 * by some lb state change function), so we don't miss anything
5777 */
5778 srv_lb_commit_status(s);
Aurelien DARRAGONe80ddb12023-04-17 15:30:11 +02005779
Aurelien DARRAGON9f5853f2023-04-18 13:52:27 +02005780 /* check if server stats must be updated due the the server state change */
5781 if (srv_prev_state != s->cur_state) {
5782 if (srv_prev_state == SRV_ST_STOPPED) {
5783 /* server was down and no longer is */
5784 if (s->last_change < now.tv_sec) // ignore negative times
5785 s->down_time += now.tv_sec - s->last_change;
5786 }
Aurelien DARRAGON5f80f8b2023-04-19 18:22:21 +02005787 else if (s->cur_state == SRV_ST_STOPPED) {
5788 /* server was up and is currently down */
5789 s->counters.down_trans++;
5790 }
Aurelien DARRAGON9f5853f2023-04-18 13:52:27 +02005791 s->last_change = now.tv_sec;
5792 }
5793
Aurelien DARRAGONe80ddb12023-04-17 15:30:11 +02005794 /* check if backend stats must be updated due to the server state change */
5795 if (prev_srv_count && s->proxy->srv_bck == 0 && s->proxy->srv_act == 0)
5796 set_backend_down(s->proxy); /* backend going down */
5797 else if (!prev_srv_count && (s->proxy->srv_bck || s->proxy->srv_act)) {
5798 /* backend was down and is back up again:
5799 * no helper function, updating last_change and backend downtime stats
5800 */
5801 if (s->proxy->last_change < now.tv_sec) // ignore negative times
5802 s->proxy->down_time += now.tv_sec - s->proxy->last_change;
5803 s->proxy->last_change = now.tv_sec;
5804 }
Emeric Brun64cc49c2017-10-03 14:46:45 +02005805}
Emeric Brun64cc49c2017-10-03 14:46:45 +02005806
Willy Tarreau144f84a2021-03-02 16:09:26 +01005807struct task *srv_cleanup_toremove_conns(struct task *task, void *context, unsigned int state)
Olivier Houchard9ea5d362019-02-14 18:29:09 +01005808{
5809 struct connection *conn;
5810
Willy Tarreau4d82bf52020-06-28 00:19:17 +02005811 while ((conn = MT_LIST_POP(&idle_conns[tid].toremove_conns,
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005812 struct connection *, toremove_list)) != NULL) {
Christopher Faulet73c12072019-04-08 11:23:22 +02005813 conn->mux->destroy(conn->ctx);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01005814 }
5815
5816 return task;
5817}
5818
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005819/* Move toremove_nb connections from idle_tree to toremove_list, -1 means
Olivier Houchardff1d0922020-06-29 20:15:59 +02005820 * moving them all.
5821 * Returns the number of connections moved.
Amaury Denoyelle5c7086f2021-01-11 09:21:52 +01005822 *
5823 * Must be called with idle_conns_lock held.
Olivier Houchardff1d0922020-06-29 20:15:59 +02005824 */
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005825static int srv_migrate_conns_to_remove(struct eb_root *idle_tree, struct mt_list *toremove_list, int toremove_nb)
Olivier Houchardff1d0922020-06-29 20:15:59 +02005826{
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005827 struct eb_node *node, *next;
Amaury Denoyelle8990b012021-02-19 15:29:16 +01005828 struct conn_hash_node *hash_node;
Olivier Houchardff1d0922020-06-29 20:15:59 +02005829 int i = 0;
5830
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005831 node = eb_first(idle_tree);
5832 while (node) {
5833 next = eb_next(node);
Olivier Houchardff1d0922020-06-29 20:15:59 +02005834 if (toremove_nb != -1 && i >= toremove_nb)
5835 break;
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005836
Amaury Denoyelle8990b012021-02-19 15:29:16 +01005837 hash_node = ebmb_entry(node, struct conn_hash_node, node);
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005838 eb_delete(node);
Willy Tarreau2b718102021-04-21 07:32:39 +02005839 MT_LIST_APPEND(toremove_list, &hash_node->conn->toremove_list);
Olivier Houchardff1d0922020-06-29 20:15:59 +02005840 i++;
Amaury Denoyellef232cb32021-01-06 16:14:12 +01005841
5842 node = next;
Olivier Houchardff1d0922020-06-29 20:15:59 +02005843 }
5844 return i;
5845}
William Dauchy6318d332020-05-02 21:52:36 +02005846/* cleanup connections for a given server
5847 * might be useful when going on forced maintenance or live changing ip/port
5848 */
William Dauchy707ad322020-05-04 13:52:40 +02005849static void srv_cleanup_connections(struct server *srv)
William Dauchy6318d332020-05-02 21:52:36 +02005850{
William Dauchy6318d332020-05-02 21:52:36 +02005851 int did_remove;
5852 int i;
William Dauchy6318d332020-05-02 21:52:36 +02005853
Amaury Denoyelle10d5c312021-01-06 14:28:51 +01005854 /* nothing to do if pool-max-conn is null */
5855 if (!srv->max_idle_conns)
5856 return;
5857
Willy Tarreauc35bcfc2020-06-29 14:43:16 +02005858 /* check all threads starting with ours */
Willy Tarreauc35bcfc2020-06-29 14:43:16 +02005859 for (i = tid;;) {
William Dauchy6318d332020-05-02 21:52:36 +02005860 did_remove = 0;
Amaury Denoyelle5c7086f2021-01-11 09:21:52 +01005861 HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
Willy Tarreau430bf4a2021-03-04 09:45:32 +01005862 if (srv_migrate_conns_to_remove(&srv->per_thr[i].idle_conns, &idle_conns[i].toremove_conns, -1) > 0)
William Dauchy6318d332020-05-02 21:52:36 +02005863 did_remove = 1;
Willy Tarreau430bf4a2021-03-04 09:45:32 +01005864 if (srv_migrate_conns_to_remove(&srv->per_thr[i].safe_conns, &idle_conns[i].toremove_conns, -1) > 0)
Olivier Houchardff1d0922020-06-29 20:15:59 +02005865 did_remove = 1;
Amaury Denoyelle5c7086f2021-01-11 09:21:52 +01005866 HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
William Dauchy6318d332020-05-02 21:52:36 +02005867 if (did_remove)
Willy Tarreau4d82bf52020-06-28 00:19:17 +02005868 task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
Willy Tarreauc35bcfc2020-06-29 14:43:16 +02005869
5870 if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid)
5871 break;
William Dauchy6318d332020-05-02 21:52:36 +02005872 }
Willy Tarreau260f3242021-10-06 18:30:04 +02005873}
5874
5875/* removes an idle conn after updating the server idle conns counters */
5876void srv_release_conn(struct server *srv, struct connection *conn)
5877{
5878 if (conn->flags & CO_FL_LIST_MASK) {
5879 /* The connection is currently in the server's idle list, so tell it
5880 * there's one less connection available in that list.
5881 */
5882 _HA_ATOMIC_DEC(&srv->curr_idle_conns);
5883 _HA_ATOMIC_DEC(conn->flags & CO_FL_SAFE_LIST ? &srv->curr_safe_nb : &srv->curr_idle_nb);
5884 _HA_ATOMIC_DEC(&srv->curr_idle_thr[tid]);
5885 }
5886 else {
5887 /* The connection is not private and not in any server's idle
5888 * list, so decrement the current number of used connections
5889 */
5890 _HA_ATOMIC_DEC(&srv->curr_used_conns);
5891 }
5892
5893 /* Remove the connection from any tree (safe, idle or available) */
5894 HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
5895 conn_delete_from_tree(&conn->hash_node->node);
Christopher Faulet5e1b0e72023-02-28 15:39:38 +01005896 conn->flags &= ~CO_FL_LIST_MASK;
Willy Tarreau260f3242021-10-06 18:30:04 +02005897 HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
5898}
5899
5900/* retrieve a connection from its <hash> in <tree>
5901 * returns NULL if no connection found
5902 */
5903struct connection *srv_lookup_conn(struct eb_root *tree, uint64_t hash)
5904{
Willy Tarreau85223482022-09-29 20:32:43 +02005905 struct eb64_node *node = NULL;
Willy Tarreau260f3242021-10-06 18:30:04 +02005906 struct connection *conn = NULL;
5907 struct conn_hash_node *hash_node = NULL;
5908
Willy Tarreau85223482022-09-29 20:32:43 +02005909 node = eb64_lookup(tree, hash);
Willy Tarreau260f3242021-10-06 18:30:04 +02005910 if (node) {
5911 hash_node = ebmb_entry(node, struct conn_hash_node, node);
5912 conn = hash_node->conn;
5913 }
5914
5915 return conn;
5916}
5917
5918/* retrieve the next connection sharing the same hash as <conn>
5919 * returns NULL if no connection found
5920 */
5921struct connection *srv_lookup_conn_next(struct connection *conn)
5922{
Willy Tarreau85223482022-09-29 20:32:43 +02005923 struct eb64_node *node = NULL;
Willy Tarreau260f3242021-10-06 18:30:04 +02005924 struct connection *next_conn = NULL;
5925 struct conn_hash_node *hash_node = NULL;
5926
Willy Tarreau85223482022-09-29 20:32:43 +02005927 node = eb64_next_dup(&conn->hash_node->node);
Willy Tarreau260f3242021-10-06 18:30:04 +02005928 if (node) {
Willy Tarreau85223482022-09-29 20:32:43 +02005929 hash_node = eb64_entry(node, struct conn_hash_node, node);
Willy Tarreau260f3242021-10-06 18:30:04 +02005930 next_conn = hash_node->conn;
5931 }
5932
5933 return next_conn;
5934}
5935
5936/* This adds an idle connection to the server's list if the connection is
5937 * reusable, not held by any owner anymore, but still has available streams.
5938 */
5939int srv_add_to_idle_list(struct server *srv, struct connection *conn, int is_safe)
5940{
5941 /* we try to keep the connection in the server's idle list
5942 * if we don't have too many FD in use, and if the number of
5943 * idle+current conns is lower than what was observed before
5944 * last purge, or if we already don't have idle conns for the
5945 * current thread and we don't exceed last count by global.nbthread.
5946 */
5947 if (!(conn->flags & CO_FL_PRIVATE) &&
5948 srv && srv->pool_purge_delay > 0 &&
5949 ((srv->proxy->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) &&
5950 ha_used_fds < global.tune.pool_high_count &&
5951 (srv->max_idle_conns == -1 || srv->max_idle_conns > srv->curr_idle_conns) &&
5952 ((eb_is_empty(&srv->per_thr[tid].safe_conns) &&
5953 (is_safe || eb_is_empty(&srv->per_thr[tid].idle_conns))) ||
5954 (ha_used_fds < global.tune.pool_low_count &&
5955 (srv->curr_used_conns + srv->curr_idle_conns <=
5956 MAX(srv->curr_used_conns, srv->est_need_conns) + srv->low_idle_conns))) &&
5957 !conn->mux->used_streams(conn) && conn->mux->avail_streams(conn)) {
5958 int retadd;
5959
5960 retadd = _HA_ATOMIC_ADD_FETCH(&srv->curr_idle_conns, 1);
5961 if (retadd > srv->max_idle_conns) {
5962 _HA_ATOMIC_DEC(&srv->curr_idle_conns);
5963 return 0;
5964 }
5965 _HA_ATOMIC_DEC(&srv->curr_used_conns);
5966
5967 HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
5968 conn_delete_from_tree(&conn->hash_node->node);
5969
5970 if (is_safe) {
5971 conn->flags = (conn->flags & ~CO_FL_LIST_MASK) | CO_FL_SAFE_LIST;
Willy Tarreau85223482022-09-29 20:32:43 +02005972 eb64_insert(&srv->per_thr[tid].safe_conns, &conn->hash_node->node);
Willy Tarreau260f3242021-10-06 18:30:04 +02005973 _HA_ATOMIC_INC(&srv->curr_safe_nb);
5974 } else {
5975 conn->flags = (conn->flags & ~CO_FL_LIST_MASK) | CO_FL_IDLE_LIST;
Willy Tarreau85223482022-09-29 20:32:43 +02005976 eb64_insert(&srv->per_thr[tid].idle_conns, &conn->hash_node->node);
Willy Tarreau260f3242021-10-06 18:30:04 +02005977 _HA_ATOMIC_INC(&srv->curr_idle_nb);
5978 }
5979 HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[tid].idle_conns_lock);
5980 _HA_ATOMIC_INC(&srv->curr_idle_thr[tid]);
5981
5982 __ha_barrier_full();
5983 if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
5984 HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
5985 if ((volatile void *)srv->idle_node.node.leaf_p == NULL) {
5986 srv->idle_node.key = tick_add(srv->pool_purge_delay,
5987 now_ms);
5988 eb32_insert(&idle_conn_srv, &srv->idle_node);
5989 if (!task_in_wq(idle_conn_task) && !
5990 task_in_rq(idle_conn_task)) {
5991 task_schedule(idle_conn_task,
5992 srv->idle_node.key);
5993 }
5994
5995 }
5996 HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conn_srv_lock);
5997 }
5998 return 1;
5999 }
6000 return 0;
William Dauchy6318d332020-05-02 21:52:36 +02006001}
6002
Willy Tarreau144f84a2021-03-02 16:09:26 +01006003struct task *srv_cleanup_idle_conns(struct task *task, void *context, unsigned int state)
Olivier Houchard0c18a6f2018-12-02 14:11:41 +01006004{
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006005 struct server *srv;
6006 struct eb32_node *eb;
6007 int i;
6008 unsigned int next_wakeup;
Olivier Houchardb7b3faa2018-12-14 18:15:36 +01006009
Willy Tarreau21b9ff52020-11-05 09:12:20 +01006010 next_wakeup = TICK_ETERNITY;
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006011 HA_SPIN_LOCK(OTHER_LOCK, &idle_conn_srv_lock);
6012 while (1) {
Olivier Houchard079cb9a2020-03-30 00:23:57 +02006013 int exceed_conns;
6014 int to_kill;
6015 int curr_idle;
Olivier Houchardb7b3faa2018-12-14 18:15:36 +01006016
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006017 eb = eb32_lookup_ge(&idle_conn_srv, now_ms - TIMER_LOOK_BACK);
6018 if (!eb) {
6019 /* we might have reached the end of the tree, typically because
6020 * <now_ms> is in the first half and we're first scanning the last
6021 * half. Let's loop back to the beginning of the tree now.
6022 */
Olivier Houchard0c18a6f2018-12-02 14:11:41 +01006023
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006024 eb = eb32_first(&idle_conn_srv);
6025 if (likely(!eb))
6026 break;
6027 }
6028 if (tick_is_lt(now_ms, eb->key)) {
6029 /* timer not expired yet, revisit it later */
6030 next_wakeup = eb->key;
Olivier Houchard0c18a6f2018-12-02 14:11:41 +01006031 break;
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006032 }
6033 srv = eb32_entry(eb, struct server, idle_node);
Olivier Houchard079cb9a2020-03-30 00:23:57 +02006034
6035 /* Calculate how many idle connections we want to kill :
6036 * we want to remove half the difference between the total
6037 * of established connections (used or idle) and the max
6038 * number of used connections.
6039 */
6040 curr_idle = srv->curr_idle_conns;
6041 if (curr_idle == 0)
6042 goto remove;
Willy Tarreaubdb86bd2020-06-29 15:56:35 +02006043 exceed_conns = srv->curr_used_conns + curr_idle - MAX(srv->max_used_conns, srv->est_need_conns);
Olivier Houchard079cb9a2020-03-30 00:23:57 +02006044 exceed_conns = to_kill = exceed_conns / 2 + (exceed_conns & 1);
Willy Tarreaubdb86bd2020-06-29 15:56:35 +02006045
Willy Tarreau21b9ff52020-11-05 09:12:20 +01006046 srv->est_need_conns = (srv->est_need_conns + srv->max_used_conns) / 2;
Willy Tarreaubdb86bd2020-06-29 15:56:35 +02006047 if (srv->est_need_conns < srv->max_used_conns)
6048 srv->est_need_conns = srv->max_used_conns;
6049
Willy Tarreau9dc231a2022-11-21 14:32:33 +01006050 HA_ATOMIC_STORE(&srv->max_used_conns, srv->curr_used_conns);
Olivier Houchard079cb9a2020-03-30 00:23:57 +02006051
Willy Tarreau18ed7892020-07-02 19:05:30 +02006052 if (exceed_conns <= 0)
6053 goto remove;
6054
Willy Tarreauc35bcfc2020-06-29 14:43:16 +02006055 /* check all threads starting with ours */
6056 for (i = tid;;) {
Olivier Houchard079cb9a2020-03-30 00:23:57 +02006057 int max_conn;
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006058 int j;
6059 int did_remove = 0;
6060
Olivier Houchard079cb9a2020-03-30 00:23:57 +02006061 max_conn = (exceed_conns * srv->curr_idle_thr[i]) /
6062 curr_idle + 1;
Olivier Houchardff1d0922020-06-29 20:15:59 +02006063
Amaury Denoyelle5c7086f2021-01-11 09:21:52 +01006064 HA_SPIN_LOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
Willy Tarreau430bf4a2021-03-04 09:45:32 +01006065 j = srv_migrate_conns_to_remove(&srv->per_thr[i].idle_conns, &idle_conns[i].toremove_conns, max_conn);
Olivier Houchardff1d0922020-06-29 20:15:59 +02006066 if (j > 0)
6067 did_remove = 1;
6068 if (max_conn - j > 0 &&
Willy Tarreau430bf4a2021-03-04 09:45:32 +01006069 srv_migrate_conns_to_remove(&srv->per_thr[i].safe_conns, &idle_conns[i].toremove_conns, max_conn - j) > 0)
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006070 did_remove = 1;
Amaury Denoyelle5c7086f2021-01-11 09:21:52 +01006071 HA_SPIN_UNLOCK(IDLE_CONNS_LOCK, &idle_conns[i].idle_conns_lock);
Olivier Houchardff1d0922020-06-29 20:15:59 +02006072
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006073 if (did_remove)
Willy Tarreau4d82bf52020-06-28 00:19:17 +02006074 task_wakeup(idle_conns[i].cleanup_task, TASK_WOKEN_OTHER);
Willy Tarreauc35bcfc2020-06-29 14:43:16 +02006075
6076 if ((i = ((i + 1 == global.nbthread) ? 0 : i + 1)) == tid)
6077 break;
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006078 }
Olivier Houchard079cb9a2020-03-30 00:23:57 +02006079remove:
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006080 eb32_delete(&srv->idle_node);
Willy Tarreau21b9ff52020-11-05 09:12:20 +01006081
6082 if (srv->curr_idle_conns) {
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006083 /* There are still more idle connections, add the
6084 * server back in the tree.
6085 */
Willy Tarreau21b9ff52020-11-05 09:12:20 +01006086 srv->idle_node.key = tick_add(srv->pool_purge_delay, now_ms);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006087 eb32_insert(&idle_conn_srv, &srv->idle_node);
Willy Tarreau21b9ff52020-11-05 09:12:20 +01006088 next_wakeup = tick_first(next_wakeup, srv->idle_node.key);
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006089 }
Olivier Houchard0c18a6f2018-12-02 14:11:41 +01006090 }
Olivier Houchard9ea5d362019-02-14 18:29:09 +01006091 HA_SPIN_UNLOCK(OTHER_LOCK, &idle_conn_srv_lock);
6092
Willy Tarreau21b9ff52020-11-05 09:12:20 +01006093 task->expire = next_wakeup;
Olivier Houchard0c18a6f2018-12-02 14:11:41 +01006094 return task;
6095}
Olivier Houchard88698d92019-04-16 19:07:22 +02006096
Amaury Denoyelle3109ccf2021-04-29 17:30:05 +02006097/* Close remaining idle connections. This functions is designed to be run on
6098 * process shutdown. This guarantees a proper socket shutdown to avoid
6099 * TIME_WAIT state. For a quick operation, only ctrl is closed, xprt stack is
6100 * bypassed.
6101 *
6102 * This function is not thread-safe so it must only be called via a global
6103 * deinit function.
6104 */
6105static void srv_close_idle_conns(struct server *srv)
6106{
6107 struct eb_root **cleaned_tree;
6108 int i;
6109
6110 for (i = 0; i < global.nbthread; ++i) {
6111 struct eb_root *conn_trees[] = {
6112 &srv->per_thr[i].idle_conns,
6113 &srv->per_thr[i].safe_conns,
6114 &srv->per_thr[i].avail_conns,
6115 NULL
6116 };
6117
6118 for (cleaned_tree = conn_trees; *cleaned_tree; ++cleaned_tree) {
6119 while (!eb_is_empty(*cleaned_tree)) {
6120 struct ebmb_node *node = ebmb_first(*cleaned_tree);
6121 struct conn_hash_node *conn_hash_node = ebmb_entry(node, struct conn_hash_node, node);
6122 struct connection *conn = conn_hash_node->conn;
6123
6124 if (conn->ctrl->ctrl_close)
6125 conn->ctrl->ctrl_close(conn);
6126 ebmb_delete(node);
6127 }
6128 }
6129 }
6130}
6131
6132REGISTER_SERVER_DEINIT(srv_close_idle_conns);
6133
Willy Tarreau76cc6992020-07-01 18:49:24 +02006134/* config parser for global "tune.idle-pool.shared", accepts "on" or "off" */
6135static int cfg_parse_idle_pool_shared(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01006136 const struct proxy *defpx, const char *file, int line,
Willy Tarreau76cc6992020-07-01 18:49:24 +02006137 char **err)
6138{
6139 if (too_many_args(1, args, err, NULL))
6140 return -1;
6141
6142 if (strcmp(args[1], "on") == 0)
6143 global.tune.options |= GTUNE_IDLE_POOL_SHARED;
6144 else if (strcmp(args[1], "off") == 0)
6145 global.tune.options &= ~GTUNE_IDLE_POOL_SHARED;
6146 else {
6147 memprintf(err, "'%s' expects either 'on' or 'off' but got '%s'.", args[0], args[1]);
6148 return -1;
6149 }
6150 return 0;
6151}
6152
Olivier Houchard88698d92019-04-16 19:07:22 +02006153/* config parser for global "tune.pool-{low,high}-fd-ratio" */
6154static int cfg_parse_pool_fd_ratio(char **args, int section_type, struct proxy *curpx,
Willy Tarreau01825162021-03-09 09:53:46 +01006155 const struct proxy *defpx, const char *file, int line,
Olivier Houchard88698d92019-04-16 19:07:22 +02006156 char **err)
6157{
6158 int arg = -1;
6159
6160 if (too_many_args(1, args, err, NULL))
6161 return -1;
6162
6163 if (*(args[1]) != 0)
6164 arg = atoi(args[1]);
6165
6166 if (arg < 0 || arg > 100) {
6167 memprintf(err, "'%s' expects an integer argument between 0 and 100.", args[0]);
6168 return -1;
6169 }
6170
6171 if (args[0][10] == 'h')
6172 global.tune.pool_high_ratio = arg;
6173 else
6174 global.tune.pool_low_ratio = arg;
6175 return 0;
6176}
6177
6178/* config keyword parsers */
6179static struct cfg_kw_list cfg_kws = {ILH, {
Willy Tarreau76cc6992020-07-01 18:49:24 +02006180 { CFG_GLOBAL, "tune.idle-pool.shared", cfg_parse_idle_pool_shared },
Olivier Houchard88698d92019-04-16 19:07:22 +02006181 { CFG_GLOBAL, "tune.pool-high-fd-ratio", cfg_parse_pool_fd_ratio },
6182 { CFG_GLOBAL, "tune.pool-low-fd-ratio", cfg_parse_pool_fd_ratio },
6183 { 0, NULL, NULL }
6184}};
6185
6186INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
6187
Baptiste Assmanna68ca962015-04-14 01:15:08 +02006188/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02006189 * Local variables:
6190 * c-indent-level: 8
6191 * c-basic-offset: 8
6192 * End:
6193 */