Coverage Report

Created: 2026-08-13 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/proxy.c
Line
Count
Source
1
/*
2
 * Proxy variables and functions.
3
 *
4
 * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version
9
 * 2 of the License, or (at your option) any later version.
10
 *
11
 */
12
13
#include <unistd.h>
14
#include <string.h>
15
#include <sys/types.h>
16
#include <sys/socket.h>
17
#include <sys/stat.h>
18
19
#include <import/cebis_tree.h>
20
#include <import/eb32tree.h>
21
22
#include <haproxy/acl.h>
23
#include <haproxy/api.h>
24
#include <haproxy/applet.h>
25
#include <haproxy/backend.h>
26
#include <haproxy/capture-t.h>
27
#include <haproxy/cfgparse.h>
28
#include <haproxy/cli.h>
29
#include <haproxy/counters.h>
30
#include <haproxy/errors.h>
31
#include <haproxy/fd.h>
32
#include <haproxy/filters.h>
33
#include <haproxy/frontend.h>
34
#include <haproxy/global.h>
35
#include <haproxy/guid.h>
36
#include <haproxy/http_ana.h>
37
#include <haproxy/http_htx.h>
38
#include <haproxy/http_ext.h>
39
#include <haproxy/http_rules.h>
40
#include <haproxy/mailers.h>
41
#include <haproxy/listener.h>
42
#include <haproxy/lb_chash.h>
43
#include <haproxy/lb_fas.h>
44
#include <haproxy/lb_fwlc.h>
45
#include <haproxy/lb_fwrr.h>
46
#include <haproxy/lb_map.h>
47
#include <haproxy/lb_ss.h>
48
#include <haproxy/log.h>
49
#include <haproxy/obj_type-t.h>
50
#include <haproxy/openssl-compat.h> /* required for TLSEXT_TYPE_application_layer_protocol_negotiation */
51
#include <haproxy/peers.h>
52
#include <haproxy/pool.h>
53
#include <haproxy/protocol.h>
54
#include <haproxy/proto_tcp.h>
55
#include <haproxy/proxy.h>
56
#include <haproxy/sc_strm.h>
57
#include <haproxy/quic_tp.h>
58
#include <haproxy/quic_tune.h>
59
#include <haproxy/server-t.h>
60
#include <haproxy/signal.h>
61
#include <haproxy/stats.h>
62
#include <haproxy/stconn.h>
63
#include <haproxy/stream.h>
64
#include <haproxy/stress.h>
65
#include <haproxy/task.h>
66
#include <haproxy/tcpcheck.h>
67
#include <haproxy/thread.h>
68
#include <haproxy/time.h>
69
#include <haproxy/tools.h>
70
#include <haproxy/uri_auth.h>
71
72
/* Lock to ensure multiple backends deletion concurrently is safe */
73
__decl_spinlock(proxies_del_lock);
74
75
int listeners;  /* # of proxy listeners, set by cfgparse */
76
77
/* List of non-default and non-internal proxies, except mworker and cli_fe which are stored in it.
78
 * Used for check_config_validity() post init and most runtime operations (stats, ...).
79
 */
80
struct list main_proxies = LIST_HEAD_INIT(main_proxies);
81
82
/* List of all proxies, except defaults.
83
 * Currently only used for post_proxy_check_fct and post_server_check_fct post init.
84
 */
85
struct list all_proxies = LIST_HEAD_INIT(all_proxies);
86
87
struct ceb_root *used_proxy_id = NULL; /* list of proxy IDs in use */
88
struct ceb_root *proxy_by_name = NULL; /* tree of proxies sorted by name */
89
struct ceb_root *defproxy_by_name = NULL; /* tree of default proxies sorted by name (dups possible) */
90
struct list defaults_list = LIST_HEAD_INIT(defaults_list); /* list of all defaults proxies */
91
unsigned int error_snapshot_id = 0;     /* global ID assigned to each error then incremented */
92
93
unsigned int dynpx_next_id = 0; /* lowest ID assigned to dynamic proxies */
94
95
/* CLI context used during "show backend" and "show default-server/defaults" */
96
struct show_be_ctx {
97
  struct proxy *px;
98
  struct watcher px_watch; /* watcher to automatically update px pointer on backend deletion */
99
};
100
101
/* CLI context used during "show servers {state|conn}" */
102
struct show_srv_ctx {
103
  struct proxy *px;       /* current proxy to dump or NULL */
104
  struct server *sv;      /* current server to dump or NULL */
105
  uint only_pxid;         /* dump only this proxy ID when explicit */
106
  int show_conn;          /* non-zero = "conn" otherwise "state" */
107
  enum {
108
    SHOW_SRV_HEAD = 0,
109
    SHOW_SRV_LIST,
110
  } state;
111
112
  struct watcher px_watch;  /* watcher to automatically update px on backend deletion */
113
  struct watcher srv_watch; /* watcher to automatically update sv on server deletion */
114
};
115
116
/* proxy->options. For unsupported ones, pass 0 in the "cap" (PR_CAP_*) field.
117
 * If this is due to feature removal, the val field can contain the version the
118
 * option was removed in the "val" (PR_O_*) field as (major<<8)+minor (e.g.
119
 * 0x305 for "3.5"). Pass zero there to indicate build options instead.
120
 */
121
const struct cfg_opt cfg_opts[] =
122
{
123
  { "abortonclose", PR_O_ABRT_CLOSE, PR_CAP_BE|PR_CAP_FE, 0, 0 },
124
  { "allbackups",   PR_O_USE_ALL_BK, PR_CAP_BE, 0, 0 },
125
  { "checkcache",   PR_O_CHK_CACHE,  PR_CAP_BE, 0, PR_MODE_HTTP },
126
  { "clitcpka",     PR_O_TCP_CLI_KA, PR_CAP_FE, 0, 0 },
127
  { "contstats",    PR_O_CONTSTATS,  PR_CAP_FE, 0, 0 },
128
  { "dontlognull",  PR_O_NULLNOLOG,  PR_CAP_FE, 0, 0 },
129
  { "http-buffer-request", PR_O_WREQ_BODY,  PR_CAP_FE | PR_CAP_BE, 0, PR_MODE_HTTP },
130
  { "http-drop-request-trailers", PR_O_HTTP_DROP_REQ_TRLS, PR_CAP_BE, 0, PR_MODE_HTTP },
131
  { "http-drop-response-trailers", PR_O_HTTP_DROP_RES_TRLS, PR_CAP_FE, 0, PR_MODE_HTTP },
132
  { "http-ignore-probes", PR_O_IGNORE_PRB, PR_CAP_FE, 0, PR_MODE_HTTP },
133
  { "idle-close-on-response", PR_O_IDLE_CLOSE_RESP, PR_CAP_FE, 0, PR_MODE_HTTP },
134
  { "prefer-last-server", PR_O_PREF_LAST,  PR_CAP_BE, 0, PR_MODE_HTTP },
135
  { "logasap",      PR_O_LOGASAP,    PR_CAP_FE, 0, 0 },
136
  { "nolinger",     PR_O_TCP_NOLING, PR_CAP_FE | PR_CAP_BE, 0, 0 },
137
  { "persist",      PR_O_PERSIST,    PR_CAP_BE, 0, 0 },
138
  { "srvtcpka",     PR_O_TCP_SRV_KA, PR_CAP_BE, 0, 0 },
139
  { "transparent",  0x305, 0, 0, 0 },
140
141
  { NULL, 0, 0, 0, 0 }
142
};
143
144
/* proxy->options2 */
145
const struct cfg_opt cfg_opts2[] =
146
{
147
#ifdef USE_LINUX_SPLICE
148
  { "splice-request",  PR_O2_SPLIC_REQ, PR_CAP_FE|PR_CAP_BE, 0, 0 },
149
  { "splice-response", PR_O2_SPLIC_RTR, PR_CAP_FE|PR_CAP_BE, 0, 0 },
150
  { "splice-auto",     PR_O2_SPLIC_AUT, PR_CAP_FE|PR_CAP_BE, 0, 0 },
151
#else
152
        { "splice-request",  0, 0, 0, 0 },
153
        { "splice-response", 0, 0, 0, 0 },
154
        { "splice-auto",     0, 0, 0, 0 },
155
#endif
156
  { "accept-unsafe-violations-in-http-request",  PR_O2_REQBUG_OK, PR_CAP_FE, 0, PR_MODE_HTTP },
157
  { "accept-unsafe-violations-in-http-response", PR_O2_RSPBUG_OK, PR_CAP_BE, 0, PR_MODE_HTTP },
158
  { "dontlog-normal",               PR_O2_NOLOGNORM, PR_CAP_FE, 0, 0 },
159
  { "log-separate-errors",          PR_O2_LOGERRORS, PR_CAP_FE, 0, 0 },
160
  { "log-health-checks",            PR_O2_LOGHCHKS,  PR_CAP_BE, 0, 0 },
161
  { "socket-stats",                 PR_O2_SOCKSTAT,  PR_CAP_FE, 0, 0 },
162
  { "tcp-smart-accept",             PR_O2_SMARTACC,  PR_CAP_FE, 0, 0 },
163
  { "tcp-smart-connect",            PR_O2_SMARTCON,  PR_CAP_BE, 0, 0 },
164
  { "independent-streams",          PR_O2_INDEPSTR,  PR_CAP_FE|PR_CAP_BE, 0, 0 },
165
  { "http-use-proxy-header",        PR_O2_USE_PXHDR, PR_CAP_FE, 0, PR_MODE_HTTP },
166
  { "http-pretend-keepalive",       PR_O2_FAKE_KA,   PR_CAP_BE, 0, PR_MODE_HTTP },
167
  { "http-no-delay",                PR_O2_NODELAY,   PR_CAP_FE|PR_CAP_BE, 0, PR_MODE_HTTP },
168
169
  {"h1-case-adjust-bogus-client",   PR_O2_H1_ADJ_BUGCLI, PR_CAP_FE, 0, 0 },
170
  {"h1-case-adjust-bogus-server",   PR_O2_H1_ADJ_BUGSRV, PR_CAP_BE, 0, 0 },
171
  {"disable-h2-upgrade",            PR_O2_NO_H2_UPGRADE, PR_CAP_FE, 0, PR_MODE_HTTP },
172
  { NULL, 0, 0, 0 }
173
};
174
175
/* proxy->options3 */
176
const struct cfg_opt cfg_opts3[] =
177
{
178
  {"assume-rfc6587-ntf",            PR_O3_ASSUME_RFC6587_NTF, PR_CAP_FE, 0, PR_MODE_SYSLOG },
179
  {"dont-parse-log",                PR_O3_DONTPARSELOG, PR_CAP_FE, 0, PR_MODE_SYSLOG },
180
  { NULL, 0, 0, 0 }
181
};
182
183
/* Helper function to resolve a single sticking rule after config parsing.
184
 * Returns 1 for success and 0 for failure
185
 */
186
int resolve_stick_rule(struct proxy *curproxy, struct sticking_rule *mrule)
187
0
{
188
0
  struct stktable *target;
189
190
0
  if (mrule->table.name)
191
0
    target = stktable_find_by_name(mrule->table.name);
192
0
  else
193
0
    target = curproxy->table;
194
195
0
  if (!target) {
196
0
    ha_alert("Proxy '%s': unable to find stick-table '%s'.\n",
197
0
             curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
198
0
    return 0;
199
0
  }
200
0
  else if (!stktable_compatible_sample(mrule->expr, target->type)) {
201
0
    ha_alert("Proxy '%s': type of fetch not usable with type of stick-table '%s'.\n",
202
0
             curproxy->id, mrule->table.name ? mrule->table.name : curproxy->id);
203
0
    return 0;
204
0
  }
205
206
  /* success */
207
0
  ha_free(&mrule->table.name);
208
0
  mrule->table.t = target;
209
0
  stktable_alloc_data_type(target, STKTABLE_DT_SERVER_ID, NULL, NULL);
210
0
  stktable_alloc_data_type(target, STKTABLE_DT_SERVER_KEY, NULL, NULL);
211
0
  if (!in_proxies_list(target->proxies_list, curproxy)) {
212
0
    curproxy->next_stkt_ref = target->proxies_list;
213
0
    target->proxies_list = curproxy;
214
0
  }
215
0
  return 1;
216
0
}
217
218
void free_stick_rules(struct list *rules)
219
0
{
220
0
  struct sticking_rule *rule, *ruleb;
221
222
0
  list_for_each_entry_safe(rule, ruleb, rules, list) {
223
0
    LIST_DELETE(&rule->list);
224
0
    free_acl_cond(rule->cond);
225
0
    release_sample_expr(rule->expr);
226
0
    free(rule);
227
0
  }
228
0
}
229
230
void free_server_rules(struct list *srules)
231
0
{
232
0
  struct server_rule *srule, *sruleb;
233
234
0
  list_for_each_entry_safe(srule, sruleb, srules, list) {
235
0
    LIST_DELETE(&srule->list);
236
0
    free_acl_cond(srule->cond);
237
0
    lf_expr_deinit(&srule->expr);
238
0
    free(srule->file);
239
0
    free(srule);
240
0
  }
241
0
}
242
243
/* Frees proxy members that are common to all proxy types (either regular or
244
 * default ones) for a proxy that's about to be destroyed.
245
 * This is a subset of the complete proxy or default proxy deinit code.
246
 */
247
static inline void proxy_free_common(struct proxy *px)
248
0
{
249
0
  struct acl *acl, *aclb;
250
0
  struct logger *log, *logb;
251
0
  struct lf_expr *lf, *lfb;
252
253
  /* First release from global elements under lock protection. */
254
0
  HA_SPIN_LOCK(PROXIES_DEL_LOCK, &proxies_del_lock);
255
  /* note that the node's key points to p->id */
256
0
  cebis_item_delete((px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name, conf.name_node, id, px);
257
0
  LIST_DEL_INIT(&px->global_list);
258
0
  HA_SPIN_UNLOCK(PROXIES_DEL_LOCK, &proxies_del_lock);
259
260
  /* Now release internal proxy elements. */
261
0
  ha_free(&px->id);
262
0
  drop_file_name(&px->conf.file);
263
0
  counters_fe_shared_drop(&px->fe_counters.shared);
264
0
  counters_be_shared_drop(&px->be_counters.shared);
265
0
  ha_free(&px->check_command);
266
0
  ha_free(&px->check_path);
267
0
  ha_free(&px->cookie_name);
268
0
  ha_free(&px->rdp_cookie_name);
269
0
  ha_free(&px->dyncookie_key);
270
0
  ha_free(&px->cookie_domain);
271
0
  ha_free(&px->cookie_attrs);
272
0
  ha_free(&px->lbprm.arg_str);
273
0
  ha_free(&px->capture_name);
274
0
  istfree(&px->monitor_uri);
275
0
  ha_free(&px->conn_src.iface_name);
276
0
#if defined(CONFIG_HAP_TRANSPARENT)
277
0
  ha_free(&px->conn_src.bind_hdr_name);
278
0
#endif
279
0
  istfree(&px->server_id_hdr_name);
280
0
  istfree(&px->header_unique_id);
281
282
0
  http_ext_clean(px);
283
284
0
  list_for_each_entry_safe(acl, aclb, &px->acl, list) {
285
0
    LIST_DELETE(&acl->list);
286
0
    prune_acl(acl);
287
0
    free(acl);
288
0
  }
289
290
0
  free_act_rules(&px->tcp_req.inspect_rules);
291
0
  free_act_rules(&px->tcp_rep.inspect_rules);
292
0
  free_act_rules(&px->tcp_req.l4_rules);
293
0
  free_act_rules(&px->tcp_req.l5_rules);
294
0
  free_act_rules(&px->http_req_rules);
295
0
  free_act_rules(&px->http_res_rules);
296
0
  free_act_rules(&px->http_after_res_rules);
297
#ifdef USE_QUIC
298
  free_act_rules(&px->quic_init_rules);
299
#endif
300
301
0
  lf_expr_deinit(&px->logformat);
302
0
  lf_expr_deinit(&px->logformat_sd);
303
0
  lf_expr_deinit(&px->logformat_error);
304
0
  lf_expr_deinit(&px->format_unique_id);
305
306
0
  list_for_each_entry_safe(log, logb, &px->loggers, list) {
307
0
    LIST_DEL_INIT(&log->list);
308
0
    free_logger(log);
309
0
  }
310
311
  /* ensure that remaining lf_expr that were not postchecked (ie: disabled
312
   * proxy) don't keep a reference on the proxy which is about to be freed.
313
   */
314
0
  list_for_each_entry_safe(lf, lfb, &px->conf.lf_checks, list)
315
0
    LIST_DEL_INIT(&lf->list);
316
317
0
  chunk_destroy(&px->log_tag);
318
319
0
  free_email_alert(px);
320
0
  stats_uri_auth_drop(px->uri_auth);
321
0
  px->uri_auth = NULL;
322
0
}
323
324
/* deinit all <p> proxy members, but doesn't touch to the parent pointer
325
 * itself
326
 */
327
void deinit_proxy(struct proxy *p)
328
0
{
329
0
  struct server *s, *s_back;
330
0
  struct server *defsrv;
331
0
  struct cap_hdr *h,*h_next;
332
0
  struct listener *l,*l_next;
333
0
  struct bind_conf *bind_conf, *bind_back;
334
0
  struct acl_cond *cond, *condb;
335
0
  struct switching_rule *rule, *ruleb;
336
0
  struct redirect_rule *rdr, *rdrb;
337
0
  struct proxy_deinit_fct *pxdf;
338
0
  struct server_deinit_fct *srvdf;
339
340
0
  if (!p)
341
0
    return;
342
343
0
  proxy_free_common(p);
344
345
  /* regular proxy specific cleanup */
346
0
  release_sample_expr(p->lbprm.expr);
347
0
  free(p->server_state_file_name);
348
0
  free(p->invalid_rep);
349
0
  free(p->invalid_req);
350
0
  if ((p->lbprm.algo & BE_LB_LKUP) == BE_LB_LKUP_MAP)
351
0
    free(p->lbprm.map.srv);
352
353
0
  list_for_each_entry_safe(cond, condb, &p->mon_fail_cond, list) {
354
0
    LIST_DELETE(&cond->list);
355
0
    free_acl_cond(cond);
356
0
  }
357
358
0
  guid_remove(&p->guid);
359
360
0
  EXTRA_COUNTERS_FREE(p->extra_counters_fe);
361
0
  EXTRA_COUNTERS_FREE(p->extra_counters_be);
362
363
0
  list_for_each_entry_safe(rule, ruleb, &p->persist_rules, list) {
364
0
    LIST_DELETE(&rule->list);
365
0
    free_acl_cond(rule->cond);
366
0
    free(rule);
367
0
  }
368
369
0
  free_server_rules(&p->server_rules);
370
371
0
  list_for_each_entry_safe(rule, ruleb, &p->switching_rules, list) {
372
0
    LIST_DELETE(&rule->list);
373
0
    free_acl_cond(rule->cond);
374
0
    if (rule->dynamic)
375
0
      lf_expr_deinit(&rule->be.expr);
376
0
    free(rule->file);
377
0
    free(rule);
378
0
  }
379
380
0
  list_for_each_entry_safe(rdr, rdrb, &p->redirect_rules, list) {
381
0
    LIST_DELETE(&rdr->list);
382
0
    http_free_redirect_rule(rdr);
383
0
  }
384
385
0
  free_stick_rules(&p->storersp_rules);
386
0
  free_stick_rules(&p->sticking_rules);
387
388
0
  h = p->req_cap;
389
0
  while (h) {
390
0
    if (p->defpx && h == p->defpx->req_cap)
391
0
      break;
392
0
    h_next = h->next;
393
0
    free(h->name);
394
0
    pool_destroy(h->pool);
395
0
    free(h);
396
0
    h = h_next;
397
0
  }/* end while(h) */
398
399
0
  h = p->rsp_cap;
400
0
  while (h) {
401
0
    if (p->defpx && h == p->defpx->rsp_cap)
402
0
      break;
403
0
    h_next = h->next;
404
0
    free(h->name);
405
0
    pool_destroy(h->pool);
406
0
    free(h);
407
0
    h = h_next;
408
0
  }/* end while(h) */
409
410
0
  list_for_each_entry_safe(s, s_back, &p->servers, el_px) {
411
0
    list_for_each_entry(srvdf, &server_deinit_list, list)
412
0
      srvdf->fct(s);
413
414
0
    if (p->lbprm.ops && p->lbprm.ops->server_deinit)
415
0
      p->lbprm.ops->server_deinit(s);
416
417
0
    srv_drop(s);
418
0
  }/* end while(s) */
419
420
  /* also free default-server parameters since some of them might have
421
   * been dynamically allocated (e.g.: config hints, cookies, ssl..)
422
   */
423
0
  if (p->defsrv) {
424
0
    srv_free_params(p->defsrv);
425
0
    srv_free(&p->defsrv);
426
0
  }
427
428
0
  while ((defsrv = cebuis_item_first(&p->defsrv_by_name, conf.name_node, id, struct server))) {
429
0
    cebuis_item_delete(&p->defsrv_by_name, conf.name_node, id, defsrv);
430
0
    srv_free_params(defsrv);
431
0
    srv_free(&defsrv);
432
0
  }
433
434
0
  if (p->lbprm.ops && p->lbprm.ops->proxy_deinit)
435
0
    p->lbprm.ops->proxy_deinit(p);
436
437
0
  list_for_each_entry_safe(l, l_next, &p->conf.listeners, by_fe) {
438
0
    guid_remove(&l->guid);
439
0
    LIST_DELETE(&l->by_fe);
440
0
    LIST_DELETE(&l->by_bind);
441
0
    free(l->name);
442
0
    free(l->label);
443
0
    free(l->per_thr);
444
0
    if (l->counters) {
445
0
      counters_fe_shared_drop(&l->counters->shared);
446
0
      free(l->counters);
447
0
    }
448
0
    task_destroy(l->rx.rhttp.task);
449
450
0
    EXTRA_COUNTERS_FREE(l->extra_counters);
451
0
    free(l);
452
0
  }
453
454
  /* Release unused SSL configs. */
455
0
  list_for_each_entry_safe(bind_conf, bind_back, &p->conf.bind, by_fe) {
456
0
    if (bind_conf->xprt->destroy_bind_conf)
457
0
      bind_conf->xprt->destroy_bind_conf(bind_conf);
458
0
    free(bind_conf->file);
459
0
    free(bind_conf->arg);
460
0
    free(bind_conf->settings.interface);
461
0
    LIST_DELETE(&bind_conf->by_fe);
462
0
    free(bind_conf->guid_prefix);
463
0
    free(bind_conf->rhttp_srvname);
464
0
    free(bind_conf->tcp_md5sig);
465
0
    free(bind_conf->cc_algo);
466
0
    free(bind_conf);
467
0
  }
468
469
0
  flt_deinit(p);
470
471
0
  list_for_each_entry(pxdf, &proxy_deinit_list, list)
472
0
    pxdf->fct(p);
473
474
0
  free(p->desc);
475
476
0
  task_destroy(p->task);
477
478
0
  pool_destroy(p->req_cap_pool);
479
0
  pool_destroy(p->rsp_cap_pool);
480
481
0
  stktable_deinit(p->table);
482
0
  ha_free(&p->table);
483
0
  ha_free(&p->per_tgrp);
484
485
0
  HA_RWLOCK_DESTROY(&p->lbprm.lock);
486
0
  HA_RWLOCK_DESTROY(&p->lock);
487
488
0
  proxy_unref_defaults(p);
489
0
}
490
491
/* Decrement <p> refcount and free it if null. For a default proxy instance,
492
 * refcount is ignored and free is immediately performed.
493
 */
494
void proxy_drop(struct proxy *p)
495
0
{
496
0
  if (!p)
497
0
    return;
498
499
0
  if (!(p->cap & PR_CAP_DEF)) {
500
0
    if (HA_ATOMIC_SUB_FETCH(&p->refcount, 1))
501
0
      return;
502
0
  }
503
504
0
  deinit_proxy(p);
505
0
  ha_free(&p);
506
0
}
507
508
/*
509
 * This function returns a string containing a name describing capabilities to
510
 * report comprehensible error messages. Specifically, it will return the words
511
 * "frontend", "backend" when appropriate, "defaults" if it corresponds to a
512
 * defaults section, or "proxy" for all other cases including the proxies
513
 * declared in "listen" mode.
514
 */
515
const char *proxy_cap_str(int cap)
516
0
{
517
0
  if (cap & PR_CAP_DEF)
518
0
    return "defaults";
519
520
0
  if ((cap & PR_CAP_LISTEN) != PR_CAP_LISTEN) {
521
0
    if (cap & PR_CAP_FE)
522
0
      return "frontend";
523
0
    else if (cap & PR_CAP_BE)
524
0
      return "backend";
525
0
  }
526
0
  return "proxy";
527
0
}
528
529
/*
530
 * This function returns a string containing the mode of the proxy in a format
531
 * suitable for error messages.
532
 */
533
0
const char *proxy_mode_str(int mode) {
534
535
0
  if (mode == PR_MODE_TCP)
536
0
    return "tcp";
537
0
  else if (mode == PR_MODE_HTTP)
538
0
    return "http";
539
0
  else if (mode == PR_MODE_CLI)
540
0
    return "cli";
541
0
  else if (mode == PR_MODE_SYSLOG)
542
0
    return "syslog";
543
0
  else if (mode == PR_MODE_PEERS)
544
0
    return "peers";
545
0
  else if (mode == PR_MODE_SPOP)
546
0
    return "spop";
547
0
  else
548
0
    return "unknown";
549
0
}
550
551
/* Convert <mode> string into proxy mode type. PR_MODES is returned for unknown values. */
552
enum pr_mode str_to_proxy_mode(const char *mode)
553
0
{
554
0
  if (strcmp(mode, "http") == 0)
555
0
    return PR_MODE_HTTP;
556
0
  else if (strcmp(mode, "tcp") == 0)
557
0
    return PR_MODE_TCP;
558
0
  else if (strcmp(mode, "log") == 0)
559
0
    return PR_MODE_SYSLOG;
560
0
  else if (strcmp(mode, "spop") == 0)
561
0
    return PR_MODE_SPOP;
562
563
0
  return PR_MODES;
564
0
}
565
566
/* try to find among known options the one that looks closest to <word> by
567
 * counting transitions between letters, digits and other characters. Will
568
 * return the best matching word if found, otherwise NULL. An optional array
569
 * of extra words to compare may be passed in <extra>, but it must then be
570
 * terminated by a NULL entry. If unused it may be NULL.
571
 */
572
const char *proxy_find_best_option(const char *word, const char **extra)
573
0
{
574
0
  uint8_t word_sig[1024];
575
0
  uint8_t list_sig[1024];
576
0
  const char *best_ptr = NULL;
577
0
  int dist, best_dist = INT_MAX;
578
0
  int index;
579
580
0
  make_word_fingerprint(word_sig, word);
581
582
0
  for (index = 0; cfg_opts[index].name; index++) {
583
0
    make_word_fingerprint(list_sig, cfg_opts[index].name);
584
0
    dist = word_fingerprint_distance(word_sig, list_sig);
585
0
    if (dist < best_dist) {
586
0
      best_dist = dist;
587
0
      best_ptr = cfg_opts[index].name;
588
0
    }
589
0
  }
590
591
0
  for (index = 0; cfg_opts2[index].name; index++) {
592
0
    make_word_fingerprint(list_sig, cfg_opts2[index].name);
593
0
    dist = word_fingerprint_distance(word_sig, list_sig);
594
0
    if (dist < best_dist) {
595
0
      best_dist = dist;
596
0
      best_ptr = cfg_opts2[index].name;
597
0
    }
598
0
  }
599
600
0
  while (extra && *extra) {
601
0
    make_word_fingerprint(list_sig, *extra);
602
0
    dist = word_fingerprint_distance(word_sig, list_sig);
603
0
    if (dist < best_dist) {
604
0
      best_dist = dist;
605
0
      best_ptr = *extra;
606
0
    }
607
0
    extra++;
608
0
  }
609
610
0
  if (best_dist > 2 * strlen(word) || (best_ptr && best_dist > 2 * strlen(best_ptr)))
611
0
    best_ptr = NULL;
612
0
  return best_ptr;
613
0
}
614
615
/* This function returns the first unused proxy ID greater than or equal to
616
 * <from> in used_proxy_id. Zero is returned if no spare one is found (should
617
 * never happen).
618
 */
619
uint proxy_get_next_id(uint from)
620
0
{
621
0
  const struct proxy *px;
622
623
0
  do {
624
0
    px = ceb32_item_lookup_ge(&used_proxy_id, conf.uuid_node, uuid, from, struct proxy);
625
0
    if (!px || px->uuid > from)
626
0
      return from; /* available */
627
0
    from++;
628
0
  } while (from);
629
0
  return from;
630
0
}
631
632
/* This function parses a "timeout" statement in a proxy section. It returns
633
 * -1 if there is any error, 1 for a warning, otherwise zero. If it does not
634
 * return zero, it will write an error or warning message into a preallocated
635
 * buffer returned at <err>. The trailing is not be written. The function must
636
 * be called with <args> pointing to the first command line word, with <proxy>
637
 * pointing to the proxy being parsed, and <defpx> to the default proxy or NULL.
638
 * As a special case for compatibility with older configs, it also accepts
639
 * "{cli|srv|con}timeout" in args[0].
640
 */
641
static int proxy_parse_timeout(char **args, int section, struct proxy *proxy,
642
                               const struct proxy *defpx, const char *file, int line,
643
                               char **err)
644
0
{
645
0
  unsigned timeout;
646
0
  int retval, cap;
647
0
  const char *res, *name;
648
0
  int *tv = NULL;
649
0
  const int *td = NULL;
650
651
0
  retval = 0;
652
653
  /* simply skip "timeout" but remain compatible with old form */
654
0
  if (strcmp(args[0], "timeout") == 0)
655
0
    args++;
656
657
0
  name = args[0];
658
0
  if (strcmp(args[0], "client") == 0) {
659
0
    name = "client";
660
0
    tv = &proxy->timeout.client;
661
0
    td = &defpx->timeout.client;
662
0
    cap = PR_CAP_FE;
663
0
  } else if (strcmp(args[0], "tarpit") == 0) {
664
0
    tv = &proxy->timeout.tarpit;
665
0
    td = &defpx->timeout.tarpit;
666
0
    cap = PR_CAP_FE | PR_CAP_BE;
667
0
  } else if (strcmp(args[0], "client-hs") == 0) {
668
0
    tv = &proxy->timeout.client_hs;
669
0
    td = &defpx->timeout.client_hs;
670
0
    cap = PR_CAP_FE;
671
0
  } else if (strcmp(args[0], "http-keep-alive") == 0) {
672
0
    tv = &proxy->timeout.httpka;
673
0
    td = &defpx->timeout.httpka;
674
0
    cap = PR_CAP_FE | PR_CAP_BE;
675
0
  } else if (strcmp(args[0], "http-request") == 0) {
676
0
    tv = &proxy->timeout.httpreq;
677
0
    td = &defpx->timeout.httpreq;
678
0
    cap = PR_CAP_FE | PR_CAP_BE;
679
0
  } else if (strcmp(args[0], "server") == 0) {
680
0
    name = "server";
681
0
    tv = &proxy->timeout.server;
682
0
    td = &defpx->timeout.server;
683
0
    cap = PR_CAP_BE;
684
0
  } else if (strcmp(args[0], "connect") == 0) {
685
0
    name = "connect";
686
0
    tv = &proxy->timeout.connect;
687
0
    td = &defpx->timeout.connect;
688
0
    cap = PR_CAP_BE;
689
0
  } else if (strcmp(args[0], "check") == 0) {
690
0
    tv = &proxy->timeout.check;
691
0
    td = &defpx->timeout.check;
692
0
    cap = PR_CAP_BE;
693
0
  } else if (strcmp(args[0], "queue") == 0) {
694
0
    tv = &proxy->timeout.queue;
695
0
    td = &defpx->timeout.queue;
696
0
    cap = PR_CAP_BE;
697
0
  } else if (strcmp(args[0], "tunnel") == 0) {
698
0
    tv = &proxy->timeout.tunnel;
699
0
    td = &defpx->timeout.tunnel;
700
0
    cap = PR_CAP_BE;
701
0
  } else if (strcmp(args[0], "client-fin") == 0) {
702
0
    tv = &proxy->timeout.clientfin;
703
0
    td = &defpx->timeout.clientfin;
704
0
    cap = PR_CAP_FE;
705
0
  } else if (strcmp(args[0], "server-fin") == 0) {
706
0
    tv = &proxy->timeout.serverfin;
707
0
    td = &defpx->timeout.serverfin;
708
0
    cap = PR_CAP_BE;
709
0
  } else if (strcmp(args[0], "clitimeout") == 0) {
710
0
    memprintf(err, "the '%s' directive is not supported anymore since HAProxy 2.1. Use 'timeout client'.", args[0]);
711
0
    return -1;
712
0
  } else if (strcmp(args[0], "srvtimeout") == 0) {
713
0
    memprintf(err, "the '%s' directive is not supported anymore since HAProxy 2.1. Use 'timeout server'.", args[0]);
714
0
    return -1;
715
0
  } else if (strcmp(args[0], "contimeout") == 0) {
716
0
    memprintf(err, "the '%s' directive is not supported anymore since HAProxy 2.1. Use 'timeout connect'.", args[0]);
717
0
    return -1;
718
0
  } else {
719
0
    memprintf(err,
720
0
              "'timeout' supports 'client', 'server', 'connect', 'check', "
721
0
              "'queue', 'handshake', 'http-keep-alive', 'http-request', 'tunnel', 'tarpit', "
722
0
        "'client-fin' and 'server-fin' (got '%s')",
723
0
              args[0]);
724
0
    return -1;
725
0
  }
726
727
0
  if (*args[1] == 0) {
728
0
    memprintf(err, "'timeout %s' expects an integer value (in milliseconds)", name);
729
0
    return -1;
730
0
  }
731
732
0
  res = parse_time_err(args[1], &timeout, TIME_UNIT_MS);
733
0
  if (res == PARSE_TIME_OVER) {
734
0
    memprintf(err, "timer overflow in argument '%s' to 'timeout %s' (maximum value is 2147483647 ms or ~24.8 days)",
735
0
        args[1], name);
736
0
    return -1;
737
0
  }
738
0
  else if (res == PARSE_TIME_UNDER) {
739
0
    memprintf(err, "timer underflow in argument '%s' to 'timeout %s' (minimum non-null value is 1 ms)",
740
0
        args[1], name);
741
0
    return -1;
742
0
  }
743
0
  else if (res) {
744
0
    memprintf(err, "unexpected character '%c' in 'timeout %s'", *res, name);
745
0
    return -1;
746
0
  }
747
748
0
  if (warn_if_lower(args[1], 100)) {
749
0
    memprintf(err, "'timeout %s %u' in %s '%s' is suspiciously small for a value in milliseconds. Please use an explicit unit ('%ums') if that was the intent.",
750
0
              name, timeout, proxy_type_str(proxy), proxy->id, timeout);
751
0
    retval = 1;
752
0
  }
753
754
0
  if (!(proxy->cap & cap)) {
755
0
    memprintf(err, "'timeout %s' will be ignored because %s '%s' has no %s capability",
756
0
              name, proxy_type_str(proxy), proxy->id,
757
0
              (cap & PR_CAP_BE) ? "backend" : "frontend");
758
0
    retval = 1;
759
0
  }
760
0
  else if (defpx && *tv != *td) {
761
0
    memprintf(err, "overwriting 'timeout %s' which was already specified", name);
762
0
    retval = 1;
763
0
  }
764
765
0
  if (*args[2] != 0) {
766
0
    memprintf(err, "'timeout %s' : unexpected extra argument '%s' after value '%s'.", name, args[2], args[1]);
767
0
    retval = -1;
768
0
  }
769
770
0
  *tv = MS_TO_TICKS(timeout);
771
0
  return retval;
772
0
}
773
774
/* This function parses a "rate-limit" statement in a proxy section. It returns
775
 * -1 if there is any error, 1 for a warning, otherwise zero. If it does not
776
 * return zero, it will write an error or warning message into a preallocated
777
 * buffer returned at <err>. The function must be called with <args> pointing
778
 * to the first command line word, with <proxy> pointing to the proxy being
779
 * parsed, and <defpx> to the default proxy or NULL.
780
 */
781
static int proxy_parse_rate_limit(char **args, int section, struct proxy *proxy,
782
                                  const struct proxy *defpx, const char *file, int line,
783
                                  char **err)
784
0
{
785
0
  int retval;
786
0
  char *res;
787
0
  unsigned int *tv = NULL;
788
0
  const unsigned int *td = NULL;
789
0
  unsigned int val;
790
791
0
  retval = 0;
792
793
0
  if (strcmp(args[1], "sessions") == 0) {
794
0
    tv = &proxy->fe_sps_lim;
795
0
    td = &defpx->fe_sps_lim;
796
0
  }
797
0
  else {
798
0
    memprintf(err, "'%s' only supports 'sessions' (got '%s')", args[0], args[1]);
799
0
    return -1;
800
0
  }
801
802
0
  if (*args[2] == 0) {
803
0
    memprintf(err, "'%s %s' expects expects an integer value (in sessions/second)", args[0], args[1]);
804
0
    return -1;
805
0
  }
806
807
0
  val = strtoul(args[2], &res, 0);
808
0
  if (*res) {
809
0
    memprintf(err, "'%s %s' : unexpected character '%c' in integer value '%s'", args[0], args[1], *res, args[2]);
810
0
    return -1;
811
0
  }
812
813
0
  if (!(proxy->cap & PR_CAP_FE)) {
814
0
    memprintf(err, "%s %s will be ignored because %s '%s' has no frontend capability",
815
0
        args[0], args[1], proxy_type_str(proxy), proxy->id);
816
0
    retval = 1;
817
0
  }
818
0
  else if (defpx && *tv != *td) {
819
0
    memprintf(err, "overwriting %s %s which was already specified", args[0], args[1]);
820
0
    retval = 1;
821
0
  }
822
823
0
  *tv = val;
824
0
  return retval;
825
0
}
826
827
/* This function parses a "max-keep-alive-queue" statement in a proxy section.
828
 * It returns -1 if there is any error, 1 for a warning, otherwise zero. If it
829
 * does not return zero, it will write an error or warning message into a
830
 * preallocated buffer returned at <err>. The function must be called with
831
 * <args> pointing to the first command line word, with <proxy> pointing to
832
 * the proxy being parsed, and <defpx> to the default proxy or NULL.
833
 */
834
static int proxy_parse_max_ka_queue(char **args, int section, struct proxy *proxy,
835
                                    const struct proxy *defpx, const char *file, int line,
836
                                    char **err)
837
0
{
838
0
  int retval;
839
0
  char *res;
840
0
  unsigned int val;
841
842
0
  retval = 0;
843
844
0
  if (*args[1] == 0) {
845
0
    memprintf(err, "'%s' expects expects an integer value (or -1 to disable)", args[0]);
846
0
    return -1;
847
0
  }
848
849
0
  val = strtol(args[1], &res, 0);
850
0
  if (*res) {
851
0
    memprintf(err, "'%s' : unexpected character '%c' in integer value '%s'", args[0], *res, args[1]);
852
0
    return -1;
853
0
  }
854
855
0
  if (!(proxy->cap & PR_CAP_BE)) {
856
0
    memprintf(err, "%s will be ignored because %s '%s' has no backend capability",
857
0
              args[0], proxy_type_str(proxy), proxy->id);
858
0
    retval = 1;
859
0
  }
860
861
  /* we store <val+1> so that a user-facing value of -1 is stored as zero (default) */
862
0
  proxy->max_ka_queue = val + 1;
863
0
  return retval;
864
0
}
865
866
/* This function parses a "declare" statement in a proxy section. It returns -1
867
 * if there is any error, 1 for warning, otherwise 0. If it does not return zero,
868
 * it will write an error or warning message into a preallocated buffer returned
869
 * at <err>. The function must be called with <args> pointing to the first command
870
 * line word, with <proxy> pointing to the proxy being parsed, and <defpx> to the
871
 * default proxy or NULL.
872
 */
873
static int proxy_parse_declare(char **args, int section, struct proxy *curpx,
874
                               const struct proxy *defpx, const char *file, int line,
875
                               char **err)
876
0
{
877
  /* Capture keyword wannot be declared in a default proxy. */
878
0
  if (curpx == defpx) {
879
0
    memprintf(err, "'%s' not available in default section", args[0]);
880
0
    return -1;
881
0
  }
882
883
  /* Capture keyword is only available in frontend. */
884
0
  if (!(curpx->cap & PR_CAP_FE)) {
885
0
    memprintf(err, "'%s' only available in frontend or listen section", args[0]);
886
0
    return -1;
887
0
  }
888
889
  /* Check mandatory second keyword. */
890
0
  if (!args[1] || !*args[1]) {
891
0
    memprintf(err, "'%s' needs a second keyword that specify the type of declaration ('capture')", args[0]);
892
0
    return -1;
893
0
  }
894
895
  /* Actually, declare is only available for declaring capture
896
   * slot, but in the future it can declare maps or variables.
897
   * So, this section permits to check and switch according with
898
   * the second keyword.
899
   */
900
0
  if (strcmp(args[1], "capture") == 0) {
901
0
    char *error = NULL;
902
0
    long len;
903
0
    struct cap_hdr *hdr;
904
905
    /* Check the next keyword. */
906
0
    if (!args[2] || !*args[2] ||
907
0
        (strcmp(args[2], "response") != 0 &&
908
0
         strcmp(args[2], "request") != 0)) {
909
0
      memprintf(err, "'%s %s' requires a direction ('request' or 'response')", args[0], args[1]);
910
0
      return -1;
911
0
    }
912
913
    /* Check the 'len' keyword. */
914
0
    if (!args[3] || !*args[3] || strcmp(args[3], "len") != 0) {
915
0
      memprintf(err, "'%s %s' requires a capture length ('len')", args[0], args[1]);
916
0
      return -1;
917
0
    }
918
919
    /* Check the length value. */
920
0
    if (!args[4] || !*args[4]) {
921
0
      memprintf(err, "'%s %s': 'len' requires a numeric value that represents the "
922
0
                     "capture length",
923
0
                args[0], args[1]);
924
0
      return -1;
925
0
    }
926
927
    /* convert the length value. */
928
0
    len = strtol(args[4], &error, 10);
929
0
    if (*error != '\0') {
930
0
      memprintf(err, "'%s %s': cannot parse the length '%s'.",
931
0
                args[0], args[1], args[4]);
932
0
      return -1;
933
0
    }
934
935
    /* check length. */
936
0
    if (len <= 0) {
937
0
      memprintf(err, "length must be > 0");
938
0
      return -1;
939
0
    }
940
941
    /* register the capture. */
942
0
    hdr = calloc(1, sizeof(*hdr));
943
0
    if (!hdr) {
944
0
      memprintf(err, "proxy '%s': out of memory while registering a capture", curpx->id);
945
0
      return -1;
946
0
    }
947
0
    hdr->name = NULL; /* not a header capture */
948
0
    hdr->namelen = 0;
949
0
    hdr->len = len;
950
0
    hdr->pool = create_pool("caphdr", hdr->len + 1, MEM_F_SHARED);
951
0
    if (!hdr->pool) {
952
0
      memprintf(err, "out of memory");
953
0
      free(hdr);
954
0
      return -1;
955
0
    }
956
957
0
    if (strcmp(args[2], "request") == 0) {
958
0
      hdr->next = curpx->req_cap;
959
0
      hdr->index = curpx->nb_req_cap++;
960
0
      curpx->req_cap = hdr;
961
0
    }
962
0
    if (strcmp(args[2], "response") == 0) {
963
0
      hdr->next = curpx->rsp_cap;
964
0
      hdr->index = curpx->nb_rsp_cap++;
965
0
      curpx->rsp_cap = hdr;
966
0
    }
967
0
    return 0;
968
0
  }
969
0
  else {
970
0
    memprintf(err, "unknown declaration type '%s' (supports 'capture')", args[1]);
971
0
    return -1;
972
0
  }
973
0
}
974
975
/* This function parses a "retry-on" statement */
976
static int
977
proxy_parse_retry_on(char **args, int section, struct proxy *curpx,
978
                               const struct proxy *defpx, const char *file, int line,
979
                               char **err)
980
0
{
981
0
  int i;
982
983
0
  if (!(*args[1])) {
984
0
    memprintf(err, "'%s' needs at least one keyword to specify when to retry", args[0]);
985
0
    return -1;
986
0
  }
987
0
  if (!(curpx->cap & PR_CAP_BE)) {
988
0
    memprintf(err, "'%s' only available in backend or listen section", args[0]);
989
0
    return -1;
990
0
  }
991
0
  curpx->retry_type = 0;
992
0
  for (i = 1; *(args[i]); i++) {
993
0
    if (strcmp(args[i], "conn-failure") == 0)
994
0
      curpx->retry_type |= PR_RE_CONN_FAILED;
995
0
    else if (strcmp(args[i], "empty-response") == 0)
996
0
      curpx->retry_type |= PR_RE_DISCONNECTED;
997
0
    else if (strcmp(args[i], "response-timeout") == 0)
998
0
      curpx->retry_type |= PR_RE_TIMEOUT;
999
0
    else if (strcmp(args[i], "401") == 0)
1000
0
      curpx->retry_type |= PR_RE_401;
1001
0
    else if (strcmp(args[i], "403") == 0)
1002
0
      curpx->retry_type |= PR_RE_403;
1003
0
    else if (strcmp(args[i], "404") == 0)
1004
0
      curpx->retry_type |= PR_RE_404;
1005
0
    else if (strcmp(args[i], "408") == 0)
1006
0
      curpx->retry_type |= PR_RE_408;
1007
0
    else if (strcmp(args[i], "421") == 0)
1008
0
      curpx->retry_type |= PR_RE_421;
1009
0
    else if (strcmp(args[i], "425") == 0)
1010
0
      curpx->retry_type |= PR_RE_425;
1011
0
    else if (strcmp(args[i], "429") == 0)
1012
0
      curpx->retry_type |= PR_RE_429;
1013
0
    else if (strcmp(args[i], "500") == 0)
1014
0
      curpx->retry_type |= PR_RE_500;
1015
0
    else if (strcmp(args[i], "501") == 0)
1016
0
      curpx->retry_type |= PR_RE_501;
1017
0
    else if (strcmp(args[i], "502") == 0)
1018
0
      curpx->retry_type |= PR_RE_502;
1019
0
    else if (strcmp(args[i], "503") == 0)
1020
0
      curpx->retry_type |= PR_RE_503;
1021
0
    else if (strcmp(args[i], "504") == 0)
1022
0
      curpx->retry_type |= PR_RE_504;
1023
0
    else if (strcmp(args[i], "0rtt-rejected") == 0)
1024
0
      curpx->retry_type |= PR_RE_EARLY_ERROR;
1025
0
    else if (strcmp(args[i], "junk-response") == 0)
1026
0
      curpx->retry_type |= PR_RE_JUNK_REQUEST;
1027
0
    else if (!(strcmp(args[i], "all-retryable-errors")))
1028
0
      curpx->retry_type |= PR_RE_CONN_FAILED | PR_RE_DISCONNECTED |
1029
0
                           PR_RE_TIMEOUT | PR_RE_500 | PR_RE_502 |
1030
0
               PR_RE_503 | PR_RE_504 | PR_RE_EARLY_ERROR |
1031
0
               PR_RE_JUNK_REQUEST;
1032
0
    else if (strcmp(args[i], "none") == 0) {
1033
0
      if (i != 1 || *args[i + 1]) {
1034
0
        memprintf(err, "'%s' 'none' keyword only usable alone", args[0]);
1035
0
        return -1;
1036
0
      }
1037
0
    } else {
1038
0
      memprintf(err, "'%s': unknown keyword '%s'", args[0], args[i]);
1039
0
      return -1;
1040
0
    }
1041
1042
0
  }
1043
1044
1045
0
  return 0;
1046
0
}
1047
1048
/* This function parses a "hash-preserve-affinity" statement */
1049
static int
1050
proxy_parse_hash_preserve_affinity(char **args, int section, struct proxy *curpx,
1051
                  const struct proxy *defpx, const char *file, int line,
1052
                  char **err)
1053
0
{
1054
0
  if (!(*args[1])) {
1055
0
    memprintf(err, "'%s' needs a keyword to specify when to preserve hash affinity", args[0]);
1056
0
    return -1;
1057
0
  }
1058
0
  if (!(curpx->cap & PR_CAP_BE)) {
1059
0
    memprintf(err, "'%s' only available in backend or listen section", args[0]);
1060
0
    return -1;
1061
0
  }
1062
1063
0
  curpx->options3 &= ~PR_O3_HASHAFNTY_MASK;
1064
1065
0
  if (strcmp(args[1], "always") == 0)
1066
0
    curpx->options3 |= PR_O3_HASHAFNTY_ALWS;
1067
0
  else if (strcmp(args[1], "maxconn") == 0)
1068
0
    curpx->options3 |= PR_O3_HASHAFNTY_MAXCONN;
1069
0
  else if (strcmp(args[1], "maxqueue") == 0)
1070
0
    curpx->options3 |= PR_O3_HASHAFNTY_MAXQUEUE;
1071
0
  else {
1072
0
    memprintf(err, "'%s': unknown keyword '%s'", args[0], args[1]);
1073
0
    return -1;
1074
0
  }
1075
1076
0
  return 0;
1077
0
}
1078
1079
#ifdef TCP_KEEPCNT
1080
/* This function parses "{cli|srv}tcpka-cnt" statements */
1081
static int proxy_parse_tcpka_cnt(char **args, int section, struct proxy *proxy,
1082
                                    const struct proxy *defpx, const char *file, int line,
1083
                                    char **err)
1084
0
{
1085
0
  int retval;
1086
0
  char *res;
1087
0
  unsigned int tcpka_cnt;
1088
1089
0
  retval = 0;
1090
1091
0
  if (*args[1] == 0) {
1092
0
    memprintf(err, "'%s' expects an integer value", args[0]);
1093
0
    return -1;
1094
0
  }
1095
1096
0
  tcpka_cnt = strtol(args[1], &res, 0);
1097
0
  if (*res) {
1098
0
    memprintf(err, "'%s' : unexpected character '%c' in integer value '%s'", args[0], *res, args[1]);
1099
0
    return -1;
1100
0
  }
1101
1102
0
  if (strcmp(args[0], "clitcpka-cnt") == 0) {
1103
0
    if (!(proxy->cap & PR_CAP_FE)) {
1104
0
      memprintf(err, "%s will be ignored because %s '%s' has no frontend capability",
1105
0
                args[0], proxy_type_str(proxy), proxy->id);
1106
0
      retval = 1;
1107
0
    }
1108
0
    proxy->clitcpka_cnt = tcpka_cnt;
1109
0
  } else if (strcmp(args[0], "srvtcpka-cnt") == 0) {
1110
0
    if (!(proxy->cap & PR_CAP_BE)) {
1111
0
      memprintf(err, "%s will be ignored because %s '%s' has no backend capability",
1112
0
                args[0], proxy_type_str(proxy), proxy->id);
1113
0
      retval = 1;
1114
0
    }
1115
0
    proxy->srvtcpka_cnt = tcpka_cnt;
1116
0
  } else {
1117
    /* unreachable */
1118
0
    memprintf(err, "'%s': unknown keyword", args[0]);
1119
0
    return -1;
1120
0
  }
1121
1122
0
  return retval;
1123
0
}
1124
#endif
1125
1126
#ifdef TCP_KEEPIDLE
1127
/* This function parses "{cli|srv}tcpka-idle" statements */
1128
static int proxy_parse_tcpka_idle(char **args, int section, struct proxy *proxy,
1129
                                  const struct proxy *defpx, const char *file, int line,
1130
                                  char **err)
1131
0
{
1132
0
  int retval;
1133
0
  const char *res;
1134
0
  unsigned int tcpka_idle;
1135
1136
0
  retval = 0;
1137
1138
0
  if (*args[1] == 0) {
1139
0
    memprintf(err, "'%s' expects an integer value", args[0]);
1140
0
    return -1;
1141
0
  }
1142
0
  res = parse_time_err(args[1], &tcpka_idle, TIME_UNIT_S);
1143
0
  if (res == PARSE_TIME_OVER) {
1144
0
    memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
1145
0
        args[1], args[0]);
1146
0
    return -1;
1147
0
  }
1148
0
  else if (res == PARSE_TIME_UNDER) {
1149
0
    memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
1150
0
        args[1], args[0]);
1151
0
    return -1;
1152
0
  }
1153
0
  else if (res) {
1154
0
    memprintf(err, "unexpected character '%c' in argument to <%s>.\n", *res, args[0]);
1155
0
    return -1;
1156
0
  }
1157
1158
0
  if (strcmp(args[0], "clitcpka-idle") == 0) {
1159
0
    if (!(proxy->cap & PR_CAP_FE)) {
1160
0
      memprintf(err, "%s will be ignored because %s '%s' has no frontend capability",
1161
0
                args[0], proxy_type_str(proxy), proxy->id);
1162
0
      retval = 1;
1163
0
    }
1164
0
    proxy->clitcpka_idle = tcpka_idle;
1165
0
  } else if (strcmp(args[0], "srvtcpka-idle") == 0) {
1166
0
    if (!(proxy->cap & PR_CAP_BE)) {
1167
0
      memprintf(err, "%s will be ignored because %s '%s' has no backend capability",
1168
0
                args[0], proxy_type_str(proxy), proxy->id);
1169
0
      retval = 1;
1170
0
    }
1171
0
    proxy->srvtcpka_idle = tcpka_idle;
1172
0
  } else {
1173
    /* unreachable */
1174
0
    memprintf(err, "'%s': unknown keyword", args[0]);
1175
0
    return -1;
1176
0
  }
1177
1178
0
  return retval;
1179
0
}
1180
#endif
1181
1182
#ifdef TCP_KEEPINTVL
1183
/* This function parses "{cli|srv}tcpka-intvl" statements */
1184
static int proxy_parse_tcpka_intvl(char **args, int section, struct proxy *proxy,
1185
                       const struct proxy *defpx, const char *file, int line,
1186
                                   char **err)
1187
0
{
1188
0
  int retval;
1189
0
  const char *res;
1190
0
  unsigned int tcpka_intvl;
1191
1192
0
  retval = 0;
1193
1194
0
  if (*args[1] == 0) {
1195
0
    memprintf(err, "'%s' expects an integer value", args[0]);
1196
0
    return -1;
1197
0
  }
1198
0
  res = parse_time_err(args[1], &tcpka_intvl, TIME_UNIT_S);
1199
0
  if (res == PARSE_TIME_OVER) {
1200
0
    memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
1201
0
        args[1], args[0]);
1202
0
    return -1;
1203
0
  }
1204
0
  else if (res == PARSE_TIME_UNDER) {
1205
0
    memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
1206
0
        args[1], args[0]);
1207
0
    return -1;
1208
0
  }
1209
0
  else if (res) {
1210
0
    memprintf(err, "unexpected character '%c' in argument to <%s>.\n", *res, args[0]);
1211
0
    return -1;
1212
0
  }
1213
1214
0
  if (strcmp(args[0], "clitcpka-intvl") == 0) {
1215
0
    if (!(proxy->cap & PR_CAP_FE)) {
1216
0
      memprintf(err, "%s will be ignored because %s '%s' has no frontend capability",
1217
0
                args[0], proxy_type_str(proxy), proxy->id);
1218
0
      retval = 1;
1219
0
    }
1220
0
    proxy->clitcpka_intvl = tcpka_intvl;
1221
0
  } else if (strcmp(args[0], "srvtcpka-intvl") == 0) {
1222
0
    if (!(proxy->cap & PR_CAP_BE)) {
1223
0
      memprintf(err, "%s will be ignored because %s '%s' has no backend capability",
1224
0
                args[0], proxy_type_str(proxy), proxy->id);
1225
0
      retval = 1;
1226
0
    }
1227
0
    proxy->srvtcpka_intvl = tcpka_intvl;
1228
0
  } else {
1229
    /* unreachable */
1230
0
    memprintf(err, "'%s': unknown keyword", args[0]);
1231
0
    return -1;
1232
0
  }
1233
1234
0
  return retval;
1235
0
}
1236
#endif
1237
1238
/* Parser for "be-unpublished" proxy keyword. */
1239
static int proxy_parse_be_unpublished(char **args, int section_type, struct proxy *curpx,
1240
                                      const struct proxy *defpx, const char *file, int line,
1241
                                      char **err)
1242
0
{
1243
0
  if (curpx->cap & PR_CAP_DEF) {
1244
0
    memprintf(err, "'%s' not allowed in 'defaults' section.", args[0]);
1245
0
    goto err;
1246
0
  }
1247
1248
0
  if (!(curpx->cap & PR_CAP_BE)) {
1249
0
    memprintf(err, "'%s' only available in backend or listen section.", args[0]);
1250
0
    goto err;
1251
0
  }
1252
1253
0
  curpx->flags |= PR_FL_BE_UNPUBLISHED;
1254
1255
0
  return 0;
1256
1257
0
 err:
1258
0
  return -1;
1259
0
}
1260
1261
static int proxy_parse_force_be_switch(char **args, int section_type, struct proxy *curpx,
1262
                                       const struct proxy *defpx, const char *file, int line,
1263
                                       char **err)
1264
0
{
1265
0
  struct acl_cond *cond = NULL;
1266
0
  struct persist_rule *rule;
1267
1268
0
  if (curpx->cap & PR_CAP_DEF) {
1269
0
    memprintf(err, "'%s' not allowed in 'defaults' section.", args[0]);
1270
0
    goto err;
1271
0
  }
1272
1273
0
  if (!(curpx->cap & PR_CAP_FE)) {
1274
0
    memprintf(err, "'%s' only available in frontend or listen section.", args[0]);
1275
0
    goto err;
1276
0
  }
1277
1278
0
  if (strcmp(args[1], "if") != 0 && strcmp(args[1], "unless") != 0) {
1279
0
    memprintf(err, "'%s' requires either 'if' or 'unless' followed by a condition.", args[0]);
1280
0
    goto err;
1281
0
  }
1282
1283
0
  if (!(cond = build_acl_cond(file, line, &curpx->acl, curpx, (const char **)args + 1, err))) {
1284
0
    memprintf(err, "'%s' : %s.", args[0], *err);
1285
0
    goto err;
1286
0
  }
1287
1288
0
  if (warnif_cond_conflicts(cond, SMP_VAL_FE_REQ_CNT, err)) {
1289
0
    memprintf(err, "'%s' : %s.", args[0], *err);
1290
0
    goto err;
1291
0
  }
1292
1293
0
  rule = calloc(1, sizeof(*rule));
1294
0
  if (!rule) {
1295
0
    memprintf(err, "'%s' : out of memory.", args[0]);
1296
0
    goto err;
1297
0
  }
1298
1299
0
  rule->cond = cond;
1300
0
  rule->type = PERSIST_TYPE_BE_SWITCH;
1301
0
  LIST_INIT(&rule->list);
1302
0
  LIST_APPEND(&curpx->persist_rules, &rule->list);
1303
1304
0
  return 0;
1305
1306
0
 err:
1307
0
  free_acl_cond(cond);
1308
0
  return -1;
1309
0
}
1310
1311
static int proxy_parse_guid(char **args, int section_type, struct proxy *curpx,
1312
                            const struct proxy *defpx, const char *file, int line,
1313
                            char **err)
1314
0
{
1315
0
  const char *guid;
1316
0
  char *guid_err = NULL;
1317
1318
0
  if (curpx->cap & PR_CAP_DEF) {
1319
0
    ha_alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, line, args[0]);
1320
0
    return -1;
1321
0
  }
1322
1323
0
  if (!*args[1]) {
1324
0
    memprintf(err, "'%s' : expects an argument", args[0]);
1325
0
    return -1;
1326
0
  }
1327
1328
0
  guid = args[1];
1329
0
  if (guid_insert(&curpx->obj_type, guid, &guid_err)) {
1330
0
    memprintf(err, "'%s': %s", args[0], guid_err);
1331
0
    ha_free(&guid_err);
1332
0
    return -1;
1333
0
  }
1334
1335
0
  return 0;
1336
0
}
1337
1338
/* This function inserts proxy <px> into the tree of known proxies (regular
1339
 * ones or defaults depending on px->cap & PR_CAP_DEF). The proxy's name is
1340
 * used as the storing key so it must already have been initialized.
1341
 */
1342
void proxy_store_name(struct proxy *px)
1343
0
{
1344
0
  struct ceb_root **root = (px->cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name;
1345
1346
0
  cebis_item_insert(root, conf.name_node, id, px);
1347
0
}
1348
1349
/* Returns a pointer to the first proxy matching capabilities <cap> and id
1350
 * <id>. NULL is returned if no match is found. If <table> is non-zero, it
1351
 * only considers proxies having a table.
1352
 */
1353
struct proxy *proxy_find_by_id(int id, int cap, int table)
1354
0
{
1355
0
  struct proxy *px;
1356
1357
0
  for (px = ceb32_item_lookup(&used_proxy_id, conf.uuid_node, uuid, id, struct proxy);
1358
0
       px ; px = ceb32_item_next_dup(&used_proxy_id, conf.uuid_node, uuid, px)) {
1359
0
    if ((px->cap & cap) != cap)
1360
0
      continue;
1361
1362
0
    if (table && (!px->table || !px->table->size))
1363
0
      continue;
1364
1365
0
    return px;
1366
0
  }
1367
0
  return NULL;
1368
0
}
1369
1370
/* Returns a pointer to the first proxy matching either name <name>, or id
1371
 * <name> if <name> begins with a '#'. NULL is returned if no match is found.
1372
 * If <table> is non-zero, it only considers proxies having a table. The search
1373
 * is made into the regular proxies, unless <cap> has PR_CAP_DEF set in which
1374
 * case it's searched into the defproxy tree.
1375
 */
1376
struct proxy *proxy_find_by_name(const char *name, int cap, int table)
1377
0
{
1378
0
  struct proxy *curproxy;
1379
1380
0
  if (*name == '#' && !(cap & PR_CAP_DEF)) {
1381
0
    curproxy = proxy_find_by_id(atoi(name + 1), cap, table);
1382
0
    if (curproxy)
1383
0
      return curproxy;
1384
0
  }
1385
0
  else {
1386
0
    struct ceb_root **root;
1387
1388
0
    root = (cap & PR_CAP_DEF) ? &defproxy_by_name : &proxy_by_name;
1389
0
    for (curproxy = cebis_item_lookup(root, conf.name_node, id, name, struct proxy);
1390
0
         curproxy; curproxy = cebis_item_next_dup(root, conf.name_node, id, curproxy)) {
1391
0
      if ((curproxy->cap & cap) != cap)
1392
0
        continue;
1393
1394
0
      if (table && (!curproxy->table || !curproxy->table->size))
1395
0
        continue;
1396
1397
0
      return curproxy;
1398
0
    }
1399
0
  }
1400
0
  return NULL;
1401
0
}
1402
1403
/* Finds the best match for a proxy with capabilities <cap>, name <name> and id
1404
 * <id>. At most one of <id> or <name> may be different provided that <cap> is
1405
 * valid. Either <id> or <name> may be left unspecified (0). The purpose is to
1406
 * find a proxy based on some information from a previous configuration, across
1407
 * reloads or during information exchange between peers.
1408
 *
1409
 * Names are looked up first if present, then IDs are compared if present. In
1410
 * case of an inexact match whatever is forced in the configuration has
1411
 * precedence in the following order :
1412
 *   - 1) forced ID (proves a renaming / change of proxy type)
1413
 *   - 2) proxy name+type (may indicate a move if ID differs)
1414
 *   - 3) automatic ID+type (may indicate a renaming)
1415
 *
1416
 * Depending on what is found, we can end up in the following situations :
1417
 *
1418
 *   name id cap  | possible causes
1419
 *   -------------+-----------------
1420
 *    --  --  --  | nothing found
1421
 *    --  --  ok  | nothing found
1422
 *    --  ok  --  | proxy deleted, ID points to next one
1423
 *    --  ok  ok  | proxy renamed, or deleted with ID pointing to next one
1424
 *    ok  --  --  | proxy deleted, but other half with same name still here (before)
1425
 *    ok  --  ok  | proxy's ID changed (proxy moved in the config file)
1426
 *    ok  ok  --  | proxy deleted, but other half with same name still here (after)
1427
 *    ok  ok  ok  | perfect match
1428
 *
1429
 * Upon return if <diff> is not NULL, it is zeroed then filled with up to 3 bits :
1430
 *   - PR_FBM_MISMATCH_ID        : proxy was found but ID differs
1431
 *                                 (and ID was not zero)
1432
 *   - PR_FBM_MISMATCH_NAME      : proxy was found by ID but name differs
1433
 *                                 (and name was not NULL)
1434
 *   - PR_FBM_MISMATCH_PROXYTYPE : a proxy of different type was found with
1435
 *                                 the same name and/or id
1436
 *
1437
 * Only a valid proxy is returned. If capabilities do not match, NULL is
1438
 * returned. The caller can check <diff> to report detailed warnings / errors,
1439
 * and decide whether or not to use what was found.
1440
 */
1441
struct proxy *proxy_find_best_match(int cap, const char *name, int id, int *diff)
1442
0
{
1443
0
  struct proxy *byname;
1444
0
  struct proxy *byid;
1445
1446
0
  if (!name && !id)
1447
0
    return NULL;
1448
1449
0
  if (diff)
1450
0
    *diff = 0;
1451
1452
0
  byname = byid = NULL;
1453
1454
0
  if (name) {
1455
0
    byname = proxy_find_by_name(name, cap, 0);
1456
0
    if (byname && (!id || byname->uuid == id))
1457
0
      return byname;
1458
0
  }
1459
1460
  /* remaining possibilities :
1461
   *   - name not set
1462
   *   - name set but not found
1463
   *   - name found, but ID doesn't match.
1464
   */
1465
0
  if (id) {
1466
0
    byid = proxy_find_by_id(id, cap, 0);
1467
0
    if (byid) {
1468
0
      if (byname) {
1469
        /* id+type found, name+type found, but not all 3.
1470
         * ID wins only if forced, otherwise name wins.
1471
         */
1472
0
        if (byid->options & PR_O_FORCED_ID) {
1473
0
          if (diff)
1474
0
            *diff |= PR_FBM_MISMATCH_NAME;
1475
0
          return byid;
1476
0
        }
1477
0
        else {
1478
0
          if (diff)
1479
0
            *diff |= PR_FBM_MISMATCH_ID;
1480
0
          return byname;
1481
0
        }
1482
0
      }
1483
1484
      /* remaining possibilities :
1485
       *   - name not set
1486
       *   - name set but not found
1487
       */
1488
0
      if (name && diff)
1489
0
        *diff |= PR_FBM_MISMATCH_NAME;
1490
0
      return byid;
1491
0
    }
1492
1493
    /* ID not found */
1494
0
    if (byname) {
1495
0
      if (diff)
1496
0
        *diff |= PR_FBM_MISMATCH_ID;
1497
0
      return byname;
1498
0
    }
1499
0
  }
1500
1501
  /* All remaining possibilities will lead to NULL. If we can report more
1502
   * detailed information to the caller about changed types and/or name,
1503
   * we'll do it. For example, we could detect that "listen foo" was
1504
   * split into "frontend foo_ft" and "backend foo_bk" if IDs are forced.
1505
   *   - name not set, ID not found
1506
   *   - name not found, ID not set
1507
   *   - name not found, ID not found
1508
   */
1509
0
  if (!diff)
1510
0
    return NULL;
1511
1512
0
  if (name) {
1513
0
    byname = proxy_find_by_name(name, 0, 0);
1514
0
    if (byname && (!id || byname->uuid == id))
1515
0
      *diff |= PR_FBM_MISMATCH_PROXYTYPE;
1516
0
  }
1517
1518
0
  if (id) {
1519
0
    byid = proxy_find_by_id(id, 0, 0);
1520
0
    if (byid) {
1521
0
      if (!name)
1522
0
        *diff |= PR_FBM_MISMATCH_PROXYTYPE; /* only type changed */
1523
0
      else if (byid->options & PR_O_FORCED_ID)
1524
0
        *diff |= PR_FBM_MISMATCH_NAME | PR_FBM_MISMATCH_PROXYTYPE; /* name and type changed */
1525
      /* otherwise it's a different proxy that was returned */
1526
0
    }
1527
0
  }
1528
0
  return NULL;
1529
0
}
1530
1531
/* This function checks that the designated proxy has no http directives
1532
 * enabled. It will output a warning if there are, and will fix some of them.
1533
 * It returns the number of fatal errors encountered. This should be called
1534
 * at the end of the configuration parsing if the proxy is not in http mode.
1535
 * The <file> argument is used to construct the error message.
1536
 */
1537
int proxy_cfg_ensure_no_http(struct proxy *curproxy)
1538
0
{
1539
0
  if (curproxy->cookie_name != NULL) {
1540
0
    ha_warning("cookie will be ignored for %s '%s' (needs 'mode http').\n",
1541
0
         proxy_type_str(curproxy), curproxy->id);
1542
0
  }
1543
0
  if (curproxy->lbprm.algo & BE_LB_NEED_HTTP) {
1544
0
    curproxy->lbprm.algo &= ~BE_LB_ALGO;
1545
0
    curproxy->lbprm.algo |= BE_LB_ALGO_RR;
1546
0
    ha_warning("Layer 7 hash not possible for %s '%s' (needs 'mode http'). Falling back to round robin.\n",
1547
0
         proxy_type_str(curproxy), curproxy->id);
1548
0
  }
1549
0
  if (curproxy->logformat.str == default_http_log_format) {
1550
    /* Note: we don't change the directive's file:line number */
1551
0
    curproxy->logformat.str = default_tcp_log_format;
1552
0
    ha_warning("parsing [%s:%d] : 'option httplog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'.\n",
1553
0
         curproxy->logformat.conf.file, curproxy->logformat.conf.line,
1554
0
         proxy_type_str(curproxy), curproxy->id);
1555
0
  }
1556
0
  else if (curproxy->logformat.str == clf_http_log_format) {
1557
    /* Note: we don't change the directive's file:line number */
1558
0
    curproxy->logformat.str = clf_tcp_log_format;
1559
0
    ha_warning("parsing [%s:%d] : 'option httplog clf' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog clf'.\n",
1560
0
         curproxy->logformat.conf.file, curproxy->logformat.conf.line,
1561
0
         proxy_type_str(curproxy), curproxy->id);
1562
0
  }
1563
0
  else if (curproxy->logformat.str == default_https_log_format) {
1564
    /* Note: we don't change the directive's file:line number */
1565
0
    curproxy->logformat.str = default_tcp_log_format;
1566
0
    ha_warning("parsing [%s:%d] : 'option httpslog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'.\n",
1567
0
         curproxy->logformat.conf.file, curproxy->logformat.conf.line,
1568
0
         proxy_type_str(curproxy), curproxy->id);
1569
0
  }
1570
1571
0
  return 0;
1572
0
}
1573
1574
/* This function checks that the designated proxy has no log directives
1575
 * enabled. It will output a warning if there are, and will fix some of them.
1576
 * It returns the number of fatal errors encountered. This should be called
1577
 * at the end of the configuration parsing if the proxy is not in log mode.
1578
 * The <file> argument is used to construct the error message.
1579
 */
1580
int proxy_cfg_ensure_no_log(struct proxy *curproxy)
1581
0
{
1582
0
  if (curproxy->lbprm.algo & BE_LB_NEED_LOG) {
1583
0
    curproxy->lbprm.algo &= ~BE_LB_ALGO;
1584
0
    curproxy->lbprm.algo |= BE_LB_ALGO_RR;
1585
0
    ha_warning("Unusable balance algorithm for %s '%s' (needs 'mode log'). Falling back to round robin.\n",
1586
0
         proxy_type_str(curproxy), curproxy->id);
1587
0
  }
1588
1589
0
  return 0;
1590
0
}
1591
1592
/* Perform the most basic initialization of <p> proxy and define some common
1593
 * default parameters values. Any new proxy or peer should be initialized via
1594
 * this function.
1595
 */
1596
void init_new_proxy(struct proxy *p)
1597
0
{
1598
0
  memset(p, 0, sizeof(struct proxy));
1599
0
  p->obj_type = OBJ_TYPE_PROXY;
1600
0
  LIST_INIT(&p->global_list);
1601
0
  LIST_INIT(&p->servers);
1602
0
  LIST_INIT(&p->el);
1603
0
  LIST_INIT(&p->acl);
1604
0
  LIST_INIT(&p->http_req_rules);
1605
0
  LIST_INIT(&p->http_res_rules);
1606
0
  LIST_INIT(&p->http_after_res_rules);
1607
0
  LIST_INIT(&p->redirect_rules);
1608
0
  LIST_INIT(&p->mon_fail_cond);
1609
0
  LIST_INIT(&p->switching_rules);
1610
0
  LIST_INIT(&p->server_rules);
1611
0
  LIST_INIT(&p->persist_rules);
1612
0
  LIST_INIT(&p->sticking_rules);
1613
0
  LIST_INIT(&p->storersp_rules);
1614
0
  LIST_INIT(&p->tcp_req.inspect_rules);
1615
0
  LIST_INIT(&p->tcp_rep.inspect_rules);
1616
0
  LIST_INIT(&p->tcp_req.l4_rules);
1617
0
  LIST_INIT(&p->tcp_req.l5_rules);
1618
#ifdef USE_QUIC
1619
  LIST_INIT(&p->quic_init_rules);
1620
#endif
1621
0
  MT_LIST_INIT(&p->listener_queue);
1622
0
  LIST_INIT(&p->loggers);
1623
0
  LIST_INIT(&p->conf.bind);
1624
0
  LIST_INIT(&p->conf.listeners);
1625
0
  LIST_INIT(&p->conf.errors);
1626
0
  LIST_INIT(&p->conf.args.list);
1627
0
  LIST_INIT(&p->conf.lf_checks);
1628
0
  LIST_INIT(&p->filter_configs);
1629
0
  LIST_INIT(&p->tcpcheck.preset_vars);
1630
0
  LIST_INIT(&p->filter_sequence.req);
1631
0
  LIST_INIT(&p->filter_sequence.res);
1632
1633
0
  MT_LIST_INIT(&p->lbprm.lb_free_list);
1634
1635
0
  p->conf.used_listener_id = NULL;
1636
0
  p->conf.used_server_id   = NULL;
1637
0
  p->used_server_addr      = NULL;
1638
1639
  /* Timeouts are defined as -1 */
1640
0
  proxy_reset_timeouts(p);
1641
0
  p->tcp_rep.inspect_delay = TICK_ETERNITY;
1642
1643
  /* initial uuid is unassigned (-1) */
1644
0
  p->uuid = -1;
1645
1646
  /* Default to only allow L4 retries */
1647
0
  p->retry_type = PR_RE_CONN_FAILED;
1648
1649
0
  p->stream_new_from_sc = stream_new;
1650
0
  guid_init(&p->guid);
1651
0
  MT_LIST_INIT(&p->watcher_list);
1652
1653
0
  p->extra_counters_fe = NULL;
1654
0
  p->extra_counters_be = NULL;
1655
1656
0
  HA_RWLOCK_INIT(&p->lock);
1657
1658
0
  lf_expr_init(&p->logformat);
1659
0
  lf_expr_init(&p->logformat_sd);
1660
0
  lf_expr_init(&p->format_unique_id);
1661
0
  lf_expr_init(&p->logformat_error);
1662
1663
  /* initialize parameters to common default values */
1664
0
  p->mode = PR_MODE_TCP;
1665
0
  p->options |= PR_O_REUSE_SAFE;
1666
0
  p->max_out_conns = MAX_SRV_LIST;
1667
0
  p->email_alert.level = LOG_ALERT;
1668
0
  p->load_server_state_from_file = PR_SRV_STATE_FILE_UNSPEC;
1669
1670
0
  if (!(p->cap & PR_CAP_INT)) {
1671
0
    p->maxconn = cfg_maxpconn;
1672
0
    p->conn_retries = CONN_RETRIES;
1673
0
  }
1674
0
  else {
1675
0
    p->options2 |= PR_O2_INDEPSTR;
1676
0
    p->timeout.connect = 5000;
1677
0
  }
1678
0
}
1679
1680
/* Initialize per-thread proxy fields */
1681
int proxy_init_per_thr(struct proxy *px)
1682
0
{
1683
0
  int i;
1684
1685
0
  px->per_tgrp = ha_aligned_zalloc_typed(global.nbtgroups, typeof(*px->per_tgrp));
1686
0
  for (i = 0; i < global.nbtgroups; i++)
1687
0
    queue_init(&px->per_tgrp[i].queue, px, NULL);
1688
1689
0
  return 0;
1690
0
}
1691
1692
int proxy_finalize(struct proxy *px, int *err_code)
1693
0
{
1694
0
  struct list tmp_list = LIST_HEAD_INIT(tmp_list);
1695
0
  struct bind_conf *bind_conf;
1696
0
  struct server *newsrv;
1697
0
  struct switching_rule *rule;
1698
0
  struct server_rule *srule;
1699
0
  struct sticking_rule *mrule;
1700
0
  struct logger *tmplogger;
1701
0
  struct lb_ops *ops;
1702
0
  unsigned int next_id;
1703
0
  int cfgerr = 0;
1704
0
  char *err = NULL;
1705
0
  int i;
1706
1707
  /* check and reduce the bind-proc of each listener */
1708
0
  list_for_each_entry(bind_conf, &px->conf.bind, by_fe) {
1709
0
    int mode = conn_pr_mode_to_proto_mode(px->mode);
1710
0
    const struct mux_proto_list *mux_ent;
1711
0
    int ret;
1712
1713
    /* Check the mux protocols, if any; before the check the ALPN */
1714
0
    if (bind_conf->xprt && bind_conf->xprt == xprt_get(XPRT_QUIC)) {
1715
0
      if (!bind_conf->mux_proto) {
1716
        /* No protocol was specified. If we're using QUIC at the transport
1717
         * layer, we'll instantiate it as a mux as well. If QUIC is not
1718
         * compiled in, this will remain NULL.
1719
         */
1720
0
        bind_conf->mux_proto = get_mux_proto(ist("quic"));
1721
0
      }
1722
0
      if (bind_conf->options & BC_O_ACC_PROXY) {
1723
0
        ha_alert("Binding [%s:%d] for %s %s: QUIC protocol does not support PROXY protocol yet."
1724
0
                 " 'accept-proxy' option cannot be used with a QUIC listener.\n",
1725
0
                 bind_conf->file, bind_conf->line,
1726
0
                 proxy_type_str(px), px->id);
1727
0
        cfgerr++;
1728
0
      }
1729
0
    }
1730
1731
0
    if (bind_conf->mux_proto) {
1732
0
      int is_quic;
1733
1734
0
      if ((bind_conf->options & (BC_O_USE_SOCK_DGRAM | BC_O_USE_XPRT_STREAM)) == (BC_O_USE_SOCK_DGRAM | BC_O_USE_XPRT_STREAM))
1735
0
        is_quic = 1;
1736
0
      else
1737
0
        is_quic = 0;
1738
      /* it is possible that an incorrect mux was referenced
1739
       * due to the proxy's mode not being taken into account
1740
       * on first pass. Let's adjust it now.
1741
       */
1742
0
      mux_ent = conn_get_best_mux_entry(bind_conf->mux_proto->mux_proto, IST_NULL, PROTO_SIDE_FE, is_quic, mode);
1743
1744
0
      if (!mux_ent || !isteq(mux_ent->mux_proto, bind_conf->mux_proto->mux_proto)) {
1745
0
        ha_alert("%s '%s' : MUX protocol '%.*s' is not usable for 'bind %s' at [%s:%d].\n",
1746
0
                 proxy_type_str(px), px->id,
1747
0
                 (int)bind_conf->mux_proto->mux_proto.len,
1748
0
                 bind_conf->mux_proto->mux_proto.ptr,
1749
0
                 bind_conf->arg, bind_conf->file, bind_conf->line);
1750
0
        cfgerr++;
1751
0
      }
1752
0
      else {
1753
0
        if ((mux_ent->mux->flags & MX_FL_FRAMED) && !(bind_conf->options & BC_O_USE_SOCK_DGRAM)) {
1754
0
          ha_alert("%s '%s' : frame-based MUX protocol '%.*s' is incompatible with stream transport of 'bind %s' at [%s:%d].\n",
1755
0
                   proxy_type_str(px), px->id,
1756
0
                   (int)bind_conf->mux_proto->mux_proto.len,
1757
0
                   bind_conf->mux_proto->mux_proto.ptr,
1758
0
                   bind_conf->arg, bind_conf->file, bind_conf->line);
1759
0
          cfgerr++;
1760
0
        }
1761
0
        else if (!(mux_ent->mux->flags & MX_FL_FRAMED) && !(bind_conf->options & BC_O_USE_SOCK_STREAM)) {
1762
0
          ha_alert("%s '%s' : stream-based MUX protocol '%.*s' is incompatible with framed transport of 'bind %s' at [%s:%d].\n",
1763
0
                   proxy_type_str(px), px->id,
1764
0
                   (int)bind_conf->mux_proto->mux_proto.len,
1765
0
                   bind_conf->mux_proto->mux_proto.ptr,
1766
0
                   bind_conf->arg, bind_conf->file, bind_conf->line);
1767
0
          cfgerr++;
1768
0
        }
1769
0
      }
1770
1771
      /* update the mux */
1772
0
      bind_conf->mux_proto = mux_ent;
1773
0
    }
1774
1775
1776
    /* HTTP frontends with "h2" as ALPN/NPN will work in
1777
     * HTTP/2 and absolutely require buffers 16kB or larger.
1778
     */
1779
#ifdef USE_OPENSSL
1780
    /* no-alpn ? If so, it's the right moment to remove it */
1781
    if (bind_conf->ssl_conf.alpn_str && !bind_conf->ssl_conf.alpn_len) {
1782
      ha_free(&bind_conf->ssl_conf.alpn_str);
1783
    }
1784
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1785
    else if (!bind_conf->ssl_conf.alpn_str && !bind_conf->ssl_conf.npn_str &&
1786
       ((bind_conf->options & BC_O_USE_SSL) || bind_conf->xprt == xprt_get(XPRT_QUIC)) &&
1787
       px->mode == PR_MODE_HTTP && global.tune.bufsize >= 16384) {
1788
1789
      /* Neither ALPN nor NPN were explicitly set nor disabled, we're
1790
       * in HTTP mode with an SSL or QUIC listener, we can enable ALPN.
1791
       * Note that it's in binary form. First we try to set the ALPN from
1792
       * mux proto if set. Otherwise rely on the default ALPN.
1793
       */
1794
      if (bind_conf->mux_proto && bind_conf->mux_proto->alpn)
1795
        bind_conf->ssl_conf.alpn_str = strdup(bind_conf->mux_proto->alpn);
1796
      else if (bind_conf->xprt == xprt_get(XPRT_QUIC))
1797
        bind_conf->ssl_conf.alpn_str = strdup("\002h3");
1798
      else
1799
        bind_conf->ssl_conf.alpn_str = strdup("\002h2\010http/1.1");
1800
1801
      if (!bind_conf->ssl_conf.alpn_str) {
1802
        ha_alert("Proxy '%s': out of memory while trying to allocate a default alpn string in 'bind %s' at [%s:%d].\n",
1803
                 px->id, bind_conf->arg, bind_conf->file, bind_conf->line);
1804
        cfgerr++;
1805
        *err_code |= ERR_FATAL | ERR_ALERT;
1806
        goto out;
1807
      }
1808
      bind_conf->ssl_conf.alpn_len = strlen(bind_conf->ssl_conf.alpn_str);
1809
    }
1810
#endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */
1811
1812
1813
    if (px->mode == PR_MODE_HTTP && global.tune.bufsize < 16384) {
1814
#ifdef OPENSSL_NPN_NEGOTIATED
1815
      /* check NPN */
1816
      if (bind_conf->ssl_conf.npn_str && strstr(bind_conf->ssl_conf.npn_str, "\002h2")) {
1817
        ha_alert("HTTP frontend '%s' enables HTTP/2 via NPN at [%s:%d], so global.tune.bufsize must be at least 16384 bytes (%d now).\n",
1818
                 px->id, bind_conf->file, bind_conf->line, global.tune.bufsize);
1819
        cfgerr++;
1820
      }
1821
#endif /* OPENSSL_NPN_NEGOTIATED */
1822
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1823
      /* check ALPN */
1824
      if (bind_conf->ssl_conf.alpn_str && strstr(bind_conf->ssl_conf.alpn_str, "\002h2")) {
1825
        ha_alert("HTTP frontend '%s' enables HTTP/2 via ALPN at [%s:%d], so global.tune.bufsize must be at least 16384 bytes (%d now).\n",
1826
                 px->id, bind_conf->file, bind_conf->line, global.tune.bufsize);
1827
        cfgerr++;
1828
      }
1829
#endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */
1830
    } /* HTTP && bufsize < 16384 */
1831
1832
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
1833
    if (px->mode == PR_MODE_HTTP && !bind_conf->mux_proto &&
1834
        bind_conf->ssl_conf.alpn_str &&
1835
        strstr(bind_conf->ssl_conf.alpn_str, "\002h3")) {
1836
      if (!experimental_directives_allowed) {
1837
        ha_alert("HTTP/3 on TCP listed via ALPN on frontend '%s' at [%s:%d] relies on the experimental QMux protocol, "
1838
                 "must be allowed via a global 'expose-experimental-directives'.\n",
1839
                 px->id, bind_conf->file, bind_conf->line);
1840
        cfgerr++;
1841
      }
1842
1843
      mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
1844
    }
1845
#endif /* TLSEXT_TYPE_application_layer_protocol_negotiation */
1846
1847
#endif /* USE_OPENSSL */
1848
1849
#ifdef USE_QUIC
1850
    if (bind_conf->xprt == xprt_get(XPRT_QUIC)) {
1851
      const struct quic_cc_algo *cc_algo = bind_conf->quic_cc_algo ?
1852
        bind_conf->quic_cc_algo : default_quic_cc_algo;
1853
1854
      if (!(cc_algo->flags & QUIC_CC_ALGO_FL_OPT_PACING) &&
1855
          !(quic_tune.fe.fb_opts & QUIC_TUNE_FB_TX_PACING)) {
1856
        ha_warning("Binding [%s:%d] for %s %s: using the selected congestion algorithm without pacing may cause slowdowns or high loss rates during transfers.\n",
1857
                   bind_conf->file, bind_conf->line,
1858
                   proxy_type_str(px), px->id);
1859
        *err_code |= ERR_WARN;
1860
      }
1861
1862
      if (bind_conf->ssl_conf.early_data && conn_calc_max_streams(1)) {
1863
        ha_notice("Binding [%s:%d] for %s %s: "
1864
                  "stream elasticity is ignored for initial connection settings as this is incompatible with 0-RTT.",
1865
                   bind_conf->file, bind_conf->line,
1866
                   proxy_type_str(px), px->id);
1867
      }
1868
    }
1869
#endif /* USE_QUIC */
1870
1871
    /* finish the bind setup */
1872
0
    ret = bind_complete_thread_setup(bind_conf, err_code);
1873
0
    if (ret != 0) {
1874
0
      cfgerr += ret;
1875
0
      if (*err_code & ERR_FATAL)
1876
0
        goto out;
1877
0
    }
1878
1879
0
    if (bind_generate_guid(bind_conf)) {
1880
0
      cfgerr++;
1881
0
      *err_code |= ERR_FATAL | ERR_ALERT;
1882
0
      goto out;
1883
0
    }
1884
0
  }
1885
1886
0
  switch (px->mode) {
1887
0
  case PR_MODE_TCP:
1888
0
    cfgerr += proxy_cfg_ensure_no_http(px);
1889
0
    cfgerr += proxy_cfg_ensure_no_log(px);
1890
0
    break;
1891
1892
0
  case PR_MODE_HTTP:
1893
0
    cfgerr += proxy_cfg_ensure_no_log(px);
1894
0
    px->http_needed = 1;
1895
0
    break;
1896
1897
0
  case PR_MODE_CLI:
1898
0
    cfgerr += proxy_cfg_ensure_no_http(px);
1899
0
    cfgerr += proxy_cfg_ensure_no_log(px);
1900
0
    break;
1901
1902
0
  case PR_MODE_SYSLOG:
1903
    /* this mode is initialized as the classic tcp proxy */
1904
0
    cfgerr += proxy_cfg_ensure_no_http(px);
1905
0
    break;
1906
1907
0
  case PR_MODE_SPOP:
1908
0
    cfgerr += proxy_cfg_ensure_no_http(px);
1909
0
    cfgerr += proxy_cfg_ensure_no_log(px);
1910
0
    break;
1911
1912
0
  case PR_MODE_PEERS:
1913
0
  case PR_MODES:
1914
    /* should not happen, bug gcc warn missing switch statement */
1915
0
    ha_alert("%s '%s' cannot initialize this proxy mode (peers) in this way. NOTE: PLEASE REPORT THIS TO DEVELOPERS AS YOU'RE NOT SUPPOSED TO BE ABLE TO CREATE A CONFIGURATION TRIGGERING THIS!\n",
1916
0
             proxy_type_str(px), px->id);
1917
0
    cfgerr++;
1918
0
    break;
1919
0
  }
1920
1921
0
  if (!(px->cap & PR_CAP_INT) && (px->cap & PR_CAP_FE) && LIST_ISEMPTY(&px->conf.listeners)) {
1922
0
    ha_warning("%s '%s' has no 'bind' directive. Please declare it as a backend if this was intended.\n",
1923
0
               proxy_type_str(px), px->id);
1924
0
    *err_code |= ERR_WARN;
1925
0
  }
1926
1927
0
  if (px->cap & PR_CAP_BE) {
1928
0
    if (!(px->lbprm.algo & BE_LB_KIND)) {
1929
      /* If no LB algo is set in a backend, we
1930
       * want to use balance random by default.
1931
       */
1932
0
      px->lbprm.algo &= ~BE_LB_ALGO;
1933
0
      px->lbprm.algo |= BE_LB_ALGO_RND;
1934
0
    }
1935
0
  }
1936
1937
0
  if ((px->tcpcheck.flags & TCPCHK_FL_UNUSED_HTTP_RS)) {
1938
0
    ha_warning("%s '%s' uses http-check rules without 'option httpchk', so the rules are ignored.\n",
1939
0
               proxy_type_str(px), px->id);
1940
0
    *err_code |= ERR_WARN;
1941
0
  }
1942
1943
0
  if ((px->options2 & PR_O2_CHK_ANY) == PR_O2_EXT_CHK) {
1944
0
    if (!global.external_check) {
1945
0
      ha_alert("Proxy '%s' : '%s' unable to find required 'global.external-check'.\n",
1946
0
               px->id, "option external-check");
1947
0
      cfgerr++;
1948
0
    }
1949
0
    if (!px->check_command) {
1950
0
      ha_alert("Proxy '%s' : '%s' unable to find required 'external-check command'.\n",
1951
0
               px->id, "option external-check");
1952
0
      cfgerr++;
1953
0
    }
1954
0
    if (!(global.tune.options & GTUNE_INSECURE_FORK)) {
1955
0
      ha_warning("Proxy '%s' : 'insecure-fork-wanted' not enabled in the global section, '%s' will likely fail.\n",
1956
0
                 px->id, "option external-check");
1957
0
      *err_code |= ERR_WARN;
1958
0
    }
1959
0
  }
1960
1961
0
  if (px->email_alert.flags & PR_EMAIL_ALERT_SET) {
1962
0
    if (!(px->email_alert.mailers.name && px->email_alert.from && px->email_alert.to)) {
1963
0
      ha_warning("'email-alert' will be ignored for %s '%s' (the presence any of "
1964
0
                 "'email-alert from', 'email-alert level' 'email-alert mailers', "
1965
0
                 "'email-alert myhostname', or 'email-alert to' "
1966
0
                 "requires each of 'email-alert from', 'email-alert mailers' and 'email-alert to' "
1967
0
                 "to be present).\n",
1968
0
                 proxy_type_str(px), px->id);
1969
0
      *err_code |= ERR_WARN;
1970
0
      free_email_alert(px);
1971
0
    }
1972
0
    if (!px->email_alert.myhostname)
1973
0
      px->email_alert.myhostname = strdup(hostname);
1974
0
  }
1975
1976
0
  if (px->check_command) {
1977
0
    int clear = 0;
1978
0
    if ((px->options2 & PR_O2_CHK_ANY) != PR_O2_EXT_CHK) {
1979
0
      ha_warning("'%s' will be ignored for %s '%s' (requires 'option external-check').\n",
1980
0
                 "external-check command", proxy_type_str(px), px->id);
1981
0
      *err_code |= ERR_WARN;
1982
0
      clear = 1;
1983
0
    }
1984
0
    if (px->check_command[0] != '/' && !px->check_path) {
1985
0
      ha_alert("Proxy '%s': '%s' does not have a leading '/' and 'external-check path' is not set.\n",
1986
0
               px->id, "external-check command");
1987
0
      cfgerr++;
1988
0
    }
1989
0
    if (clear) {
1990
0
      ha_free(&px->check_command);
1991
0
    }
1992
0
  }
1993
1994
0
  if (px->check_path) {
1995
0
    if ((px->options2 & PR_O2_CHK_ANY) != PR_O2_EXT_CHK) {
1996
0
      ha_warning("'%s' will be ignored for %s '%s' (requires 'option external-check').\n",
1997
0
                 "external-check path", proxy_type_str(px), px->id);
1998
0
      *err_code |= ERR_WARN;
1999
0
      ha_free(&px->check_path);
2000
0
    }
2001
0
  }
2002
2003
  /* if a default backend was specified, let's find it */
2004
0
  if (px->defbe.name) {
2005
0
    struct proxy *target;
2006
2007
0
    target = proxy_be_by_name(px->defbe.name);
2008
0
    if (!target) {
2009
0
      ha_alert("Proxy '%s': unable to find required default_backend: '%s'.\n",
2010
0
               px->id, px->defbe.name);
2011
0
      cfgerr++;
2012
0
    } else if (target == px) {
2013
0
      ha_alert("Proxy '%s': loop detected for default_backend: '%s'.\n",
2014
0
               px->id, px->defbe.name);
2015
0
      cfgerr++;
2016
0
    } else if (target->mode != px->mode &&
2017
0
         !(px->mode == PR_MODE_TCP && target->mode == PR_MODE_HTTP)) {
2018
2019
0
      ha_alert("%s %s '%s' (%s:%d) tries to use incompatible %s %s '%s' (%s:%d) as its default backend (see 'mode').\n",
2020
0
               proxy_mode_str(px->mode), proxy_type_str(px), px->id,
2021
0
               px->conf.file, px->conf.line,
2022
0
               proxy_mode_str(target->mode), proxy_type_str(target), target->id,
2023
0
               target->conf.file, target->conf.line);
2024
0
      cfgerr++;
2025
0
    } else {
2026
0
      free(px->defbe.name);
2027
0
      px->defbe.be = target;
2028
      /* Emit a warning if this proxy also has some servers */
2029
0
      if (!LIST_ISEMPTY(&px->servers)) {
2030
0
        ha_warning("In proxy '%s', the 'default_backend' rule always has precedence over the servers, which will never be used.\n",
2031
0
                   px->id);
2032
0
        *err_code |= ERR_WARN;
2033
0
      }
2034
0
      if (target->mode == PR_MODE_HTTP) {
2035
        /* at least one of the used backends will provoke an
2036
         * HTTP upgrade
2037
         */
2038
0
        px->options |= PR_O_HTTP_UPG;
2039
0
      }
2040
2041
0
      target->flags |= PR_FL_NON_PURGEABLE;
2042
0
    }
2043
0
  }
2044
2045
  /* find the target proxy for 'use_backend' rules */
2046
0
  list_for_each_entry(rule, &px->switching_rules, list) {
2047
0
    struct proxy *target;
2048
0
    struct logformat_node *node;
2049
0
    char *pxname;
2050
2051
    /* Try to parse the string as a log format expression. If the result
2052
     * of the parsing is only one entry containing a simple string, then
2053
     * it's a standard string corresponding to a static rule, thus the
2054
     * parsing is cancelled and be.name is restored to be resolved.
2055
     */
2056
0
    pxname = rule->be.name;
2057
0
    lf_expr_init(&rule->be.expr);
2058
0
    px->conf.args.ctx = ARGC_UBK;
2059
0
    px->conf.args.file = rule->file;
2060
0
    px->conf.args.line = rule->line;
2061
0
    err = NULL;
2062
0
    if (!parse_logformat_string(pxname, px, &rule->be.expr, 0, SMP_VAL_FE_HRQ_HDR, &err)) {
2063
0
      ha_alert("Parsing [%s:%d]: failed to parse use_backend rule '%s' : %s.\n",
2064
0
               rule->file, rule->line, pxname, err);
2065
0
      free(err);
2066
0
      cfgerr++;
2067
0
      continue;
2068
0
    }
2069
0
    node = LIST_NEXT(&rule->be.expr.nodes.list, struct logformat_node *, list);
2070
2071
0
    if (!lf_expr_isempty(&rule->be.expr)) {
2072
0
      if (node->type != LOG_FMT_TEXT || node->list.n != &rule->be.expr.nodes.list) {
2073
0
        rule->dynamic = 1;
2074
0
        free(pxname);
2075
        /* backend is not yet known so we cannot assume its type,
2076
         * thus we should consider that at least one of the used
2077
         * backends may provoke HTTP upgrade
2078
         */
2079
0
        px->options |= PR_O_HTTP_UPG;
2080
0
        continue;
2081
0
      }
2082
      /* Only one element in the list, a simple string: free the expression and
2083
       * fall back to static rule
2084
       */
2085
0
      lf_expr_deinit(&rule->be.expr);
2086
0
    }
2087
2088
0
    rule->dynamic = 0;
2089
0
    rule->be.name = pxname;
2090
2091
0
    target = proxy_be_by_name(rule->be.name);
2092
0
    if (!target) {
2093
0
      ha_alert("Proxy '%s': unable to find required use_backend: '%s'.\n",
2094
0
               px->id, rule->be.name);
2095
0
      cfgerr++;
2096
0
    } else if (target == px) {
2097
0
      ha_alert("Proxy '%s': loop detected for use_backend: '%s'.\n",
2098
0
               px->id, rule->be.name);
2099
0
      cfgerr++;
2100
0
    } else if (target->mode != px->mode &&
2101
0
         !(px->mode == PR_MODE_TCP && target->mode == PR_MODE_HTTP)) {
2102
2103
0
      ha_alert("%s %s '%s' (%s:%d) tries to use incompatible %s %s '%s' (%s:%d) in a 'use_backend' rule (see 'mode').\n",
2104
0
               proxy_mode_str(px->mode), proxy_type_str(px), px->id,
2105
0
               px->conf.file, px->conf.line,
2106
0
               proxy_mode_str(target->mode), proxy_type_str(target), target->id,
2107
0
               target->conf.file, target->conf.line);
2108
0
      cfgerr++;
2109
0
    } else {
2110
0
      ha_free(&rule->be.name);
2111
0
      rule->be.backend = target;
2112
0
      if (target->mode == PR_MODE_HTTP) {
2113
        /* at least one of the used backends will provoke an
2114
         * HTTP upgrade
2115
         */
2116
0
        px->options |= PR_O_HTTP_UPG;
2117
0
      }
2118
2119
0
      target->flags |= PR_FL_NON_PURGEABLE;
2120
0
    }
2121
0
    *err_code |= warnif_tcp_http_cond(px, rule->cond);
2122
0
  }
2123
2124
  /* find the target server for 'use_server' rules */
2125
0
  list_for_each_entry(srule, &px->server_rules, list) {
2126
0
    struct server *target;
2127
0
    struct logformat_node *node;
2128
0
    char *server_name;
2129
2130
    /* We try to parse the string as a log format expression. If the result of the parsing
2131
     * is only one entry containing a single string, then it's a standard string corresponding
2132
     * to a static rule, thus the parsing is cancelled and we fall back to setting srv.ptr.
2133
     */
2134
0
    server_name = srule->srv.name;
2135
0
    lf_expr_init(&srule->expr);
2136
0
    px->conf.args.ctx = ARGC_USRV;
2137
0
    err = NULL;
2138
0
    if (!parse_logformat_string(server_name, px, &srule->expr, 0, SMP_VAL_FE_HRQ_HDR, &err)) {
2139
0
      ha_alert("Parsing [%s:%d]; use-server rule failed to parse log-format '%s' : %s.\n",
2140
0
               srule->file, srule->line, server_name, err);
2141
0
      free(err);
2142
0
      cfgerr++;
2143
0
      continue;
2144
0
    }
2145
0
    node = LIST_NEXT(&srule->expr.nodes.list, struct logformat_node *, list);
2146
2147
0
    if (!lf_expr_isempty(&srule->expr)) {
2148
0
      if (node->type != LOG_FMT_TEXT || node->list.n != &srule->expr.nodes.list) {
2149
0
        srule->dynamic = 1;
2150
0
        free(server_name);
2151
0
        continue;
2152
0
      }
2153
      /* Only one element in the list, a simple string: free the expression and
2154
       * fall back to static rule
2155
       */
2156
0
      lf_expr_deinit(&srule->expr);
2157
0
    }
2158
2159
0
    srule->dynamic = 0;
2160
0
    srule->srv.name = server_name;
2161
0
    target = server_find_by_name(px, srule->srv.name);
2162
0
    *err_code |= warnif_tcp_http_cond(px, srule->cond);
2163
2164
0
    if (!target) {
2165
0
      ha_alert("%s '%s' : unable to find server '%s' referenced in a 'use-server' rule.\n",
2166
0
               proxy_type_str(px), px->id, srule->srv.name);
2167
0
      cfgerr++;
2168
0
      continue;
2169
0
    }
2170
0
    ha_free(&srule->srv.name);
2171
0
    srule->srv.ptr = target;
2172
0
    target->flags |= SRV_F_NAME_REFD;
2173
0
  }
2174
2175
  /* find the target table for 'stick' rules */
2176
0
  list_for_each_entry(mrule, &px->sticking_rules, list) {
2177
0
    px->be_req_ana |= AN_REQ_STICKING_RULES;
2178
0
    if (mrule->flags & STK_IS_STORE)
2179
0
      px->be_rsp_ana |= AN_RES_STORE_RULES;
2180
2181
0
    if (!resolve_stick_rule(px, mrule))
2182
0
      cfgerr++;
2183
2184
0
    *err_code |= warnif_tcp_http_cond(px, mrule->cond);
2185
0
  }
2186
2187
  /* find the target table for 'store response' rules */
2188
0
  list_for_each_entry(mrule, &px->storersp_rules, list) {
2189
0
    px->be_rsp_ana |= AN_RES_STORE_RULES;
2190
2191
0
    if (!resolve_stick_rule(px, mrule))
2192
0
      cfgerr++;
2193
0
  }
2194
2195
  /* check validity for 'tcp-request' layer 4/5/6/7 rules */
2196
0
  cfgerr += check_action_rules(&px->tcp_req.l4_rules, px, err_code);
2197
0
  cfgerr += check_action_rules(&px->tcp_req.l5_rules, px, err_code);
2198
0
  cfgerr += check_action_rules(&px->tcp_req.inspect_rules, px, err_code);
2199
0
  cfgerr += check_action_rules(&px->tcp_rep.inspect_rules, px, err_code);
2200
0
  cfgerr += check_action_rules(&px->http_req_rules, px, err_code);
2201
0
  cfgerr += check_action_rules(&px->http_res_rules, px, err_code);
2202
0
  cfgerr += check_action_rules(&px->http_after_res_rules, px, err_code);
2203
#ifdef USE_QUIC
2204
  cfgerr += check_action_rules(&px->quic_init_rules, px, err_code);
2205
#endif
2206
2207
  /* Warn is a switch-mode http is used on a TCP listener with servers but no backend */
2208
0
  if (!px->defbe.name && LIST_ISEMPTY(&px->switching_rules) && !LIST_ISEMPTY(&px->servers)) {
2209
0
    if ((px->options & PR_O_HTTP_UPG) && px->mode == PR_MODE_TCP)
2210
0
      ha_warning("Proxy '%s' : 'switch-mode http' configured for a %s %s with no backend. "
2211
0
                 "Incoming connections upgraded to HTTP cannot be routed to TCP servers\n",
2212
0
                 px->id, proxy_mode_str(px->mode), proxy_type_str(px));
2213
0
  }
2214
2215
0
  if (px->table && px->table->peers.name) {
2216
0
    struct peers *curpeers;
2217
2218
0
    for (curpeers = cfg_peers; curpeers; curpeers = curpeers->next) {
2219
0
      if (strcmp(curpeers->id, px->table->peers.name) == 0) {
2220
0
        ha_free(&px->table->peers.name);
2221
0
        px->table->peers.p = curpeers;
2222
0
        break;
2223
0
      }
2224
0
    }
2225
2226
0
    if (!curpeers) {
2227
0
      ha_alert("Proxy '%s': unable to find sync peers '%s'.\n",
2228
0
               px->id, px->table->peers.name);
2229
0
      ha_free(&px->table->peers.name);
2230
0
      px->table->peers.p = NULL;
2231
0
      cfgerr++;
2232
0
    }
2233
0
    else if (curpeers->disabled) {
2234
      /* silently disable this peers section */
2235
0
      px->table->peers.p = NULL;
2236
0
    }
2237
0
    else if (!curpeers->peers_fe) {
2238
0
      ha_alert("Proxy '%s': unable to find local peer '%s' in peers section '%s'.\n",
2239
0
               px->id, localpeer, curpeers->id);
2240
0
      px->table->peers.p = NULL;
2241
0
      cfgerr++;
2242
0
    }
2243
0
  }
2244
2245
2246
0
  if (px->email_alert.mailers.name) {
2247
0
    struct mailers *curmailers = mailers;
2248
2249
0
    for (curmailers = mailers; curmailers; curmailers = curmailers->next) {
2250
0
      if (strcmp(curmailers->id, px->email_alert.mailers.name) == 0)
2251
0
        break;
2252
0
    }
2253
0
    if (!curmailers) {
2254
0
      ha_alert("Proxy '%s': unable to find mailers '%s'.\n",
2255
0
               px->id, px->email_alert.mailers.name);
2256
0
      free_email_alert(px);
2257
0
      cfgerr++;
2258
0
    }
2259
0
    else {
2260
0
      err = NULL;
2261
0
      if (init_email_alert(curmailers, px, &err)) {
2262
0
        ha_alert("Proxy '%s': %s.\n", px->id, err);
2263
0
        free(err);
2264
0
        cfgerr++;
2265
0
      }
2266
0
    }
2267
0
  }
2268
2269
0
  if (px->uri_auth && !(px->uri_auth->flags & STAT_F_CONVDONE) &&
2270
0
      !LIST_ISEMPTY(&px->uri_auth->http_req_rules) &&
2271
0
      (px->uri_auth->userlist || px->uri_auth->auth_realm )) {
2272
0
    ha_alert("%s '%s': stats 'auth'/'realm' and 'http-request' can't be used at the same time.\n",
2273
0
             "proxy", px->id);
2274
0
    cfgerr++;
2275
0
    goto out_uri_auth_compat;
2276
0
  }
2277
2278
0
  if (px->uri_auth && px->uri_auth->userlist &&
2279
0
      (!(px->uri_auth->flags & STAT_F_CONVDONE) ||
2280
0
       LIST_ISEMPTY(&px->uri_auth->http_req_rules))) {
2281
0
    const char *uri_auth_compat_req[10];
2282
0
    struct act_rule *rule;
2283
0
    i = 0;
2284
2285
    /* build the ACL condition from scratch. We're relying on anonymous ACLs for that */
2286
0
    uri_auth_compat_req[i++] = "auth";
2287
2288
0
    if (px->uri_auth->auth_realm) {
2289
0
      uri_auth_compat_req[i++] = "realm";
2290
0
      uri_auth_compat_req[i++] = px->uri_auth->auth_realm;
2291
0
    }
2292
2293
0
    uri_auth_compat_req[i++] = "unless";
2294
0
    uri_auth_compat_req[i++] = "{";
2295
0
    uri_auth_compat_req[i++] = "http_auth(.internal-stats-userlist)";
2296
0
    uri_auth_compat_req[i++] = "}";
2297
0
    uri_auth_compat_req[i++] = "";
2298
2299
0
    rule = parse_http_req_cond(uri_auth_compat_req, "internal-stats-auth-compat", 0, px);
2300
0
    if (!rule) {
2301
0
      cfgerr++;
2302
0
      goto out;
2303
0
    }
2304
2305
0
    LIST_APPEND(&px->uri_auth->http_req_rules, &rule->list);
2306
2307
0
    if (px->uri_auth->auth_realm) {
2308
0
      ha_free(&px->uri_auth->auth_realm);
2309
0
    }
2310
0
    px->uri_auth->flags |= STAT_F_CONVDONE;
2311
0
  }
2312
0
 out_uri_auth_compat:
2313
2314
  /* check whether we have a logger that uses RFC5424 log format */
2315
0
  list_for_each_entry(tmplogger, &px->loggers, list) {
2316
0
    if (tmplogger->format == LOG_FORMAT_RFC5424) {
2317
0
      if (!px->logformat_sd.str) {
2318
        /* set the default logformat_sd_string */
2319
0
        px->logformat_sd.str = default_rfc5424_sd_log_format;
2320
0
      }
2321
0
      break;
2322
0
    }
2323
0
  }
2324
2325
  /* compile the log format */
2326
0
  if (!(px->cap & PR_CAP_FE)) {
2327
0
    lf_expr_deinit(&px->logformat);
2328
0
    lf_expr_deinit(&px->logformat_sd);
2329
0
  }
2330
2331
0
  if (px->logformat.str) {
2332
0
    px->conf.args.ctx = ARGC_LOG;
2333
0
    px->conf.args.file = px->logformat.conf.file;
2334
0
    px->conf.args.line = px->logformat.conf.line;
2335
0
    err = NULL;
2336
0
    if (!lf_expr_compile(&px->logformat, &px->conf.args,
2337
0
                                LOG_OPT_MANDATORY|LOG_OPT_MERGE_SPACES,
2338
0
                                SMP_VAL_FE_LOG_END, &err) ||
2339
0
        !lf_expr_postcheck(&px->logformat, px, &err)) {
2340
0
      ha_alert("Parsing [%s:%d]: failed to parse log-format : %s.\n",
2341
0
               px->logformat.conf.file, px->logformat.conf.line, err);
2342
0
      free(err);
2343
0
      cfgerr++;
2344
0
    }
2345
0
    px->conf.args.file = NULL;
2346
0
    px->conf.args.line = 0;
2347
0
  }
2348
2349
0
  if (px->logformat_sd.str) {
2350
0
    px->conf.args.ctx = ARGC_LOGSD;
2351
0
    px->conf.args.file = px->logformat_sd.conf.file;
2352
0
    px->conf.args.line = px->logformat_sd.conf.line;
2353
0
    err = NULL;
2354
0
    if (!lf_expr_compile(&px->logformat_sd, &px->conf.args,
2355
0
                                LOG_OPT_MANDATORY|LOG_OPT_MERGE_SPACES,
2356
0
                                SMP_VAL_FE_LOG_END, &err) ||
2357
0
        !add_to_logformat_list(NULL, NULL, LF_SEPARATOR, &px->logformat_sd, &err) ||
2358
0
        !lf_expr_postcheck(&px->logformat_sd, px, &err)) {
2359
0
      ha_alert("Parsing [%s:%d]: failed to parse log-format-sd : %s.\n",
2360
0
               px->logformat_sd.conf.file, px->logformat_sd.conf.line, err);
2361
0
      free(err);
2362
0
      cfgerr++;
2363
0
    }
2364
0
    px->conf.args.file = NULL;
2365
0
    px->conf.args.line = 0;
2366
0
  }
2367
2368
0
  if (px->format_unique_id.str) {
2369
0
    int where = 0;
2370
2371
0
    px->conf.args.ctx = ARGC_UIF;
2372
0
    px->conf.args.file = px->format_unique_id.conf.file;
2373
0
    px->conf.args.line = px->format_unique_id.conf.line;
2374
0
    err = NULL;
2375
0
    if (px->cap & PR_CAP_FE)
2376
0
      where |= SMP_VAL_FE_HRQ_HDR;
2377
0
    if (px->cap & PR_CAP_BE)
2378
0
      where |= SMP_VAL_BE_HRQ_HDR;
2379
0
    if (!lf_expr_compile(&px->format_unique_id, &px->conf.args,
2380
0
                                LOG_OPT_HTTP|LOG_OPT_MERGE_SPACES, where, &err) ||
2381
0
        !lf_expr_postcheck(&px->format_unique_id, px, &err)) {
2382
0
      ha_alert("Parsing [%s:%d]: failed to parse unique-id : %s.\n",
2383
0
               px->format_unique_id.conf.file, px->format_unique_id.conf.line, err);
2384
0
      free(err);
2385
0
      cfgerr++;
2386
0
    }
2387
0
    px->conf.args.file = NULL;
2388
0
    px->conf.args.line = 0;
2389
0
  }
2390
2391
0
  if (px->logformat_error.str) {
2392
0
    px->conf.args.ctx = ARGC_LOG;
2393
0
    px->conf.args.file = px->logformat_error.conf.file;
2394
0
    px->conf.args.line = px->logformat_error.conf.line;
2395
0
    err = NULL;
2396
0
    if (!lf_expr_compile(&px->logformat_error, &px->conf.args,
2397
0
                                LOG_OPT_MANDATORY|LOG_OPT_MERGE_SPACES,
2398
0
                                SMP_VAL_FE_LOG_END, &err) ||
2399
0
        !lf_expr_postcheck(&px->logformat_error, px, &err)) {
2400
0
      ha_alert("Parsing [%s:%d]: failed to parse error-log-format : %s.\n",
2401
0
               px->logformat_error.conf.file, px->logformat_error.conf.line, err);
2402
0
      free(err);
2403
0
      cfgerr++;
2404
0
    }
2405
0
    px->conf.args.file = NULL;
2406
0
    px->conf.args.line = 0;
2407
0
  }
2408
2409
  /* "balance hash" needs to compile its expression
2410
   * (log backends will handle this in proxy log postcheck)
2411
   */
2412
0
  if (px->mode != PR_MODE_SYSLOG &&
2413
0
      (px->lbprm.algo & BE_LB_ALGO) == BE_LB_ALGO_SMP) {
2414
0
    int idx = 0;
2415
0
    const char *args[] = {
2416
0
      px->lbprm.arg_str,
2417
0
      NULL,
2418
0
    };
2419
2420
0
    err = NULL;
2421
0
    px->conf.args.ctx = ARGC_USRV; // same context as use_server.
2422
0
    px->lbprm.expr =
2423
0
      sample_parse_expr((char **)args, &idx,
2424
0
            px->conf.file, px->conf.line,
2425
0
            &err, &px->conf.args, NULL);
2426
2427
0
    if (!px->lbprm.expr) {
2428
0
      ha_alert("%s '%s' [%s:%d]: failed to parse 'balance hash' expression '%s' in : %s.\n",
2429
0
               proxy_type_str(px), px->id,
2430
0
               px->conf.file, px->conf.line,
2431
0
               px->lbprm.arg_str, err);
2432
0
      ha_free(&err);
2433
0
      cfgerr++;
2434
0
    }
2435
0
    else if (!(px->lbprm.expr->fetch->val & SMP_VAL_BE_SET_SRV)) {
2436
0
      ha_alert("%s '%s' [%s:%d]: error detected while parsing 'balance hash' expression '%s' "
2437
0
               "which requires information from %s, which is not available here.\n",
2438
0
               proxy_type_str(px), px->id,
2439
0
               px->conf.file, px->conf.line,
2440
0
               px->lbprm.arg_str, sample_src_names(px->lbprm.expr->fetch->use));
2441
0
      cfgerr++;
2442
0
    }
2443
0
    else if (px->mode == PR_MODE_HTTP && (px->lbprm.expr->fetch->use & SMP_USE_L6REQ)) {
2444
0
      ha_warning("%s '%s' [%s:%d]: L6 sample fetch <%s> will be ignored in 'balance hash' expression in HTTP mode.\n",
2445
0
                 proxy_type_str(px), px->id,
2446
0
                 px->conf.file, px->conf.line,
2447
0
                 px->lbprm.arg_str);
2448
0
    }
2449
0
    else
2450
0
      px->http_needed |= !!(px->lbprm.expr->fetch->use & SMP_USE_HTTP_ANY);
2451
0
  }
2452
2453
  /* only now we can check if some args remain unresolved.
2454
   * This must be done after the users and groups resolution.
2455
   */
2456
0
  err = NULL;
2457
0
  i = smp_resolve_args(px, &err);
2458
0
  cfgerr += i;
2459
0
  if (i) {
2460
0
    indent_msg(&err, 8);
2461
0
    ha_alert("%s%s\n", i > 1 ? "multiple argument resolution errors:" : "", err);
2462
0
    ha_free(&err);
2463
0
  } else
2464
0
    cfgerr += acl_find_targets(px);
2465
2466
0
  if (!(px->cap & PR_CAP_INT) && (px->mode == PR_MODE_TCP || px->mode == PR_MODE_HTTP) &&
2467
0
      (((px->cap & PR_CAP_FE) && !px->timeout.client) ||
2468
0
       ((px->cap & PR_CAP_BE) && !LIST_ISEMPTY(&px->servers) &&
2469
0
        (!px->timeout.connect ||
2470
0
         (!px->timeout.server && (px->mode == PR_MODE_HTTP || !px->timeout.tunnel)))))) {
2471
0
    ha_warning("missing timeouts for %s '%s'.\n"
2472
0
               "   | While not properly invalid, you will certainly encounter various problems\n"
2473
0
               "   | with such a configuration. To fix this, please ensure that all following\n"
2474
0
               "   | timeouts are set to a non-zero value: 'client', 'connect', 'server'.\n",
2475
0
               proxy_type_str(px), px->id);
2476
0
    *err_code |= ERR_WARN;
2477
0
  }
2478
2479
  /* Historically, the tarpit and queue timeouts were inherited from contimeout.
2480
   * We must still support older configurations, so let's find out whether those
2481
   * parameters have been set or must be copied from contimeouts.
2482
   */
2483
0
  if (!px->timeout.tarpit)
2484
0
    px->timeout.tarpit = px->timeout.connect;
2485
0
  if ((px->cap & PR_CAP_BE) && !px->timeout.queue)
2486
0
    px->timeout.queue = px->timeout.connect;
2487
2488
0
  if (px->tcpcheck.flags & TCPCHK_FL_UNUSED_TCP_RS) {
2489
0
    ha_warning("%s '%s' uses tcp-check rules without 'option tcp-check', so the rules are ignored.\n",
2490
0
               proxy_type_str(px), px->id);
2491
0
    *err_code |= ERR_WARN;
2492
0
  }
2493
2494
  /* ensure that cookie capture length is not too large */
2495
0
  if (px->capture_len >= global.tune.cookie_len) {
2496
0
    ha_warning("truncating capture length to %d bytes for %s '%s'.\n",
2497
0
               global.tune.cookie_len - 1, proxy_type_str(px), px->id);
2498
0
    *err_code |= ERR_WARN;
2499
0
    px->capture_len = global.tune.cookie_len - 1;
2500
0
  }
2501
2502
  /* The small pools required for the capture lists */
2503
0
  if (px->nb_req_cap) {
2504
0
    px->req_cap_pool = create_pool("ptrcap",
2505
0
                                         px->nb_req_cap * sizeof(char *),
2506
0
                                         MEM_F_SHARED);
2507
0
  }
2508
2509
0
  if (px->nb_rsp_cap) {
2510
0
    px->rsp_cap_pool = create_pool("ptrcap",
2511
0
                                         px->nb_rsp_cap * sizeof(char *),
2512
0
                                         MEM_F_SHARED);
2513
0
  }
2514
2515
0
  switch (px->load_server_state_from_file) {
2516
0
    case PR_SRV_STATE_FILE_UNSPEC:
2517
0
      px->load_server_state_from_file = PR_SRV_STATE_FILE_NONE;
2518
0
      break;
2519
0
    case PR_SRV_STATE_FILE_GLOBAL:
2520
0
      if (!global.server_state_file) {
2521
0
        ha_warning("backend '%s' configured to load server state file from global section 'server-state-file' directive. Unfortunately, 'server-state-file' is not set!\n",
2522
0
                   px->id);
2523
0
        *err_code |= ERR_WARN;
2524
0
      }
2525
0
      break;
2526
0
  }
2527
2528
  /* assign automatic UIDs to servers which don't have one yet */
2529
0
  next_id = 1;
2530
0
  list_for_each_entry(newsrv, &px->servers, el_px) {
2531
0
    if (!newsrv->puid) {
2532
      /* server ID not set, use automatic numbering with first
2533
       * spare entry starting with next_svid.
2534
       */
2535
0
      next_id = server_get_next_id(px, next_id);
2536
0
      newsrv->puid = next_id;
2537
0
      server_index_id(px, newsrv);
2538
0
    }
2539
2540
0
    next_id++;
2541
0
  }
2542
2543
0
  px->lbprm.wmult = 1; /* default weight multiplier */
2544
0
  px->lbprm.wdiv  = 1; /* default weight divider */
2545
2546
  /*
2547
   * If this server supports a maxconn parameter, it needs a dedicated
2548
   * tasks to fill the emptied slots when a connection leaves.
2549
   * Also, resolve deferred tracking dependency if needed.
2550
   */
2551
0
  list_for_each_entry(newsrv, &px->servers, el_px) {
2552
0
    set_usermsgs_ctx(newsrv->conf.file, newsrv->conf.line, &newsrv->obj_type);
2553
2554
0
    srv_minmax_conn_apply(newsrv);
2555
2556
0
    *err_code |= check_server_tcpcheck(newsrv);
2557
0
    if (*err_code & (ERR_ABORT|ERR_FATAL))
2558
0
      goto out;
2559
2560
    /* this will also properly set the transport layer for
2561
     * prod and checks
2562
     * if default-server have use_ssl, prerare ssl init
2563
     * without activating it */
2564
0
    if (newsrv->use_ssl == 1 || newsrv->check.use_ssl == 1 ||
2565
0
        (newsrv->check.tcpcheck->flags & TCPCHK_FL_USE_SSL) ||
2566
0
        ((newsrv->flags & SRV_F_DEFSRV_USE_SSL) && newsrv->use_ssl != 1)) {
2567
      /* QUIC servers are also updated here. */
2568
0
      if (xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv)
2569
0
        cfgerr += xprt_get(XPRT_SSL)->prepare_srv(newsrv);
2570
0
    }
2571
2572
    /* In HTTP only, if the SNI is not set and we can rely on the
2573
     * host header value, fill the sni expression accordingly
2574
     */
2575
0
    if (newsrv->proxy->mode == PR_MODE_HTTP &&
2576
0
        (newsrv->use_ssl == 1 || (newsrv->flags & SRV_F_DEFSRV_USE_SSL)) &&
2577
0
        !newsrv->sni_expr && !(newsrv->ssl_ctx.options & SRV_SSL_O_NO_AUTO_SNI)) {
2578
0
      if (srv_configure_auto_sni(newsrv, err_code, &err)) {
2579
0
        ha_alert("parsing [%s:%d]: %s.\n",
2580
0
                 newsrv->conf.file, newsrv->conf.line, err);
2581
0
        ha_free(&err);
2582
0
        ++cfgerr;
2583
0
        if (*err_code & ERR_ABORT)
2584
0
          goto out;
2585
0
        goto next_srv;
2586
0
      }
2587
0
    }
2588
2589
2590
0
    if ((newsrv->flags & SRV_F_FASTOPEN) &&
2591
0
        ((px->retry_type & (PR_RE_DISCONNECTED | PR_RE_TIMEOUT)) !=
2592
0
         (PR_RE_DISCONNECTED | PR_RE_TIMEOUT)))
2593
0
      ha_warning("server has tfo activated, the backend should be configured with at least 'conn-failure', 'empty-response' and 'response-timeout' or we wouldn't be able to retry the connection on failure.\n");
2594
2595
0
    if (newsrv->trackit) {
2596
0
      if (srv_apply_track(newsrv, px)) {
2597
0
        ++cfgerr;
2598
0
        goto next_srv;
2599
0
      }
2600
0
    }
2601
2602
0
  next_srv:
2603
0
    reset_usermsgs_ctx();
2604
0
  }
2605
2606
  /*
2607
   * Try to generate dynamic cookies for servers now.
2608
   * It couldn't be done earlier, since at the time we parsed
2609
   * the server line, we may not have known yet that we
2610
   * should use dynamic cookies, or the secret key may not
2611
   * have been provided yet.
2612
   */
2613
0
  if (px->ck_opts & PR_CK_DYNAMIC) {
2614
0
    list_for_each_entry(newsrv, &px->servers, el_px)
2615
0
      srv_set_dyncookie(newsrv);
2616
2617
0
  }
2618
  /* We have to initialize the server lookup mechanism depending
2619
   * on what LB algorithm was chosen.
2620
   */
2621
2622
0
  px->lbprm.algo &= ~(BE_LB_LKUP | BE_LB_PROP_DYN);
2623
0
  list_for_each_entry(ops, &lb_ops_list, link) {
2624
0
    int i;
2625
0
    for (i = 0; ops->map[i].match != 0; i++) {
2626
0
      if ((px->lbprm.algo & ops->map[i].mask) == ops->map[i].match) {
2627
0
        px->lbprm.ops = ops;
2628
0
        break;
2629
0
      }
2630
0
    }
2631
2632
0
    if (px->lbprm.ops) {
2633
0
      px->lbprm.algo |= px->lbprm.ops->algo_prop;
2634
0
      if (px->lbprm.ops->proxy_init && px->lbprm.ops->proxy_init(px) < 0)
2635
0
        cfgerr++;
2636
0
      break;
2637
0
    }
2638
0
  }
2639
2640
0
  HA_RWLOCK_INIT(&px->lbprm.lock);
2641
2642
0
  if (px->options & PR_O_LOGASAP)
2643
0
    px->to_log &= ~LW_BYTES;
2644
2645
0
  if (!(px->cap & PR_CAP_INT) && (px->mode == PR_MODE_TCP || px->mode == PR_MODE_HTTP) &&
2646
0
      (px->cap & PR_CAP_FE) && LIST_ISEMPTY(&px->loggers) &&
2647
0
      (!lf_expr_isempty(&px->logformat) || !lf_expr_isempty(&px->logformat_sd))) {
2648
0
    ha_warning("log format ignored for %s '%s' since it has no log address.\n",
2649
0
               proxy_type_str(px), px->id);
2650
0
    *err_code |= ERR_WARN;
2651
0
  }
2652
2653
0
  *err_code |= proxy_check_http_errors(px);
2654
2655
0
  if (px->mode != PR_MODE_HTTP && !(px->options & PR_O_HTTP_UPG)) {
2656
0
    int optnum;
2657
2658
0
    if (px->uri_auth) {
2659
0
      ha_warning("'stats' statement ignored for %s '%s' as it requires HTTP mode.\n",
2660
0
                 proxy_type_str(px), px->id);
2661
0
      *err_code |= ERR_WARN;
2662
0
      stats_uri_auth_drop(px->uri_auth);
2663
0
      px->uri_auth = NULL;
2664
0
    }
2665
2666
0
    if (px->capture_name) {
2667
0
      ha_warning("'capture' statement ignored for %s '%s' as it requires HTTP mode.\n",
2668
0
                 proxy_type_str(px), px->id);
2669
0
      *err_code |= ERR_WARN;
2670
0
    }
2671
2672
0
    if (isttest(px->monitor_uri)) {
2673
0
      ha_warning("'monitor-uri' statement ignored for %s '%s' as it requires HTTP mode.\n",
2674
0
                 proxy_type_str(px), px->id);
2675
0
      *err_code |= ERR_WARN;
2676
0
    }
2677
2678
0
    if (!LIST_ISEMPTY(&px->http_req_rules)) {
2679
0
      ha_warning("'http-request' rules ignored for %s '%s' as they require HTTP mode.\n",
2680
0
                 proxy_type_str(px), px->id);
2681
0
      *err_code |= ERR_WARN;
2682
0
    }
2683
2684
0
    if (!LIST_ISEMPTY(&px->http_res_rules)) {
2685
0
      ha_warning("'http-response' rules ignored for %s '%s' as they require HTTP mode.\n",
2686
0
                 proxy_type_str(px), px->id);
2687
0
      *err_code |= ERR_WARN;
2688
0
    }
2689
2690
0
    if (!LIST_ISEMPTY(&px->http_after_res_rules)) {
2691
0
      ha_warning("'http-after-response' rules ignored for %s '%s' as they require HTTP mode.\n",
2692
0
                 proxy_type_str(px), px->id);
2693
0
      *err_code |= ERR_WARN;
2694
0
    }
2695
2696
0
    if (!LIST_ISEMPTY(&px->redirect_rules)) {
2697
0
      ha_warning("'redirect' rules ignored for %s '%s' as they require HTTP mode.\n",
2698
0
                 proxy_type_str(px), px->id);
2699
0
      *err_code |= ERR_WARN;
2700
0
    }
2701
2702
0
    for (optnum = 0; cfg_opts[optnum].name; optnum++) {
2703
0
      if (cfg_opts[optnum].mode == PR_MODE_HTTP &&
2704
0
          (px->cap & cfg_opts[optnum].cap) &&
2705
0
          (px->options & cfg_opts[optnum].val)) {
2706
0
        ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
2707
0
                   cfg_opts[optnum].name, proxy_type_str(px), px->id);
2708
0
        *err_code |= ERR_WARN;
2709
0
        px->options &= ~cfg_opts[optnum].val;
2710
0
      }
2711
0
    }
2712
2713
0
    for (optnum = 0; cfg_opts2[optnum].name; optnum++) {
2714
0
      if (cfg_opts2[optnum].mode == PR_MODE_HTTP &&
2715
0
          (px->cap & cfg_opts2[optnum].cap) &&
2716
0
          (px->options2 & cfg_opts2[optnum].val)) {
2717
0
        ha_warning("'option %s' ignored for %s '%s' as it requires HTTP mode.\n",
2718
0
                   cfg_opts2[optnum].name, proxy_type_str(px), px->id);
2719
0
        *err_code |= ERR_WARN;
2720
0
        px->options2 &= ~cfg_opts2[optnum].val;
2721
0
      }
2722
0
    }
2723
2724
0
#if defined(CONFIG_HAP_TRANSPARENT)
2725
0
    if (px->conn_src.bind_hdr_occ) {
2726
0
      px->conn_src.bind_hdr_occ = 0;
2727
0
      ha_warning("%s '%s' : ignoring use of header %s as source IP in non-HTTP mode.\n",
2728
0
                 proxy_type_str(px), px->id, px->conn_src.bind_hdr_name);
2729
0
      *err_code |= ERR_WARN;
2730
0
    }
2731
0
#endif /* CONFIG_HAP_TRANSPARENT */
2732
0
  }
2733
2734
  /*
2735
   * ensure that we're not cross-dressing a TCP server into HTTP.
2736
   */
2737
0
  list_for_each_entry(newsrv, &px->servers, el_px) {
2738
0
    if ((px->mode != PR_MODE_HTTP) && newsrv->rdr_len) {
2739
0
      ha_alert("%s '%s' : server cannot have cookie or redirect prefix in non-HTTP mode.\n",
2740
0
               proxy_type_str(px), px->id);
2741
0
      cfgerr++;
2742
0
    }
2743
2744
0
    if ((px->mode != PR_MODE_HTTP) && newsrv->cklen) {
2745
0
      ha_warning("%s '%s' : ignoring cookie for server '%s' as HTTP mode is disabled.\n",
2746
0
                 proxy_type_str(px), px->id, newsrv->id);
2747
0
      *err_code |= ERR_WARN;
2748
0
    }
2749
2750
0
    if ((newsrv->flags & SRV_F_MAPPORTS) && (px->options2 & PR_O2_RDPC_PRST)) {
2751
0
      ha_warning("%s '%s' : RDP cookie persistence will not work for server '%s' because it lacks an explicit port number.\n",
2752
0
                 proxy_type_str(px), px->id, newsrv->id);
2753
0
      *err_code |= ERR_WARN;
2754
0
    }
2755
2756
0
#if defined(CONFIG_HAP_TRANSPARENT)
2757
0
    if (px->mode != PR_MODE_HTTP && newsrv->conn_src.bind_hdr_occ) {
2758
0
      newsrv->conn_src.bind_hdr_occ = 0;
2759
0
      ha_warning("%s '%s' : server %s cannot use header %s as source IP in non-HTTP mode.\n",
2760
0
                 proxy_type_str(px), px->id, newsrv->id, newsrv->conn_src.bind_hdr_name);
2761
0
      *err_code |= ERR_WARN;
2762
0
    }
2763
0
#endif /* CONFIG_HAP_TRANSPARENT */
2764
2765
0
    if ((px->mode != PR_MODE_HTTP) && (px->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR)
2766
0
      px->options &= ~PR_O_REUSE_MASK;
2767
0
    if (px->mode == PR_MODE_SPOP)
2768
0
      px->options |= PR_O_REUSE_ALWS;
2769
2770
0
    if ((px->mode != PR_MODE_HTTP) && newsrv->flags & SRV_F_RHTTP) {
2771
0
      ha_alert("%s '%s' : server %s uses reverse HTTP addressing which can only be used with HTTP mode.\n",
2772
0
               proxy_type_str(px), px->id, newsrv->id);
2773
0
      cfgerr++;
2774
0
      *err_code |= ERR_FATAL | ERR_ALERT;
2775
0
      goto out;
2776
0
    }
2777
0
  }
2778
2779
  /* Check filter configuration, if any */
2780
0
  cfgerr += flt_check(px);
2781
2782
0
  if (px->cap & PR_CAP_FE) {
2783
0
    if (!px->accept)
2784
0
      px->accept = frontend_accept;
2785
2786
0
    if (!LIST_ISEMPTY(&px->tcp_req.inspect_rules) ||
2787
0
        (px->defpx && !LIST_ISEMPTY(&px->defpx->tcp_req.inspect_rules)))
2788
0
      px->fe_req_ana |= AN_REQ_INSPECT_FE;
2789
2790
0
    if (px->mode == PR_MODE_HTTP) {
2791
0
      px->fe_req_ana |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_PROCESS_FE;
2792
0
      px->fe_rsp_ana |= AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_FE;
2793
0
    }
2794
2795
0
    if (px->mode == PR_MODE_CLI) {
2796
0
      px->fe_req_ana |= AN_REQ_WAIT_CLI;
2797
0
      px->fe_rsp_ana |= AN_RES_WAIT_CLI;
2798
0
    }
2799
2800
    /* both TCP and HTTP must check switching rules */
2801
0
    px->fe_req_ana |= AN_REQ_SWITCHING_RULES;
2802
2803
    /* Add filters analyzers if needed */
2804
0
    if (!LIST_ISEMPTY(&px->filter_configs)) {
2805
0
      px->fe_req_ana |= AN_REQ_FLT_START_FE | AN_REQ_FLT_XFER_DATA | AN_REQ_FLT_END;
2806
0
      px->fe_rsp_ana |= AN_RES_FLT_START_FE | AN_RES_FLT_XFER_DATA | AN_RES_FLT_END;
2807
0
    }
2808
0
  }
2809
2810
0
  if (px->cap & PR_CAP_BE) {
2811
0
    if (!LIST_ISEMPTY(&px->tcp_req.inspect_rules) ||
2812
0
        (px->defpx && !LIST_ISEMPTY(&px->defpx->tcp_req.inspect_rules)))
2813
0
      px->be_req_ana |= AN_REQ_INSPECT_BE;
2814
2815
0
    if (!LIST_ISEMPTY(&px->tcp_rep.inspect_rules) ||
2816
0
        (px->defpx && !LIST_ISEMPTY(&px->defpx->tcp_rep.inspect_rules)))
2817
0
                        px->be_rsp_ana |= AN_RES_INSPECT;
2818
2819
0
    if (px->mode == PR_MODE_HTTP) {
2820
0
      px->be_req_ana |= AN_REQ_WAIT_HTTP | AN_REQ_HTTP_INNER | AN_REQ_HTTP_PROCESS_BE;
2821
0
      px->be_rsp_ana |= AN_RES_WAIT_HTTP | AN_RES_HTTP_PROCESS_BE;
2822
0
    }
2823
2824
    /* If the backend does requires RDP cookie persistence, we have to
2825
     * enable the corresponding analyser.
2826
     */
2827
0
    if (px->options2 & PR_O2_RDPC_PRST)
2828
0
      px->be_req_ana |= AN_REQ_PRST_RDP_COOKIE;
2829
2830
    /* Add filters analyzers if needed */
2831
0
    if (!LIST_ISEMPTY(&px->filter_configs)) {
2832
0
      px->be_req_ana |= AN_REQ_FLT_START_BE | AN_REQ_FLT_XFER_DATA | AN_REQ_FLT_END;
2833
0
      px->be_rsp_ana |= AN_RES_FLT_START_BE | AN_RES_FLT_XFER_DATA | AN_RES_FLT_END;
2834
0
    }
2835
0
  }
2836
2837
  /* Check the mux protocols, if any, for each server attached to
2838
   * the current proxy */
2839
0
  list_for_each_entry(newsrv, &px->servers, el_px) {
2840
0
    int mode = conn_pr_mode_to_proto_mode(px->mode);
2841
0
    const struct mux_proto_list *mux_ent;
2842
2843
0
    if (srv_is_quic(newsrv)) {
2844
0
      if (!newsrv->mux_proto) {
2845
        /* Force QUIC as mux-proto on server with quic addresses, similarly to bind on FE side. */
2846
0
        newsrv->mux_proto = get_mux_proto(ist("quic"));
2847
0
      }
2848
0
    }
2849
2850
0
    if (!newsrv->mux_proto)
2851
0
      continue;
2852
2853
    /* it is possible that an incorrect mux was referenced
2854
     * due to the proxy's mode not being taken into account
2855
     * on first pass. Let's adjust it now.
2856
     */
2857
0
    mux_ent = conn_get_best_mux_entry(newsrv->mux_proto->mux_proto, IST_NULL, PROTO_SIDE_BE, srv_is_quic(newsrv), mode);
2858
2859
0
    if (!mux_ent || !isteq(mux_ent->mux_proto, newsrv->mux_proto->mux_proto)) {
2860
0
      ha_alert("%s '%s' : MUX protocol '%.*s' is not usable for server '%s' at [%s:%d].\n",
2861
0
               proxy_type_str(px), px->id,
2862
0
               (int)newsrv->mux_proto->mux_proto.len,
2863
0
               newsrv->mux_proto->mux_proto.ptr,
2864
0
               newsrv->id, newsrv->conf.file, newsrv->conf.line);
2865
0
      cfgerr++;
2866
0
    }
2867
0
    else {
2868
0
      if ((mux_ent->mux->flags & MX_FL_FRAMED) && !srv_is_quic(newsrv)) {
2869
0
        ha_alert("%s '%s' : MUX protocol '%.*s' is incompatible with stream transport used by server '%s' at [%s:%d].\n",
2870
0
                 proxy_type_str(px), px->id,
2871
0
                 (int)newsrv->mux_proto->mux_proto.len,
2872
0
                 newsrv->mux_proto->mux_proto.ptr,
2873
0
                 newsrv->id, newsrv->conf.file, newsrv->conf.line);
2874
0
        cfgerr++;
2875
0
      }
2876
0
      else if (!(mux_ent->mux->flags & MX_FL_FRAMED) && srv_is_quic(newsrv)) {
2877
0
        ha_alert("%s '%s' : MUX protocol '%.*s' is incompatible with framed transport used by server '%s' at [%s:%d].\n",
2878
0
                 proxy_type_str(px), px->id,
2879
0
                 (int)newsrv->mux_proto->mux_proto.len,
2880
0
                 newsrv->mux_proto->mux_proto.ptr,
2881
0
                 newsrv->id, newsrv->conf.file, newsrv->conf.line);
2882
0
        cfgerr++;
2883
0
      }
2884
0
    }
2885
2886
    /* update the mux */
2887
0
    newsrv->mux_proto = mux_ent;
2888
0
  }
2889
2890
  /* Allocate default tcp-check rules for proxies without
2891
   * explicit rules.
2892
   */
2893
0
  if (px->cap & PR_CAP_BE) {
2894
0
    if (!(px->options2 & PR_O2_CHK_ANY)) {
2895
0
      struct tcpcheck_ruleset *rs = NULL;
2896
2897
0
      px->options2 |= PR_O2_TCPCHK_CHK;
2898
2899
0
      rs = find_tcpcheck_ruleset("*tcp-check");
2900
0
      if (!rs) {
2901
0
        rs = create_tcpcheck_ruleset("*tcp-check");
2902
0
        if (rs == NULL) {
2903
0
          ha_alert("config: %s '%s': out of memory.\n",
2904
0
                   proxy_type_str(px), px->id);
2905
0
          cfgerr++;
2906
0
        }
2907
0
      }
2908
0
      px->tcpcheck.rs = rs;
2909
0
      free_tcpcheck_vars(&px->tcpcheck.preset_vars);
2910
0
    }
2911
0
  }
2912
2913
0
 out:
2914
0
  if (cfgerr)
2915
0
    *err_code |= ERR_ALERT | ERR_FATAL;
2916
2917
0
  return cfgerr;
2918
0
}
2919
2920
/* Frees all dynamic settings allocated on a default proxy that's about to be
2921
 * destroyed. Note that most of the fields are not even reset, so extreme care
2922
 * is required here.
2923
 */
2924
static void defaults_px_free(struct proxy *defproxy)
2925
0
{
2926
0
  struct cap_hdr *h,*h_next;
2927
2928
0
  proxy_free_common(defproxy);
2929
2930
  /* default proxy specific cleanup */
2931
0
  if (defproxy->defsrv)
2932
0
    srv_free_params(defproxy->defsrv);
2933
0
  ha_free(&defproxy->defbe.name);
2934
0
  srv_free(&defproxy->defsrv);
2935
2936
0
  h = defproxy->req_cap;
2937
0
  while (h) {
2938
0
    h_next = h->next;
2939
0
    free(h->name);
2940
0
    pool_destroy(h->pool);
2941
0
    free(h);
2942
0
    h = h_next;
2943
0
  }
2944
2945
0
  h = defproxy->rsp_cap;
2946
0
  while (h) {
2947
0
    h_next = h->next;
2948
0
    free(h->name);
2949
0
    pool_destroy(h->pool);
2950
0
    free(h);
2951
0
    h = h_next;
2952
0
  }
2953
2954
0
  proxy_release_conf_errors(defproxy);
2955
0
  deinit_proxy_tcpcheck(defproxy);
2956
0
}
2957
2958
/* Removes <px> defaults instance from the name tree, free its content and
2959
 * storage. This must only be used if <px> is unreferenced.
2960
 *
2961
 * Uses PROXIES_DEL_LOCK to protect global tree/list accesses.
2962
 */
2963
void defaults_px_destroy(struct proxy *px)
2964
0
{
2965
0
  BUG_ON(!(px->cap & PR_CAP_DEF));
2966
0
  BUG_ON(px->conf.def_ref != 0);
2967
2968
0
  HA_SPIN_LOCK(PROXIES_DEL_LOCK, &proxies_del_lock);
2969
0
  cebis_item_delete(&defproxy_by_name, conf.name_node, id, px);
2970
0
  LIST_DELETE(&px->el);
2971
0
  HA_SPIN_UNLOCK(PROXIES_DEL_LOCK, &proxies_del_lock);
2972
2973
0
  defaults_px_free(px);
2974
0
  free(px);
2975
0
}
2976
2977
/* delete all unreferenced default proxies. A default proxy is unreferenced if
2978
 * its <def_ref> count is equal to zero.
2979
 *
2980
 * Not thread safe - currently only used during init.
2981
 */
2982
void defaults_px_destroy_all_unref(void)
2983
0
{
2984
0
  struct proxy *px, *nx;
2985
2986
0
  for (px = cebis_item_first(&defproxy_by_name, conf.name_node, id, struct proxy); px; px = nx) {
2987
0
    BUG_ON(!(px->cap & PR_CAP_DEF));
2988
0
    nx = cebis_item_next(&defproxy_by_name, conf.name_node, id, px);
2989
0
    if (!HA_ATOMIC_LOAD(&px->conf.def_ref))
2990
0
      defaults_px_destroy(px);
2991
0
  }
2992
0
}
2993
2994
/* Removes <px> defaults from the name tree. This operation is useful when a
2995
 * section is made invisible by a newer instance with the same name. If <px> is
2996
 * not referenced it is freed immediately, else it is kept in defaults_list.
2997
 *
2998
 * Not thread safe - currently only used during parsing.
2999
 */
3000
void defaults_px_detach(struct proxy *px)
3001
0
{
3002
0
  BUG_ON(!(px->cap & PR_CAP_DEF));
3003
0
  cebis_item_delete(&defproxy_by_name, conf.name_node, id, px);
3004
0
  if (!HA_ATOMIC_LOAD(&px->conf.def_ref))
3005
0
    defaults_px_destroy(px);
3006
  /* If not destroyed, <px> can still be accessed in <defaults_list>. */
3007
0
}
3008
3009
/* Increments by one defaults proxy reference of all defaults stored in tree name.
3010
 *
3011
 * Not thread safe - currently only used during init.
3012
 */
3013
void defaults_px_ref_all(void)
3014
0
{
3015
0
  struct proxy *px;
3016
3017
0
  for (px = cebis_item_first(&defproxy_by_name, conf.name_node, id, struct proxy);
3018
0
       px;
3019
0
       px = cebis_item_next(&defproxy_by_name, conf.name_node, id, px)) {
3020
0
    HA_ATOMIC_INC(&px->conf.def_ref);
3021
0
  }
3022
0
}
3023
3024
/* Decrements defaults proxy ref of all defaults. This is the reverse of
3025
 * defaults_px_ref_all().
3026
 *
3027
 * Not thread safe - currently only used during deinit.
3028
 */
3029
void defaults_px_unref_all(void)
3030
0
{
3031
0
  struct proxy *px, *nx;
3032
3033
0
  for (px = cebis_item_first(&defproxy_by_name, conf.name_node, id, struct proxy); px; px = nx) {
3034
0
    nx = cebis_item_next(&defproxy_by_name, conf.name_node, id, px);
3035
3036
0
    BUG_ON(!px->conf.def_ref);
3037
0
    if (!HA_ATOMIC_SUB_FETCH(&px->conf.def_ref, 1))
3038
0
      defaults_px_destroy(px);
3039
0
  }
3040
0
}
3041
3042
/* Add a reference on the default proxy <defpx> for the proxy <px> Nothing is
3043
 * done if <px> already references <defpx>. Otherwise, the default proxy
3044
 * <def_ref> count is incremented by one.
3045
 *
3046
 * Access on default proxy reference is thread safe thanks to atomic ops.
3047
 */
3048
static inline void defaults_px_ref(struct proxy *defpx, struct proxy *px)
3049
0
{
3050
0
  if (px->defpx == defpx)
3051
0
    return;
3052
  /* <px> is already referencing another defaults. */
3053
0
  BUG_ON(px->defpx);
3054
3055
0
  px->defpx = defpx;
3056
0
  HA_ATOMIC_INC(&defpx->conf.def_ref);
3057
0
}
3058
3059
/* Check that <px> can inherits from <defpx> default proxy. If some settings
3060
 * cannot be copied, <def_ref> count of the defaults instance is incremented.
3061
 * Inheritance may be impossible due to incompatibility issues. In this case,
3062
 * <errmsg> will be allocated to point to a textual description of the error.
3063
 *
3064
 * Returns ERR_NONE on success and a combination of ERR_CODE on failure
3065
 */
3066
int proxy_ref_defaults(struct proxy *px, struct proxy *defpx, char **errmsg)
3067
0
{
3068
0
  char defcap = defpx->cap & PR_CAP_LISTEN;
3069
0
  int err_code = ERR_NONE;
3070
3071
0
  if ((px->cap & PR_CAP_BE) && (defpx->nb_req_cap || defpx->nb_rsp_cap)) {
3072
0
    memprintf(errmsg, "backend or defaults sections cannot inherit from a defaults section defining"
3073
0
             " captures (defaults section at %s:%d)",
3074
0
             defpx->conf.file, defpx->conf.line);
3075
0
    err_code |= ERR_ALERT | ERR_ABORT;
3076
0
    goto out;
3077
0
  }
3078
3079
  /* If the current default proxy defines TCP/HTTP rules, the
3080
   * current proxy will keep a reference on it. But some sanity
3081
   * checks are performed first:
3082
   *
3083
   * - It cannot be used to init a defaults section
3084
   * - It cannot be used to init a listen section
3085
   * - It cannot be used to init backend and frontend sections at
3086
   *   same time. It can be used to init several sections of the
3087
   *   same type only.
3088
   * - It cannot define L4/L5 TCP rules if it is used to init
3089
   *   backend sections.
3090
   * - It cannot define 'tcp-response content' rules if it
3091
   *   is used to init frontend sections.
3092
   *
3093
   * If no error is found, <def_ref> count of the default proxy is incremented.
3094
   */
3095
0
  if ((!LIST_ISEMPTY(&defpx->http_req_rules)        ||
3096
0
       !LIST_ISEMPTY(&defpx->http_res_rules)        ||
3097
0
       !LIST_ISEMPTY(&defpx->http_after_res_rules)  ||
3098
0
       !LIST_ISEMPTY(&defpx->tcp_req.l4_rules)      ||
3099
0
       !LIST_ISEMPTY(&defpx->tcp_req.l5_rules)      ||
3100
0
       !LIST_ISEMPTY(&defpx->tcp_req.inspect_rules) ||
3101
0
       !LIST_ISEMPTY(&defpx->tcp_rep.inspect_rules))) {
3102
3103
    /* Note: Add tcpcheck_rules too if unresolve args become allowed in defaults section */
3104
0
    if (px->cap & PR_CAP_DEF) {
3105
0
      memprintf(errmsg, "a defaults section cannot inherit from a defaults section defining TCP/HTTP rules (defaults section at %s:%d)",
3106
0
                defpx->conf.file, defpx->conf.line);
3107
0
      err_code |= ERR_ALERT | ERR_ABORT;
3108
0
      goto out;
3109
0
    }
3110
0
    else if ((px->cap & PR_CAP_LISTEN) == PR_CAP_LISTEN) {
3111
0
      memprintf(errmsg, "a listen section cannot inherit from a defaults section defining TCP/HTTP rules");
3112
0
      err_code |= ERR_ALERT | ERR_ABORT;
3113
0
      goto out;
3114
0
    }
3115
0
    else if ((defcap == PR_CAP_BE || defcap == PR_CAP_FE) && (px->cap & PR_CAP_LISTEN) != defcap) {
3116
0
      memprintf(errmsg, "frontends and backends cannot inherit from the same defaults section"
3117
0
               " if it defines TCP/HTTP rules (defaults section at %s:%d)",
3118
0
               defpx->conf.file, defpx->conf.line);
3119
0
      err_code |= ERR_ALERT | ERR_ABORT;
3120
0
      goto out;
3121
0
    }
3122
0
    else if (!(px->cap & PR_CAP_FE) && (!LIST_ISEMPTY(&defpx->tcp_req.l4_rules) ||
3123
0
             !LIST_ISEMPTY(&defpx->tcp_req.l5_rules))) {
3124
0
      memprintf(errmsg, "a backend section cannot inherit from a defaults section defining"
3125
0
               " 'tcp-request connection' or 'tcp-request session' rules (defaults section at %s:%d)",
3126
0
               defpx->conf.file, defpx->conf.line);
3127
0
      err_code |= ERR_ALERT | ERR_ABORT;
3128
0
      goto out;
3129
0
    }
3130
0
    else if (!(px->cap & PR_CAP_BE) && !LIST_ISEMPTY(&defpx->tcp_rep.inspect_rules)) {
3131
0
      memprintf(errmsg, "a frontend section cannot inherit from a defaults section defining"
3132
0
               " 'tcp-response content' rules (defaults section at %s:%d)",
3133
0
               defpx->conf.file, defpx->conf.line);
3134
0
      err_code |= ERR_ALERT | ERR_ABORT;
3135
0
      goto out;
3136
0
    }
3137
3138
0
    defpx->cap = (defpx->cap & ~PR_CAP_LISTEN) | (px->cap & PR_CAP_LISTEN);
3139
0
    defaults_px_ref(defpx, px);
3140
0
  }
3141
3142
0
  if (defpx->tcpcheck.rs && (defpx->tcpcheck.rs->flags & TCPCHK_RULES_PROTO_CHK) &&
3143
0
      (px->cap & PR_CAP_LISTEN) == PR_CAP_BE) {
3144
    /* If the current default proxy defines tcpcheck rules, the
3145
     * current proxy will keep a reference on it. but only if the
3146
     * current proxy has the backend capability.
3147
     */
3148
0
    defaults_px_ref(defpx, px);
3149
0
  }
3150
3151
0
 out:
3152
0
  return err_code;
3153
0
}
3154
3155
/* proxy <px> removes its reference on its default proxy. The default proxy
3156
 * <def_ref> count is decremented by one. If it was the last reference, the
3157
 * corresponding default proxy is destroyed.
3158
 *
3159
 * Access on default proxy reference is thread safe thanks to atomic ops.
3160
 */
3161
void proxy_unref_defaults(struct proxy *px)
3162
0
{
3163
0
  if (px->defpx == NULL)
3164
0
    return;
3165
0
  if (!HA_ATOMIC_SUB_FETCH(&px->defpx->conf.def_ref, 1))
3166
0
    defaults_px_destroy(px->defpx);
3167
0
  px->defpx = NULL;
3168
0
}
3169
3170
/* prepares a new proxy <name> of type <cap> from the provided <px>
3171
 * pointer.
3172
 * <px> is assumed to be freshly allocated
3173
 * <name> may be NULL: proxy id assignment will be skipped.
3174
 *
3175
 * Returns a 1 on success or 0 on failure (in which case errmsg must be checked
3176
 * then freed).
3177
 */
3178
int setup_new_proxy(struct proxy *px, const char *name, unsigned int cap, char **errmsg)
3179
0
{
3180
0
  init_new_proxy(px);
3181
3182
0
  if (name) {
3183
0
    px->id = strdup(name);
3184
0
    if (!px->id) {
3185
0
      memprintf(errmsg, "out of memory");
3186
0
      goto fail;
3187
0
    }
3188
0
  }
3189
3190
0
  px->cap = cap;
3191
0
  px->last_change = ns_to_sec(now_ns);
3192
3193
  /* Internal proxies or with empty name are not stored in the named tree. */
3194
0
  if (name && name[0] != '\0' && !(cap & PR_CAP_INT))
3195
0
    proxy_store_name(px);
3196
3197
0
  if (!(cap & PR_CAP_DEF))
3198
0
    LIST_APPEND(&all_proxies, &px->global_list);
3199
3200
0
  return 1;
3201
3202
0
 fail:
3203
0
  if (name)
3204
0
    memprintf(errmsg, "proxy '%s': %s", name, *errmsg);
3205
3206
0
  srv_free(&px->defsrv);
3207
0
  ha_free(&px->id);
3208
0
  counters_fe_shared_drop(&px->fe_counters.shared);
3209
0
  counters_be_shared_drop(&px->be_counters.shared);
3210
3211
0
  return 0;
3212
0
}
3213
3214
/* Allocates a new proxy <name> of type <cap>.
3215
 * Returns the proxy instance on success. On error, NULL is returned.
3216
 */
3217
struct proxy *alloc_new_proxy(const char *name, unsigned int cap, char **errmsg)
3218
0
{
3219
0
  struct proxy *curproxy;
3220
3221
0
  if ((curproxy = ha_aligned_zalloc_typed(1, typeof(*curproxy))) == NULL) {
3222
0
    memprintf(errmsg, "proxy '%s': out of memory", name);
3223
0
    goto fail;
3224
0
  }
3225
3226
0
  if (!setup_new_proxy(curproxy, name, cap, errmsg))
3227
0
    goto fail;
3228
3229
0
  proxy_take(curproxy);
3230
3231
0
 done:
3232
0
  return curproxy;
3233
3234
0
 fail:
3235
  /* Note: in case of fatal error here, we WILL make valgrind unhappy,
3236
   * but its not worth trying to unroll everything here just before
3237
   * quitting.
3238
   */
3239
0
  if (curproxy)
3240
0
    srv_free(&curproxy->defsrv);
3241
0
  free(curproxy);
3242
0
  return NULL;
3243
0
}
3244
3245
/* Increment <px> refcount. Does nothing for a default proxy instance. */
3246
void proxy_take(struct proxy *px)
3247
0
{
3248
0
  if (!(px->cap & PR_CAP_DEF))
3249
0
    HA_ATOMIC_INC(&px->refcount);
3250
0
}
3251
3252
/* post-check for proxies */
3253
static int proxy_postcheck(struct proxy *px)
3254
0
{
3255
0
  struct listener *listener;
3256
0
  char *errmsg = NULL;
3257
0
  int err_code = ERR_NONE;
3258
3259
  /* allocate private memory for shared counters: used as a fallback
3260
   * or when sharing is disabled. If sharing is enabled pointers will
3261
   * be updated to point to the proper shared memory location during
3262
   * proxy postparsing, see proxy_postparse()
3263
   */
3264
0
  if (px->cap & PR_CAP_FE) {
3265
0
    if (!counters_fe_shared_prepare(&px->fe_counters.shared, &px->guid, &errmsg)) {
3266
0
      ha_alert("out of memory while setting up shared counters for %s %s : %s\n",
3267
0
               proxy_type_str(px), px->id, errmsg);
3268
0
      ha_free(&errmsg);
3269
0
      err_code |= ERR_ALERT | ERR_FATAL;
3270
0
      goto out;
3271
0
    }
3272
0
  }
3273
0
  if (px->cap & (PR_CAP_FE|PR_CAP_BE)) {
3274
    /* by default stream->be points to stream->fe, thus proxy
3275
     * be_counters may be used even if the proxy lacks the backend
3276
     * capability
3277
     */
3278
0
    if (!counters_be_shared_prepare(&px->be_counters.shared, &px->guid, &errmsg)) {
3279
0
      ha_alert("out of memory while setting up shared counters for %s %s : %s\n",
3280
0
               proxy_type_str(px), px->id, errmsg);
3281
0
      ha_free(&errmsg);
3282
0
      err_code |= ERR_ALERT | ERR_FATAL;
3283
0
      goto out;
3284
0
    }
3285
3286
0
  }
3287
3288
0
  list_for_each_entry(listener, &px->conf.listeners, by_fe) {
3289
0
    if (listener->counters) {
3290
0
      if (!counters_fe_shared_prepare(&listener->counters->shared, &listener->guid, &errmsg)) {
3291
0
        ha_free(&listener->counters);
3292
0
        ha_alert("out of memory while setting up shared listener counters for %s %s : %s\n",
3293
0
                 proxy_type_str(px), px->id, errmsg);
3294
0
        ha_free(&errmsg);
3295
0
        err_code |= ERR_ALERT | ERR_FATAL;
3296
0
        goto out;
3297
0
      }
3298
0
    }
3299
0
  }
3300
3301
0
 out:
3302
0
  return err_code;
3303
0
}
3304
REGISTER_POST_PROXY_CHECK(proxy_postcheck);
3305
3306
/* Copy the proxy settings from <defproxy> to <curproxy>.
3307
 * Returns 0 on success.
3308
 * Returns 1 on error. <errmsg> will be allocated with an error description.
3309
 */
3310
static int proxy_defproxy_cpy(struct proxy *curproxy, const struct proxy *defproxy,
3311
                              char **errmsg)
3312
0
{
3313
0
  struct logger *tmplogger;
3314
0
  char *tmpmsg = NULL;
3315
3316
  /* set default values from the specified default proxy */
3317
3318
0
  if (defproxy->defsrv) {
3319
0
    if (!curproxy->defsrv) {
3320
      /* there's a default-server in the defaults proxy but
3321
       * none allocated yet in the current proxy so we have
3322
       * to allocate and pre-initialize it right now.
3323
       */
3324
0
      curproxy->defsrv = srv_alloc();
3325
0
      if (!curproxy->defsrv) {
3326
0
        memprintf(errmsg, "proxy '%s': out of memory allocating default-server", curproxy->id);
3327
0
        return 1;
3328
0
      }
3329
3330
0
      curproxy->defsrv->id = NULL;
3331
0
      srv_settings_init(curproxy->defsrv);
3332
0
    }
3333
0
    srv_settings_cpy(curproxy->defsrv, defproxy->defsrv, 0);
3334
0
  }
3335
3336
0
  curproxy->flags = (defproxy->flags & PR_FL_DISABLED); /* Only inherit from disabled flag */
3337
0
  curproxy->options = defproxy->options;
3338
0
  curproxy->options2 = defproxy->options2;
3339
0
  curproxy->no_options = defproxy->no_options;
3340
0
  curproxy->no_options2 = defproxy->no_options2;
3341
0
  curproxy->retry_type = defproxy->retry_type;
3342
0
  curproxy->tcp_req.inspect_delay = defproxy->tcp_req.inspect_delay;
3343
0
  curproxy->tcp_rep.inspect_delay = defproxy->tcp_rep.inspect_delay;
3344
3345
0
  http_ext_clean(curproxy);
3346
0
  http_ext_dup(defproxy, curproxy);
3347
3348
0
  if (isttest(defproxy->server_id_hdr_name))
3349
0
    curproxy->server_id_hdr_name = istdup(defproxy->server_id_hdr_name);
3350
3351
  /* initialize error relocations */
3352
0
  if (!proxy_dup_default_conf_errors(curproxy, defproxy, &tmpmsg)) {
3353
0
    memprintf(errmsg, "proxy '%s' : %s", curproxy->id, tmpmsg);
3354
0
    free(tmpmsg);
3355
0
    return 1;
3356
0
  }
3357
3358
0
  if (curproxy->cap & PR_CAP_FE) {
3359
0
    curproxy->maxconn = defproxy->maxconn;
3360
0
    curproxy->backlog = defproxy->backlog;
3361
0
    curproxy->fe_sps_lim = defproxy->fe_sps_lim;
3362
3363
0
    curproxy->to_log = defproxy->to_log & ~LW_COOKIE & ~LW_REQHDR & ~ LW_RSPHDR;
3364
0
    curproxy->max_out_conns = defproxy->max_out_conns;
3365
3366
0
    curproxy->clitcpka_cnt   = defproxy->clitcpka_cnt;
3367
0
    curproxy->clitcpka_idle  = defproxy->clitcpka_idle;
3368
0
    curproxy->clitcpka_intvl = defproxy->clitcpka_intvl;
3369
0
    curproxy->stream_new_from_sc = defproxy->stream_new_from_sc;
3370
0
  }
3371
3372
0
  if (curproxy->cap & PR_CAP_BE) {
3373
0
    curproxy->lbprm.algo = defproxy->lbprm.algo;
3374
0
    curproxy->lbprm.hash_balance_factor = defproxy->lbprm.hash_balance_factor;
3375
0
    curproxy->fullconn = defproxy->fullconn;
3376
0
    curproxy->conn_retries = defproxy->conn_retries;
3377
0
    curproxy->redispatch_after = defproxy->redispatch_after;
3378
0
    curproxy->max_ka_queue = defproxy->max_ka_queue;
3379
3380
0
    curproxy->tcpcheck.flags = (defproxy->tcpcheck.flags & ~TCPCHK_FL_UNUSED_RS);
3381
0
    curproxy->tcpcheck.rs  = defproxy->tcpcheck.rs;
3382
0
    if (!dup_tcpcheck_vars(&curproxy->tcpcheck.preset_vars,
3383
0
               &defproxy->tcpcheck.preset_vars)) {
3384
0
      memprintf(errmsg, "proxy '%s': failed to duplicate tcpcheck preset-vars", curproxy->id);
3385
0
      return 1;
3386
0
    }
3387
3388
0
    curproxy->ck_opts = defproxy->ck_opts;
3389
3390
0
    if (defproxy->cookie_name)
3391
0
      curproxy->cookie_name = strdup(defproxy->cookie_name);
3392
0
    curproxy->cookie_len = defproxy->cookie_len;
3393
3394
0
    if (defproxy->dyncookie_key)
3395
0
      curproxy->dyncookie_key = strdup(defproxy->dyncookie_key);
3396
0
    if (defproxy->cookie_domain)
3397
0
      curproxy->cookie_domain = strdup(defproxy->cookie_domain);
3398
3399
0
    if (defproxy->cookie_maxidle)
3400
0
      curproxy->cookie_maxidle = defproxy->cookie_maxidle;
3401
3402
0
    if (defproxy->cookie_maxlife)
3403
0
      curproxy->cookie_maxlife = defproxy->cookie_maxlife;
3404
3405
0
    if (defproxy->rdp_cookie_name)
3406
0
      curproxy->rdp_cookie_name = strdup(defproxy->rdp_cookie_name);
3407
0
    curproxy->rdp_cookie_len = defproxy->rdp_cookie_len;
3408
3409
0
    if (defproxy->cookie_attrs)
3410
0
      curproxy->cookie_attrs = strdup(defproxy->cookie_attrs);
3411
3412
0
    if (defproxy->lbprm.arg_str)
3413
0
      curproxy->lbprm.arg_str = strdup(defproxy->lbprm.arg_str);
3414
0
    curproxy->lbprm.arg_len  = defproxy->lbprm.arg_len;
3415
0
    curproxy->lbprm.arg_opt1 = defproxy->lbprm.arg_opt1;
3416
0
    curproxy->lbprm.arg_opt2 = defproxy->lbprm.arg_opt2;
3417
0
    curproxy->lbprm.arg_opt3 = defproxy->lbprm.arg_opt3;
3418
3419
0
    if (defproxy->conn_src.iface_name)
3420
0
      curproxy->conn_src.iface_name = strdup(defproxy->conn_src.iface_name);
3421
0
    curproxy->conn_src.iface_len = defproxy->conn_src.iface_len;
3422
0
    curproxy->conn_src.opts = defproxy->conn_src.opts;
3423
0
#if defined(CONFIG_HAP_TRANSPARENT)
3424
0
    curproxy->conn_src.tproxy_addr = defproxy->conn_src.tproxy_addr;
3425
0
#endif
3426
0
    curproxy->load_server_state_from_file = defproxy->load_server_state_from_file;
3427
3428
0
    curproxy->srvtcpka_cnt   = defproxy->srvtcpka_cnt;
3429
0
    curproxy->srvtcpka_idle  = defproxy->srvtcpka_idle;
3430
0
    curproxy->srvtcpka_intvl = defproxy->srvtcpka_intvl;
3431
0
  }
3432
3433
0
  if (curproxy->cap & PR_CAP_FE) {
3434
0
    if (defproxy->capture_name)
3435
0
      curproxy->capture_name = strdup(defproxy->capture_name);
3436
0
    curproxy->capture_namelen = defproxy->capture_namelen;
3437
0
    curproxy->capture_len = defproxy->capture_len;
3438
3439
0
    curproxy->nb_req_cap = defproxy->nb_req_cap;
3440
0
    curproxy->req_cap = defproxy->req_cap;
3441
3442
0
    curproxy->nb_rsp_cap = defproxy->nb_rsp_cap;
3443
0
    curproxy->rsp_cap = defproxy->rsp_cap;
3444
0
  }
3445
3446
0
  if (curproxy->cap & PR_CAP_FE) {
3447
0
    curproxy->timeout.client = defproxy->timeout.client;
3448
0
    curproxy->timeout.client_hs = defproxy->timeout.client_hs;
3449
0
    curproxy->timeout.clientfin = defproxy->timeout.clientfin;
3450
0
    curproxy->timeout.tarpit = defproxy->timeout.tarpit;
3451
0
    curproxy->timeout.httpreq = defproxy->timeout.httpreq;
3452
0
    curproxy->timeout.httpka = defproxy->timeout.httpka;
3453
0
    if (isttest(defproxy->monitor_uri))
3454
0
      curproxy->monitor_uri = istdup(defproxy->monitor_uri);
3455
0
    if (defproxy->defbe.name)
3456
0
      curproxy->defbe.name = strdup(defproxy->defbe.name);
3457
3458
0
    lf_expr_dup(&defproxy->logformat, &curproxy->logformat);
3459
0
    lf_expr_dup(&defproxy->logformat_sd, &curproxy->logformat_sd);
3460
0
    lf_expr_dup(&defproxy->logformat_error, &curproxy->logformat_error);
3461
0
  }
3462
3463
0
  if (curproxy->cap & PR_CAP_BE) {
3464
0
    curproxy->timeout.connect = defproxy->timeout.connect;
3465
0
    curproxy->timeout.server = defproxy->timeout.server;
3466
0
    curproxy->timeout.serverfin = defproxy->timeout.serverfin;
3467
0
    curproxy->timeout.check = defproxy->timeout.check;
3468
0
    curproxy->timeout.queue = defproxy->timeout.queue;
3469
0
    curproxy->timeout.tarpit = defproxy->timeout.tarpit;
3470
0
    curproxy->timeout.httpreq = defproxy->timeout.httpreq;
3471
0
    curproxy->timeout.httpka = defproxy->timeout.httpka;
3472
0
    curproxy->timeout.tunnel = defproxy->timeout.tunnel;
3473
0
    curproxy->conn_src.source_addr = defproxy->conn_src.source_addr;
3474
0
  }
3475
3476
0
  curproxy->mode = defproxy->mode;
3477
3478
  /* for stats */
3479
0
  stats_uri_auth_drop(curproxy->uri_auth);
3480
0
  stats_uri_auth_take(defproxy->uri_auth);
3481
0
  curproxy->uri_auth = defproxy->uri_auth;
3482
3483
  /* copy default loggers to curproxy */
3484
0
  list_for_each_entry(tmplogger, &defproxy->loggers, list) {
3485
0
    struct logger *node = dup_logger(tmplogger);
3486
3487
0
    if (!node) {
3488
0
      memprintf(errmsg, "proxy '%s': out of memory", curproxy->id);
3489
0
      return 1;
3490
0
    }
3491
0
    LIST_APPEND(&curproxy->loggers, &node->list);
3492
0
  }
3493
3494
0
  lf_expr_dup(&defproxy->format_unique_id, &curproxy->format_unique_id);
3495
3496
0
  chunk_dup(&curproxy->log_tag, &defproxy->log_tag);
3497
3498
  /* copy default header unique id */
3499
0
  if (isttest(defproxy->header_unique_id)) {
3500
0
    const struct ist copy = istdup(defproxy->header_unique_id);
3501
3502
0
    if (!isttest(copy)) {
3503
0
      memprintf(errmsg, "proxy '%s': out of memory for unique-id-header", curproxy->id);
3504
0
      return 1;
3505
0
    }
3506
0
    curproxy->header_unique_id = copy;
3507
0
  }
3508
3509
  /* default compression options */
3510
0
  if (defproxy->comp != NULL) {
3511
0
    curproxy->comp = calloc(1, sizeof(*curproxy->comp));
3512
0
    if (!curproxy->comp) {
3513
0
      memprintf(errmsg, "proxy '%s': out of memory for default compression options", curproxy->id);
3514
0
      return 1;
3515
0
    }
3516
0
    curproxy->comp->algos_res = defproxy->comp->algos_res;
3517
0
    curproxy->comp->algo_req = defproxy->comp->algo_req;
3518
0
    curproxy->comp->types_res = defproxy->comp->types_res;
3519
0
    curproxy->comp->types_req = defproxy->comp->types_req;
3520
0
    curproxy->comp->minsize_res = defproxy->comp->minsize_res;
3521
0
    curproxy->comp->minsize_req = defproxy->comp->minsize_req;
3522
0
    curproxy->comp->flags = defproxy->comp->flags;
3523
0
  }
3524
3525
0
  if (defproxy->check_path)
3526
0
    curproxy->check_path = strdup(defproxy->check_path);
3527
0
  if (defproxy->check_command)
3528
0
    curproxy->check_command = strdup(defproxy->check_command);
3529
3530
0
  BUG_ON(curproxy->email_alert.flags & PR_EMAIL_ALERT_RESOLVED);
3531
0
  if (defproxy->email_alert.mailers.name)
3532
0
    curproxy->email_alert.mailers.name = strdup(defproxy->email_alert.mailers.name);
3533
0
  if (defproxy->email_alert.from)
3534
0
    curproxy->email_alert.from = strdup(defproxy->email_alert.from);
3535
0
  if (defproxy->email_alert.to)
3536
0
    curproxy->email_alert.to = strdup(defproxy->email_alert.to);
3537
0
  if (defproxy->email_alert.myhostname)
3538
0
    curproxy->email_alert.myhostname = strdup(defproxy->email_alert.myhostname);
3539
0
  curproxy->email_alert.level = defproxy->email_alert.level;
3540
0
  curproxy->email_alert.flags = defproxy->email_alert.flags;
3541
3542
0
  if (curproxy->cap & PR_CAP_FE) // don't inherit on backends
3543
0
    curproxy->conf.log_steps = defproxy->conf.log_steps;
3544
3545
0
  return 0;
3546
0
}
3547
3548
/* Allocates a new proxy <name> of type <cap> found at position <file:linenum>,
3549
 * preset it from the defaults of <defproxy> and returns it. In case of error,
3550
 * an alert is printed and NULL is returned.
3551
 */
3552
struct proxy *parse_new_proxy(const char *name, unsigned int cap,
3553
                              const char *file, int linenum,
3554
                              const struct proxy *defproxy)
3555
0
{
3556
0
  struct proxy *curproxy = NULL;
3557
0
  char *errmsg = NULL;
3558
3559
0
  if (!(curproxy = alloc_new_proxy(name, cap, &errmsg))) {
3560
0
    ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
3561
0
    free(errmsg);
3562
0
    return NULL;
3563
0
  }
3564
3565
0
  if (defproxy) {
3566
0
    if (proxy_defproxy_cpy(curproxy, defproxy, &errmsg)) {
3567
0
      ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg);
3568
0
      free(errmsg);
3569
3570
0
      proxy_drop(curproxy);
3571
0
      return NULL;
3572
0
    }
3573
0
  }
3574
3575
0
  curproxy->conf.args.file = curproxy->conf.file = copy_file_name(file);
3576
0
  curproxy->conf.args.line = curproxy->conf.line = linenum;
3577
3578
0
  return curproxy;
3579
0
}
3580
3581
/* to be called under the proxy lock after pausing some listeners. This will
3582
 * automatically update the p->flags flag
3583
 */
3584
void proxy_cond_pause(struct proxy *p)
3585
0
{
3586
0
  if (p->li_ready)
3587
0
    return;
3588
0
  p->flags |= PR_FL_PAUSED;
3589
0
}
3590
3591
/* to be called under the proxy lock after resuming some listeners. This will
3592
 * automatically update the p->flags flag
3593
 */
3594
void proxy_cond_resume(struct proxy *p)
3595
0
{
3596
0
  if (!p->li_ready)
3597
0
    return;
3598
0
  p->flags &= ~PR_FL_PAUSED;
3599
0
}
3600
3601
/* to be called under the proxy lock after stopping some listeners. This will
3602
 * automatically update the p->flags flag after stopping the last one, and
3603
 * will emit a log indicating the proxy's condition. The function is idempotent
3604
 * so that it will not emit multiple logs; a proxy will be disabled only once.
3605
 */
3606
void proxy_cond_disable(struct proxy *p)
3607
0
{
3608
0
  long long cum_conn = 0;
3609
0
  long long cum_sess = 0;
3610
3611
0
  if (p->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
3612
0
    return;
3613
3614
0
  if (p->li_ready + p->li_paused > 0)
3615
0
    return;
3616
3617
0
  p->flags |= PR_FL_STOPPED;
3618
3619
  /* Note: syslog proxies use their own loggers so while it's somewhat OK
3620
   * to report them being stopped as a warning, we must not spam their log
3621
   * servers which are in fact production servers. For other types (CLI,
3622
   * peers, etc) we must not report them at all as they're not really on
3623
   * the data plane but on the control plane.
3624
   */
3625
0
  if (!(global.mode & MODE_STARTING)) {
3626
0
    if (p->cap & PR_CAP_FE)
3627
0
      cum_conn = COUNTERS_SHARED_TOTAL(p->fe_counters.shared.tg, cum_conn, HA_ATOMIC_LOAD);
3628
0
    if (p->cap & PR_CAP_BE)
3629
0
      cum_sess = COUNTERS_SHARED_TOTAL(p->be_counters.shared.tg, cum_sess, HA_ATOMIC_LOAD);
3630
0
  }
3631
3632
0
  if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP || p->mode == PR_MODE_SYSLOG || p->mode == PR_MODE_SPOP) && !(p->cap & PR_CAP_INT))
3633
0
    ha_warning("Proxy %s stopped (cumulated conns: FE: %lld, BE: %lld).\n",
3634
0
         p->id, cum_conn, cum_sess);
3635
3636
0
  if ((p->mode == PR_MODE_TCP || p->mode == PR_MODE_HTTP || p->mode == PR_MODE_SPOP) && !(p->cap & PR_CAP_INT))
3637
0
    send_log(p, LOG_WARNING, "Proxy %s stopped (cumulated conns: FE: %lld, BE: %lld).\n",
3638
0
       p->id, cum_conn, cum_sess);
3639
3640
0
  if (p->table && p->table->size && p->table->sync_task)
3641
0
    task_wakeup(p->table->sync_task, TASK_WOKEN_MSG);
3642
3643
0
  if (p->task)
3644
0
    task_wakeup(p->task, TASK_WOKEN_MSG);
3645
0
}
3646
3647
/*
3648
 * This is the proxy management task. It enables proxies when there are enough
3649
 * free streams, or stops them when the table is full. It is designed to be
3650
 * called as a task which is woken up upon stopping or when rate limiting must
3651
 * be enforced.
3652
 */
3653
struct task *manage_proxy(struct task *t, void *context, unsigned int state)
3654
0
{
3655
0
  struct proxy *p = context;
3656
0
  int next = TICK_ETERNITY;
3657
0
  unsigned int wait;
3658
3659
  /* We should periodically try to enable listeners waiting for a
3660
   * global resource here.
3661
   */
3662
3663
  /* If the proxy holds a stick table, we need to purge all unused
3664
   * entries. These are all the ones in the table with ref_cnt == 0
3665
   * and all the ones in the pool used to allocate new entries. Any
3666
   * entry attached to an existing stream waiting for a store will
3667
   * be in neither list. Any entry being dumped will have ref_cnt > 0.
3668
   * However we protect tables that are being synced to peers.
3669
   */
3670
0
  if (unlikely(stopping && (p->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && p->table && p->table->current)) {
3671
3672
0
    if (!p->table->refcnt) {
3673
      /* !table->refcnt means there
3674
       * is no more pending full resync
3675
       * to push to a new process and
3676
       * we are free to flush the table.
3677
       */
3678
0
      int cleaned_up;
3679
3680
      /* We purposely enforce a budget limitation since we don't want
3681
       * to spend too much time purging old entries
3682
       *
3683
       * This is known to cause the watchdog to occasionnaly trigger if
3684
       * the table is huge and all entries become available for purge
3685
       * at the same time
3686
       *
3687
       * Moreover, we must also anticipate the pool_gc() call which
3688
       * will also be much slower if there is too much work at once
3689
       */
3690
0
      cleaned_up = stktable_trash_oldest(p->table);
3691
0
      if (cleaned_up) {
3692
        /* immediately release freed memory since we are stopping */
3693
0
        pool_gc(NULL);
3694
0
        if (cleaned_up) {
3695
          /* it is very likely that there are still trashable
3696
           * entries in the table, reschedule a new cleanup
3697
           * attempt ASAP
3698
           */
3699
0
          t->expire = TICK_ETERNITY;
3700
0
          task_wakeup(t, TASK_WOKEN_RES);
3701
0
          return t;
3702
0
        }
3703
0
      }
3704
0
    }
3705
0
    if (p->table->current) {
3706
      /* some entries still remain but are not yet available
3707
       * for cleanup, let's recheck in one second
3708
       */
3709
0
      next = tick_first(next, tick_add(now_ms, 1000));
3710
0
    }
3711
0
  }
3712
3713
  /* the rest below is just for frontends */
3714
0
  if (!(p->cap & PR_CAP_FE))
3715
0
    goto out;
3716
3717
  /* check the various reasons we may find to block the frontend */
3718
0
  if (unlikely(p->feconn >= p->maxconn))
3719
0
    goto out;
3720
3721
0
  if (p->fe_sps_lim &&
3722
0
      (wait = COUNTERS_SHARED_TOTAL_ARG2(p->fe_counters.shared.tg, sess_per_sec, next_event_delay, p->fe_sps_lim, 0))) {
3723
3724
    /* we're blocking because a limit was reached on the number of
3725
     * requests/s on the frontend. We want to re-check ASAP, which
3726
     * means in 1 ms before estimated expiration date, because the
3727
     * timer will have settled down.
3728
     */
3729
0
    next = tick_first(next, tick_add(now_ms, wait));
3730
0
    goto out;
3731
0
  }
3732
3733
  /* The proxy is not limited so we can re-enable any waiting listener */
3734
0
  dequeue_proxy_listeners(p, 0);
3735
0
 out:
3736
0
  t->expire = next;
3737
0
  task_queue(t);
3738
0
  return t;
3739
0
}
3740
3741
3742
static int proxy_parse_grace(char **args, int section_type, struct proxy *curpx,
3743
                             const struct proxy *defpx, const char *file, int line,
3744
                             char **err)
3745
0
{
3746
0
  const char *res;
3747
3748
0
  if (!*args[1]) {
3749
0
    memprintf(err, "'%s' expects <time> as argument.\n", args[0]);
3750
0
    return -1;
3751
0
  }
3752
0
  res = parse_time_err(args[1], &global.grace_delay, TIME_UNIT_MS);
3753
0
  if (res == PARSE_TIME_OVER) {
3754
0
    memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
3755
0
        args[1], args[0]);
3756
0
    return -1;
3757
0
  }
3758
0
  else if (res == PARSE_TIME_UNDER) {
3759
0
    memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
3760
0
        args[1], args[0]);
3761
0
    return -1;
3762
0
  }
3763
0
  else if (res) {
3764
0
    memprintf(err, "unexpected character '%c' in argument to <%s>.\n", *res, args[0]);
3765
0
    return -1;
3766
0
  }
3767
0
  return 0;
3768
0
}
3769
3770
static int proxy_parse_hard_stop_after(char **args, int section_type, struct proxy *curpx,
3771
                                const struct proxy *defpx, const char *file, int line,
3772
                                char **err)
3773
0
{
3774
0
  const char *res;
3775
3776
0
  if (!*args[1]) {
3777
0
    memprintf(err, "'%s' expects <time> as argument.\n", args[0]);
3778
0
    return -1;
3779
0
  }
3780
0
  res = parse_time_err(args[1], &global.hard_stop_after, TIME_UNIT_MS);
3781
0
  if (res == PARSE_TIME_OVER) {
3782
0
    memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
3783
0
        args[1], args[0]);
3784
0
    return -1;
3785
0
  }
3786
0
  else if (res == PARSE_TIME_UNDER) {
3787
0
    memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
3788
0
        args[1], args[0]);
3789
0
    return -1;
3790
0
  }
3791
0
  else if (res) {
3792
0
    memprintf(err, "unexpected character '%c' in argument to <%s>.\n", *res, args[0]);
3793
0
    return -1;
3794
0
  }
3795
0
  return 0;
3796
0
}
3797
3798
static int proxy_parse_close_spread_time(char **args, int section_type, struct proxy *curpx,
3799
           const struct proxy *defpx, const char *file, int line,
3800
           char **err)
3801
0
{
3802
0
  const char *res;
3803
3804
0
  if (!*args[1]) {
3805
0
    memprintf(err, "'%s' expects <time> as argument.\n", args[0]);
3806
0
    return -1;
3807
0
  }
3808
3809
  /* If close-spread-time is set to "infinite", disable the active connection
3810
   * closing during soft-stop.
3811
   */
3812
0
  if (strcmp(args[1], "infinite") == 0) {
3813
0
    global.tune.options |= GTUNE_DISABLE_ACTIVE_CLOSE;
3814
0
    global.close_spread_time = TICK_ETERNITY;
3815
0
    return 0;
3816
0
  }
3817
3818
0
  res = parse_time_err(args[1], &global.close_spread_time, TIME_UNIT_MS);
3819
0
  if (res == PARSE_TIME_OVER) {
3820
0
    memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
3821
0
        args[1], args[0]);
3822
0
    return -1;
3823
0
  }
3824
0
  else if (res == PARSE_TIME_UNDER) {
3825
0
    memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
3826
0
        args[1], args[0]);
3827
0
    return -1;
3828
0
  }
3829
0
  else if (res) {
3830
0
    memprintf(err, "unexpected character '%c' in argument to <%s>.\n", *res, args[0]);
3831
0
    return -1;
3832
0
  }
3833
0
  global.tune.options &= ~GTUNE_DISABLE_ACTIVE_CLOSE;
3834
3835
0
  return 0;
3836
0
}
3837
3838
struct task *hard_stop(struct task *t, void *context, unsigned int state)
3839
0
{
3840
0
  struct proxy *p;
3841
0
  struct stream *s;
3842
0
  int thr;
3843
3844
0
  if (killed) {
3845
0
    ha_warning("Some tasks resisted to hard-stop, exiting now.\n");
3846
0
    send_log(NULL, LOG_WARNING, "Some tasks resisted to hard-stop, exiting now.\n");
3847
0
    killed = 2;
3848
0
    for (thr = 0; thr < global.nbthread; thr++)
3849
0
      if (_HA_ATOMIC_LOAD(&ha_thread_info[thr].tg->threads_enabled) & ha_thread_info[thr].ltid_bit)
3850
0
        wake_thread(thr);
3851
0
    t->expire = TICK_ETERNITY;
3852
0
    return t;
3853
0
  }
3854
3855
0
  ha_warning("soft-stop running for too long, performing a hard-stop.\n");
3856
0
  send_log(NULL, LOG_WARNING, "soft-stop running for too long, performing a hard-stop.\n");
3857
0
  list_for_each_entry(p, &main_proxies, el) {
3858
0
    if ((p->cap & PR_CAP_FE) && (p->feconn > 0)) {
3859
0
      ha_warning("Proxy %s hard-stopped (%d remaining conns will be closed).\n",
3860
0
           p->id, p->feconn);
3861
0
      send_log(p, LOG_WARNING, "Proxy %s hard-stopped (%d remaining conns will be closed).\n",
3862
0
        p->id, p->feconn);
3863
0
    }
3864
0
  }
3865
3866
0
  thread_isolate();
3867
3868
0
  for (thr = 0; thr < global.nbthread; thr++) {
3869
0
    list_for_each_entry(s, &ha_thread_ctx[thr].streams, list) {
3870
0
      stream_shutdown(s, SF_ERR_KILLED);
3871
0
    }
3872
0
  }
3873
3874
0
  thread_release();
3875
3876
0
  killed = 1;
3877
0
  t->expire = tick_add(now_ms, MS_TO_TICKS(1000));
3878
0
  return t;
3879
0
}
3880
3881
/* perform the soft-stop right now (i.e. unbind listeners) */
3882
static void do_soft_stop_now()
3883
0
{
3884
0
  struct proxy *p;
3885
0
  struct task *task;
3886
3887
  /* disable busy polling to avoid cpu eating for the new process */
3888
0
  global.tune.options &= ~GTUNE_BUSY_POLLING;
3889
3890
0
  if (tick_isset(global.close_spread_time)) {
3891
0
    global.close_spread_end = tick_add(now_ms, global.close_spread_time);
3892
0
  }
3893
3894
  /* schedule a hard-stop after a delay if needed */
3895
0
  if (tick_isset(global.hard_stop_after)) {
3896
0
    task = task_new_anywhere();
3897
0
    if (task) {
3898
0
      task->process = hard_stop;
3899
0
      task_schedule(task, tick_add(now_ms, global.hard_stop_after));
3900
0
    }
3901
0
    else {
3902
0
      ha_alert("out of memory trying to allocate the hard-stop task.\n");
3903
0
    }
3904
0
  }
3905
3906
  /* we isolate so that we have a chance of stopping listeners in other groups */
3907
0
  thread_isolate();
3908
3909
  /* stop all stoppable listeners */
3910
0
  protocol_stop_now();
3911
3912
0
  thread_release();
3913
3914
  /* Loop on proxies to stop backends */
3915
0
  list_for_each_entry(p, &main_proxies, el) {
3916
0
    HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
3917
0
    proxy_cond_disable(p);
3918
0
    HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
3919
0
  }
3920
3921
  /* signal zero is used to broadcast the "stopping" event */
3922
0
  signal_handler(0);
3923
0
}
3924
3925
/* triggered by a soft-stop delayed with `grace` */
3926
static struct task *grace_expired(struct task *t, void *context, unsigned int state)
3927
0
{
3928
0
  ha_notice("Grace period expired, proceeding with soft-stop now.\n");
3929
0
  send_log(NULL, LOG_NOTICE, "Grace period expired, proceeding with soft-stop now.\n");
3930
0
  do_soft_stop_now();
3931
0
  task_destroy(t);
3932
0
  return NULL;
3933
0
}
3934
3935
/*
3936
 * this function disables health-check servers so that the process will quickly be ignored
3937
 * by load balancers.
3938
 */
3939
void soft_stop(void)
3940
0
{
3941
0
  struct task *task;
3942
3943
0
  stopping = 1;
3944
3945
0
  if (tick_isset(global.grace_delay)) {
3946
0
    task = task_new_anywhere();
3947
0
    if (task) {
3948
0
      ha_notice("Scheduling a soft-stop in %u ms.\n", global.grace_delay);
3949
0
      send_log(NULL, LOG_WARNING, "Scheduling a soft-stop in %u ms.\n", global.grace_delay);
3950
0
      task->process = grace_expired;
3951
0
      task_schedule(task, tick_add(now_ms, global.grace_delay));
3952
0
      return;
3953
0
    }
3954
0
    else {
3955
0
      ha_alert("out of memory trying to allocate the stop-stop task, stopping now.\n");
3956
0
    }
3957
0
  }
3958
3959
  /* no grace (or failure to enforce it): stop now */
3960
0
  do_soft_stop_now();
3961
0
}
3962
3963
3964
/* Temporarily disables listening on all of the proxy's listeners. Upon
3965
 * success, the proxy enters the PR_PAUSED state. The function returns 0
3966
 * if it fails, or non-zero on success.
3967
 * The function takes the proxy's lock so it's safe to
3968
 * call from multiple places.
3969
 */
3970
int pause_proxy(struct proxy *p)
3971
0
{
3972
0
  struct listener *l;
3973
3974
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
3975
3976
0
  if (!(p->cap & PR_CAP_FE) || (p->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) || !p->li_ready)
3977
0
    goto end;
3978
3979
0
  list_for_each_entry(l, &p->conf.listeners, by_fe)
3980
0
    suspend_listener(l, 1, 0);
3981
3982
0
  if (p->li_ready && !tg_agents_enabled) {
3983
0
    ha_warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id);
3984
0
    send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id);
3985
0
    HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
3986
0
    return 0;
3987
0
  }
3988
0
end:
3989
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
3990
0
  return 1;
3991
0
}
3992
3993
/*
3994
 * This function completely stops a proxy and releases its listeners. It has
3995
 * to be called when going down in order to release the ports so that another
3996
 * process may bind to them. It must also be called on disabled proxies at the
3997
 * end of start-up. If all listeners are closed, the proxy is set to the
3998
 * PR_STOPPED state.
3999
 * The function takes the proxy's lock so it's safe to
4000
 * call from multiple places.
4001
 */
4002
void stop_proxy(struct proxy *p)
4003
0
{
4004
0
  struct listener *l;
4005
4006
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
4007
4008
0
  list_for_each_entry(l, &p->conf.listeners, by_fe)
4009
0
    stop_listener(l, 1, 0, 0);
4010
4011
0
  if (!(p->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) && !p->li_ready) {
4012
    /* might be just a backend */
4013
0
    p->flags |= PR_FL_STOPPED;
4014
0
  }
4015
4016
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
4017
0
}
4018
4019
/* This function resumes listening on the specified proxy. It scans all of its
4020
 * listeners and tries to enable them all. If any of them fails, the proxy is
4021
 * put back to the paused state. It returns 1 upon success, or zero if an error
4022
 * is encountered.
4023
 * The function takes the proxy's lock so it's safe to
4024
 * call from multiple places.
4025
 */
4026
int resume_proxy(struct proxy *p)
4027
0
{
4028
0
  struct listener *l;
4029
0
  int fail;
4030
4031
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &p->lock);
4032
4033
0
  if ((p->flags & (PR_FL_DISABLED|PR_FL_STOPPED)) || !p->li_paused)
4034
0
    goto end;
4035
4036
0
  fail = 0;
4037
0
  list_for_each_entry(l, &p->conf.listeners, by_fe) {
4038
0
    if (!resume_listener(l, 1, 0)) {
4039
0
      int port;
4040
4041
0
      port = get_host_port(&l->rx.addr);
4042
0
      if (port) {
4043
0
        ha_warning("Port %d busy while trying to enable %s %s.\n",
4044
0
             port, proxy_cap_str(p->cap), p->id);
4045
0
        send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n",
4046
0
           port, proxy_cap_str(p->cap), p->id);
4047
0
      }
4048
0
      else {
4049
0
        ha_warning("Bind on socket %d busy while trying to enable %s %s.\n",
4050
0
             l->luid, proxy_cap_str(p->cap), p->id);
4051
0
        send_log(p, LOG_WARNING, "Bind on socket %d busy while trying to enable %s %s.\n",
4052
0
           l->luid, proxy_cap_str(p->cap), p->id);
4053
0
      }
4054
4055
      /* Another port might have been enabled. Let's stop everything. */
4056
0
      fail = 1;
4057
0
      break;
4058
0
    }
4059
0
  }
4060
4061
0
  if (fail) {
4062
0
    HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
4063
    /* pause_proxy will take PROXY_LOCK */
4064
0
    pause_proxy(p);
4065
0
    return 0;
4066
0
  }
4067
0
end:
4068
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &p->lock);
4069
0
  return 1;
4070
0
}
4071
4072
/* Set current stream's backend to <be>. Nothing is done if the
4073
 * stream already had a backend assigned, which is indicated by
4074
 * s->flags & SF_BE_ASSIGNED.
4075
 * All flags, stats and counters which need be updated are updated.
4076
 * Returns 1 if done, 0 in case of internal error, eg: lack of resource.
4077
 */
4078
int stream_set_backend(struct stream *s, struct proxy *be)
4079
0
{
4080
0
  unsigned int req_ana;
4081
0
  unsigned int beconn;
4082
4083
0
  if (s->flags & SF_BE_ASSIGNED)
4084
0
    return 1;
4085
4086
0
  if (flt_set_stream_backend(s, be) < 0)
4087
0
    return 0;
4088
4089
0
  s->be = be;
4090
0
  if (be->be_counters.shared.tg)
4091
0
    s->be_tgcounters = be->be_counters.shared.tg[tgid - 1];
4092
0
  else
4093
0
    s->be_tgcounters = NULL;
4094
4095
0
  beconn = HA_ATOMIC_ADD_FETCH(&be->beconn, 1);
4096
0
  COUNTERS_UPDATE_MAX(&be->be_counters.conn_max, beconn);
4097
0
  proxy_inc_be_ctr(be);
4098
4099
  /* assign new parameters to the stream from the new backend */
4100
0
  s->scb->flags &= ~SC_FL_INDEP_STR;
4101
0
  if (be->options2 & PR_O2_INDEPSTR)
4102
0
    s->scb->flags |= SC_FL_INDEP_STR;
4103
4104
  /* We want to enable the backend-specific analysers except those which
4105
   * were already run as part of the frontend/listener. Note that it would
4106
   * be more reliable to store the list of analysers that have been run,
4107
   * but what we do here is OK for now.
4108
   */
4109
0
  req_ana = be->be_req_ana;
4110
0
  if (!(strm_fe(s)->options & PR_O_WREQ_BODY) && be->options & PR_O_WREQ_BODY) {
4111
    /* The backend request to parse a request body while it was not
4112
     * performed on the frontend, so add the corresponding analyser
4113
     */
4114
0
    req_ana |= AN_REQ_HTTP_BODY;
4115
0
  }
4116
0
  if (IS_HTX_STRM(s) && strm_fe(s)->mode != PR_MODE_HTTP) {
4117
    /* The stream was already upgraded to HTTP, so remove analysers
4118
     * set during the upgrade
4119
     */
4120
0
    req_ana &= ~(AN_REQ_WAIT_HTTP|AN_REQ_HTTP_PROCESS_FE);
4121
0
  }
4122
0
  s->req.analysers |= req_ana & ~(strm_li(s) ? strm_li(s)->bind_conf->analysers : 0);
4123
4124
0
  if (!IS_HTX_STRM(s) && be->mode == PR_MODE_HTTP) {
4125
    /* If we chain a TCP frontend to an HTX backend, we must upgrade
4126
     * the client mux */
4127
0
    if (!stream_set_http_mode(s, NULL))
4128
0
      return 0;
4129
0
  }
4130
0
  else if (IS_HTX_STRM(s) && be->mode != PR_MODE_HTTP) {
4131
    /* If a TCP backend is assgiend to an HTX stream, return an
4132
     * error. It may happens for a new stream on a previously
4133
     * upgraded connections. */
4134
0
    if (!(s->flags & SF_ERR_MASK))
4135
0
      s->flags |= SF_ERR_INTERNAL;
4136
0
    return 0;
4137
0
  }
4138
0
  else {
4139
    /* If the target backend requires HTTP processing, we have to allocate
4140
     * the HTTP transaction if we did not have one.
4141
     */
4142
0
    if (unlikely(!s->txn.http && be->http_needed && !http_create_txn(s)))
4143
0
      return 0;
4144
0
  }
4145
4146
0
  s->flags |= SF_BE_ASSIGNED;
4147
0
  if (be->options2 & PR_O2_NODELAY) {
4148
0
    s->scf->flags |= SC_FL_SND_NEVERWAIT;
4149
0
    s->scb->flags |= SC_FL_SND_NEVERWAIT;
4150
0
  }
4151
4152
0
  return 1;
4153
0
}
4154
4155
/* Capture a bad request or response and archive it in the proxy's structure.
4156
 * It is relatively protocol-agnostic so it requires that a number of elements
4157
 * are passed :
4158
 *  - <proxy> is the proxy where the error was detected and where the snapshot
4159
 *    needs to be stored
4160
 *  - <is_back> indicates that the error happened when receiving the response
4161
 *  - <other_end> is a pointer to the proxy on the other side when known
4162
 *  - <target> is the target of the connection, usually a server or a proxy
4163
 *  - <sess> is the session which experienced the error
4164
 *  - <ctx> may be NULL or should contain any info relevant to the protocol
4165
 *  - <buf> is the buffer containing the offending data
4166
 *  - <buf_ofs> is the position of this buffer's input data in the input
4167
 *    stream, starting at zero. It may be passed as zero if unknown.
4168
 *  - <buf_out> is the portion of <buf->data> which was already forwarded and
4169
 *    which precedes the buffer's input. The buffer's input starts at
4170
 *    buf->head + buf_out.
4171
 *  - <err_pos> is the pointer to the faulty byte in the buffer's input.
4172
 *  - <show> is the callback to use to display <ctx>. It may be NULL.
4173
 */
4174
void proxy_capture_error(struct proxy *proxy, int is_back,
4175
       struct proxy *other_end, enum obj_type *target,
4176
       const struct session *sess,
4177
       const struct buffer *buf, long buf_ofs,
4178
       unsigned int buf_out, unsigned int err_pos,
4179
       const union error_snapshot_ctx *ctx,
4180
       void (*show)(struct buffer *, const struct error_snapshot *))
4181
0
{
4182
0
  struct error_snapshot *es;
4183
0
  unsigned int buf_len;
4184
0
  int len1, len2;
4185
0
  unsigned int ev_id;
4186
4187
0
  ev_id = HA_ATOMIC_FETCH_ADD(&error_snapshot_id, 1);
4188
4189
0
  buf_len = b_data(buf) - buf_out;
4190
4191
0
  es = malloc(sizeof(*es) + buf_len);
4192
0
  if (!es)
4193
0
    return;
4194
4195
0
  es->buf_size = buf->size;
4196
0
  es->buf_len = buf_len;
4197
0
  es->ev_id   = ev_id;
4198
4199
0
  len1 = b_size(buf) - b_peek_ofs(buf, buf_out);
4200
0
  if (len1 > buf_len)
4201
0
    len1 = buf_len;
4202
4203
0
  if (len1) {
4204
0
    memcpy(es->buf, b_peek(buf, buf_out), len1);
4205
0
    len2 = buf_len - len1;
4206
0
    if (len2)
4207
0
      memcpy(es->buf + len1, b_orig(buf), len2);
4208
0
  }
4209
4210
0
  es->buf_err = err_pos;
4211
0
  es->when    = date; // user-visible date
4212
0
  es->srv     = objt_server(target);
4213
0
  es->oe      = other_end;
4214
0
  if (sess && objt_conn(sess->origin) && conn_get_src(__objt_conn(sess->origin)))
4215
0
    es->src  = *__objt_conn(sess->origin)->src;
4216
0
  else
4217
0
    memset(&es->src, 0, sizeof(es->src));
4218
4219
0
  es->buf_wrap = b_wrap(buf) - b_peek(buf, buf_out);
4220
0
  es->buf_out  = buf_out;
4221
0
  es->buf_ofs  = buf_ofs;
4222
4223
  /* be sure to indicate the offset of the first IN byte */
4224
0
  if (es->buf_ofs >= es->buf_len)
4225
0
    es->buf_ofs -= es->buf_len;
4226
0
  else
4227
0
    es->buf_ofs = 0;
4228
4229
  /* protocol-specific part now */
4230
0
  if (ctx)
4231
0
    es->ctx = *ctx;
4232
0
  else
4233
0
    memset(&es->ctx, 0, sizeof(es->ctx));
4234
0
  es->show = show;
4235
4236
  /* note: we still lock since we have to be certain that nobody is
4237
   * dumping the output while we free.
4238
   */
4239
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &proxy->lock);
4240
0
  if (is_back) {
4241
0
    es = HA_ATOMIC_XCHG(&proxy->invalid_rep, es);
4242
0
  } else {
4243
0
    es = HA_ATOMIC_XCHG(&proxy->invalid_req, es);
4244
0
  }
4245
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &proxy->lock);
4246
0
  ha_free(&es);
4247
0
}
4248
4249
/* Configure all proxies which lack a maxconn setting to use the global one by
4250
 * default. This avoids the common mistake consisting in setting maxconn only
4251
 * in the global section and discovering the hard way that it doesn't propagate
4252
 * through the frontends. These values are also propagated through the various
4253
 * targeted backends, whose fullconn is finally calculated if not yet set.
4254
 */
4255
void proxy_adjust_all_maxconn()
4256
0
{
4257
0
  struct proxy *curproxy;
4258
0
  struct switching_rule *swrule1, *swrule2;
4259
4260
0
  list_for_each_entry(curproxy, &main_proxies, el) {
4261
0
    if (curproxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
4262
0
      continue;
4263
4264
0
    if (!(curproxy->cap & PR_CAP_FE))
4265
0
      continue;
4266
4267
0
    if (!curproxy->maxconn)
4268
0
      curproxy->maxconn = global.maxconn;
4269
4270
    /* update the target backend's fullconn count : default_backend */
4271
0
    if (curproxy->defbe.be)
4272
0
      curproxy->defbe.be->tot_fe_maxconn += curproxy->maxconn;
4273
0
    else if ((curproxy->cap & PR_CAP_LISTEN) == PR_CAP_LISTEN)
4274
0
      curproxy->tot_fe_maxconn += curproxy->maxconn;
4275
4276
0
    list_for_each_entry(swrule1, &curproxy->switching_rules, list) {
4277
      /* For each target of switching rules, we update their
4278
       * tot_fe_maxconn, except if a previous rule points to
4279
       * the same backend or to the default backend.
4280
       */
4281
0
      if (swrule1->be.backend != curproxy->defbe.be) {
4282
        /* note: swrule1->be.backend isn't a backend if the rule
4283
         * is dynamic, it's an expression instead, so it must not
4284
         * be dereferenced as a backend before being certain it is.
4285
         */
4286
0
        list_for_each_entry(swrule2, &curproxy->switching_rules, list) {
4287
0
          if (swrule2 == swrule1) {
4288
0
            if (!swrule1->dynamic)
4289
0
              swrule1->be.backend->tot_fe_maxconn += curproxy->maxconn;
4290
0
            break;
4291
0
          }
4292
0
          else if (!swrule2->dynamic && swrule2->be.backend == swrule1->be.backend) {
4293
            /* there are multiple refs of this backend */
4294
0
            break;
4295
0
          }
4296
0
        }
4297
0
      }
4298
0
    }
4299
0
  }
4300
4301
  /* automatically compute fullconn if not set. We must not do it in the
4302
   * loop above because cross-references are not yet fully resolved.
4303
   */
4304
0
  list_for_each_entry(curproxy, &main_proxies, el) {
4305
0
    if (curproxy->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
4306
0
      continue;
4307
4308
    /* If <fullconn> is not set, let's set it to 10% of the sum of
4309
     * the possible incoming frontend's maxconns.
4310
     */
4311
0
    if (!curproxy->fullconn && (curproxy->cap & PR_CAP_BE)) {
4312
      /* we have the sum of the maxconns in <total>. We only
4313
       * keep 10% of that sum to set the default fullconn, with
4314
       * a hard minimum of 1 (to avoid a divide by zero).
4315
       */
4316
0
      curproxy->fullconn = (curproxy->tot_fe_maxconn + 9) / 10;
4317
0
      if (!curproxy->fullconn)
4318
0
        curproxy->fullconn = 1;
4319
0
    }
4320
0
  }
4321
0
}
4322
4323
/* releases what's no longer needed after a proxy section covering <curproxy>.
4324
 * Returns an error code made of ERR_*, or 0 on success.
4325
 */
4326
static int post_section_px_cleanup()
4327
0
{
4328
0
  if (!curproxy)
4329
0
    return 0; // nothing to do
4330
4331
  /* Perform clean up of empty default-server in proxies. This is not
4332
   * executed for defaults section as this may still be useful.
4333
   */
4334
0
  if ((curproxy->cap & PR_CAP_LISTEN) && !(curproxy->cap & PR_CAP_DEF)) {
4335
    /* Unnamed default-server is removed if it does not define specific setting. */
4336
0
    if (curproxy->defsrv && !(curproxy->defsrv->flags & SRV_F_UMODIFIED)) {
4337
0
      srv_free_params(curproxy->defsrv);
4338
0
      srv_free(&curproxy->defsrv);
4339
0
    }
4340
0
  }
4341
0
  return 0;
4342
0
}
4343
4344
REGISTER_CONFIG_POST_SECTION("frontend", post_section_px_cleanup);
4345
REGISTER_CONFIG_POST_SECTION("backend",  post_section_px_cleanup);
4346
REGISTER_CONFIG_POST_SECTION("listen",   post_section_px_cleanup);
4347
REGISTER_CONFIG_POST_SECTION("defaults", post_section_px_cleanup);
4348
4349
/* Config keywords below */
4350
4351
static struct cfg_kw_list cfg_kws = {ILH, {
4352
  { CFG_GLOBAL, "grace", proxy_parse_grace },
4353
  { CFG_GLOBAL, "hard-stop-after", proxy_parse_hard_stop_after },
4354
  { CFG_GLOBAL, "close-spread-time", proxy_parse_close_spread_time },
4355
  { CFG_LISTEN, "timeout", proxy_parse_timeout },
4356
  { CFG_LISTEN, "clitimeout", proxy_parse_timeout }, /* This keyword actually fails to parse, this line remains for better error messages. */
4357
  { CFG_LISTEN, "contimeout", proxy_parse_timeout }, /* This keyword actually fails to parse, this line remains for better error messages. */
4358
  { CFG_LISTEN, "srvtimeout", proxy_parse_timeout }, /* This keyword actually fails to parse, this line remains for better error messages. */
4359
  { CFG_LISTEN, "rate-limit", proxy_parse_rate_limit },
4360
  { CFG_LISTEN, "max-keep-alive-queue", proxy_parse_max_ka_queue },
4361
  { CFG_LISTEN, "declare", proxy_parse_declare },
4362
  { CFG_LISTEN, "retry-on", proxy_parse_retry_on },
4363
  { CFG_LISTEN, "hash-preserve-affinity", proxy_parse_hash_preserve_affinity },
4364
#ifdef TCP_KEEPCNT
4365
  { CFG_LISTEN, "clitcpka-cnt", proxy_parse_tcpka_cnt },
4366
  { CFG_LISTEN, "srvtcpka-cnt", proxy_parse_tcpka_cnt },
4367
#endif
4368
#ifdef TCP_KEEPIDLE
4369
  { CFG_LISTEN, "clitcpka-idle", proxy_parse_tcpka_idle },
4370
  { CFG_LISTEN, "srvtcpka-idle", proxy_parse_tcpka_idle },
4371
#endif
4372
#ifdef TCP_KEEPINTVL
4373
  { CFG_LISTEN, "clitcpka-intvl", proxy_parse_tcpka_intvl },
4374
  { CFG_LISTEN, "srvtcpka-intvl", proxy_parse_tcpka_intvl },
4375
#endif
4376
  { CFG_LISTEN, "be-unpublished", proxy_parse_be_unpublished },
4377
  { CFG_LISTEN, "force-be-switch", proxy_parse_force_be_switch },
4378
  { CFG_LISTEN, "guid", proxy_parse_guid },
4379
  { 0, NULL, NULL },
4380
}};
4381
4382
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
4383
4384
/* Expects to find a frontend named <arg> and returns it, otherwise displays various
4385
 * adequate error messages and returns NULL. This function is designed to be used by
4386
 * functions requiring a frontend on the CLI.
4387
 */
4388
struct proxy *cli_find_frontend(struct appctx *appctx, const char *arg)
4389
0
{
4390
0
  struct proxy *px;
4391
4392
0
  if (!*arg) {
4393
0
    cli_err(appctx, "A frontend name is expected.\n");
4394
0
    return NULL;
4395
0
  }
4396
4397
0
  px = proxy_fe_by_name(arg);
4398
0
  if (!px) {
4399
0
    cli_err(appctx, "No such frontend.\n");
4400
0
    return NULL;
4401
0
  }
4402
0
  return px;
4403
0
}
4404
4405
/* Expects to find a backend named <arg> and returns it, otherwise displays various
4406
 * adequate error messages and returns NULL. This function is designed to be used by
4407
 * functions requiring a frontend on the CLI.
4408
 */
4409
struct proxy *cli_find_backend(struct appctx *appctx, const char *arg)
4410
0
{
4411
0
  struct proxy *px;
4412
4413
0
  if (!*arg) {
4414
0
    cli_err(appctx, "A backend name is expected.\n");
4415
0
    return NULL;
4416
0
  }
4417
4418
0
  px = proxy_be_by_name(arg);
4419
0
  if (!px) {
4420
0
    cli_err(appctx, "No such backend.\n");
4421
0
    return NULL;
4422
0
  }
4423
0
  return px;
4424
0
}
4425
4426
/* Parser for "show default-server [<backend>] command.
4427
 * Returns 0 unless a requested backend is unknown.
4428
 */
4429
static int cli_parse_show_default_server(char **args, char *payload, struct appctx *appctx, void *private)
4430
0
{
4431
0
  struct show_be_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
4432
4433
  /* Watch proxies list as backends may be deleted during iteration. No
4434
   * need to watch for servers as default-server instances cannot be
4435
   * removed.
4436
   */
4437
0
  watcher_init(&ctx->px_watch, &ctx->px, offsetof(struct proxy, watcher_list));
4438
4439
  /* check if a backend name has been provided */
4440
0
  if (*args[2]) {
4441
0
    ctx->px = proxy_be_by_name(args[2]);
4442
0
    if (!ctx->px)
4443
0
      return cli_err(appctx, "Can't find backend.\n");
4444
0
  }
4445
0
  else {
4446
    /* Only attach the watcher if full iteration is requested. */
4447
0
    watcher_attach(&ctx->px_watch, main_proxies_first());
4448
0
  }
4449
4450
0
  return 0;
4451
0
}
4452
4453
/* Handler for "show default-server [<backend>] command.
4454
 * Returns 1 on completion or 0 to yield due to output blocked.
4455
 */
4456
static int cli_io_handler_show_default_server(struct appctx *appctx)
4457
0
{
4458
0
  struct show_be_ctx *ctx = appctx->svcctx;
4459
0
  struct server *defsrv;
4460
0
  int prefix;
4461
4462
0
  for (; ctx->px; watcher_next(&ctx->px_watch, main_proxies_next(ctx->px))) {
4463
0
    chunk_reset(&trash);
4464
0
    prefix = 1;
4465
4466
    /* servers are only in backends */
4467
0
    if ((ctx->px->cap & PR_CAP_BE) && !(ctx->px->cap & PR_CAP_INT)) {
4468
      /* Dump unnamed default-server if allocated. */
4469
0
      if (ctx->px->defsrv) {
4470
0
        chunk_appendf(&trash, "* %s\n", ctx->px->id);
4471
0
        prefix = 0;
4472
0
      }
4473
4474
      /* Dump named default-server instances. */
4475
0
      for (defsrv = cebuis_item_first(&ctx->px->defsrv_by_name, conf.name_node, id, struct server);
4476
0
           defsrv; defsrv = cebuis_item_next(&ctx->px->defsrv_by_name, conf.name_node, id, defsrv)) {
4477
0
        chunk_appendf(&trash, "%s %s/%s\n",
4478
0
                      prefix ? "*" : " ", ctx->px->id, defsrv->id);
4479
0
        prefix = 0;
4480
0
      }
4481
4482
0
      if (STRESS_RUN1(applet_putchk_stress(appctx, &trash) == -1,
4483
0
                      applet_putchk(appctx, &trash) == -1)) {
4484
0
        return 0;
4485
0
      }
4486
0
    }
4487
4488
    /* Watcher is not attached if a specific backend has been requested. */
4489
0
    if (!watcher_is_attached(&ctx->px_watch))
4490
0
      break;
4491
0
  }
4492
4493
0
  return 1;
4494
0
}
4495
4496
/* release handler for "show default-server" */
4497
static void cli_io_release_show_default_server(struct appctx *appctx)
4498
0
{
4499
0
  struct show_be_ctx *ctx = appctx->svcctx;
4500
0
  watcher_detach(&ctx->px_watch);
4501
0
}
4502
4503
/* Handler for "show defaults" command. */
4504
static int cli_io_handler_show_defaults(struct appctx *appctx)
4505
0
{
4506
0
  struct show_be_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
4507
4508
0
  if (!ctx->px) {
4509
    /* No need to use ctx <px_watch> as defaults proxies cannot be removed at runtime. */
4510
0
    ctx->px = !LIST_ISEMPTY(&defaults_list) ?
4511
0
      LIST_ELEM(defaults_list.n, struct proxy *, el) : NULL;
4512
0
  }
4513
4514
0
  while (ctx->px) {
4515
0
    chunk_reset(&trash);
4516
0
    chunk_appendf(&trash, "%s\n", ctx->px->id);
4517
4518
0
    if (STRESS_RUN1(applet_putchk_stress(appctx, &trash) == -1,
4519
0
                    applet_putchk(appctx, &trash) == -1)) {
4520
0
      return 0;
4521
0
    }
4522
4523
0
    if (ctx->px->el.n == &defaults_list)
4524
0
      break;
4525
0
    ctx->px = LIST_ELEM(ctx->px->el.n, struct proxy *, el);
4526
0
  }
4527
4528
0
  return 1;
4529
0
}
4530
4531
/* parse a "show servers [state|conn]" CLI line, returns 0 if it wants to start
4532
 * the dump or 1 if it stops immediately. If an argument is specified, it will
4533
 * reserve a show_srv_ctx context and set the proxy pointer into ->px, its ID
4534
 * into ->only_pxid, and ->show_conn to 0 for "state", or 1 for "conn".
4535
 */
4536
static int cli_parse_show_servers(char **args, char *payload, struct appctx *appctx, void *private)
4537
0
{
4538
0
  struct show_srv_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
4539
0
  struct proxy *px;
4540
4541
0
  ctx->show_conn = *args[2] == 'c'; // "conn" vs "state"
4542
4543
0
  watcher_init(&ctx->px_watch,  &ctx->px, offsetof(struct proxy,  watcher_list));
4544
0
  watcher_init(&ctx->srv_watch, &ctx->sv, offsetof(struct server, watcher_list));
4545
4546
  /* check if a backend name has been provided */
4547
0
  if (*args[3]) {
4548
    /* read server state from local file */
4549
0
    px = proxy_be_by_name(args[3]);
4550
4551
0
    if (!px)
4552
0
      return cli_err(appctx, "Can't find backend.\n");
4553
4554
0
    watcher_attach(&ctx->px_watch, px);
4555
0
    ctx->only_pxid = px->uuid;
4556
0
  }
4557
0
  return 0;
4558
0
}
4559
4560
/* helper to dump server addr */
4561
static void dump_server_addr(const struct sockaddr_storage *addr, char *addr_str)
4562
0
{
4563
0
  addr_str[0] = '\0';
4564
0
  switch (addr->ss_family) {
4565
0
    case AF_INET:
4566
0
    case AF_INET6:
4567
0
      addr_to_str(addr, addr_str, INET6_ADDRSTRLEN + 1);
4568
0
      break;
4569
0
    default:
4570
0
      memcpy(addr_str, "-\0", 2);
4571
0
      break;
4572
0
  }
4573
0
}
4574
4575
/* dumps server state information for all the servers found in backend cli.p0.
4576
 * These information are all the parameters which may change during HAProxy runtime.
4577
 * By default, we only export to the last known server state file format. These
4578
 * information can be used at next startup to recover same level of server
4579
 * state. It takes its context from show_srv_ctx, with the proxy pointer from
4580
 * ->px, the proxy's id ->only_pxid, the server's pointer from ->sv, and the
4581
 * choice of what to dump from ->show_conn.
4582
 */
4583
static int dump_servers_state(struct appctx *appctx)
4584
0
{
4585
0
  struct show_srv_ctx *ctx = appctx->svcctx;
4586
0
  struct proxy *px = ctx->px;
4587
0
  struct server *srv;
4588
0
  char srv_addr[INET6_ADDRSTRLEN + 1];
4589
0
  char srv_agent_addr[INET6_ADDRSTRLEN + 1];
4590
0
  char srv_check_addr[INET6_ADDRSTRLEN + 1];
4591
0
  time_t srv_time_since_last_change;
4592
0
  int bk_f_forced_id, srv_f_forced_id;
4593
0
  char *srvrecord;
4594
4595
0
  if (!ctx->sv)
4596
0
    watcher_attach(&ctx->srv_watch, proxy_first_server(px));
4597
4598
0
  for (; ctx->sv; watcher_next(&ctx->srv_watch, proxy_next_server(ctx->sv))) {
4599
0
    srv = ctx->sv;
4600
4601
0
    dump_server_addr(&srv->addr, srv_addr);
4602
0
    dump_server_addr(&srv->check.addr, srv_check_addr);
4603
0
    dump_server_addr(&srv->agent.addr, srv_agent_addr);
4604
4605
0
    srv_time_since_last_change = ns_to_sec(now_ns) - srv->last_change;
4606
0
    bk_f_forced_id = px->options & PR_O_FORCED_ID ? 1 : 0;
4607
0
    srv_f_forced_id = srv->flags & SRV_F_FORCED_ID ? 1 : 0;
4608
4609
0
    srvrecord = NULL;
4610
0
    if (srv->srvrq && srv->srvrq->name)
4611
0
      srvrecord = srv->srvrq->name;
4612
4613
0
    if (ctx->show_conn == 0) {
4614
      /* show servers state */
4615
0
      chunk_printf(&trash,
4616
0
                   "%d %s "
4617
0
                   "%d %s %s "
4618
0
                   "%d %d %d %d %ld "
4619
0
                   "%d %d %d %d %d "
4620
0
                   "%d %d %s %u "
4621
0
             "%s %d %d "
4622
0
             "%s %s %d"
4623
0
                   "\n",
4624
0
                   px->uuid, HA_ANON_CLI(px->id),
4625
0
                   srv->puid, HA_ANON_CLI(srv->id),
4626
0
             hash_ipanon(appctx->cli_ctx.anon_key, srv_addr, 0),
4627
0
                   srv->cur_state, srv->cur_admin, srv->uweight, srv->iweight,
4628
0
             (long int)srv_time_since_last_change,
4629
0
                   srv->check.status, srv->check.result, srv->check.health,
4630
0
             srv->check.state & 0x0F, srv->agent.state & 0x1F,
4631
0
                   bk_f_forced_id, srv_f_forced_id,
4632
0
             srv->hostname ? HA_ANON_CLI(srv->hostname) : "-", srv->svc_port,
4633
0
                   srvrecord ? srvrecord : "-", srv->use_ssl, srv->check.port,
4634
0
             srv_check_addr, srv_agent_addr, srv->agent.port);
4635
0
    } else {
4636
      /* show servers conn */
4637
0
      int thr;
4638
4639
0
      chunk_printf(&trash,
4640
0
                   "%s/%s %d/%d %s %u - %u %u %u %u %u %u %u %u %d %u",
4641
0
                   HA_ANON_CLI(px->id), HA_ANON_CLI(srv->id),
4642
0
                   px->uuid, srv->puid, hash_ipanon(appctx->cli_ctx.anon_key, srv_addr, 0),
4643
0
                   srv->svc_port, srv->pool_purge_delay,
4644
0
                   srv->served,
4645
0
                   srv->curr_used_conns, srv->max_used_conns, srv->est_need_conns,
4646
0
                   srv->curr_sess_idle_conns,
4647
0
                   srv->curr_idle_nb, srv->curr_safe_nb, (int)srv->max_idle_conns, srv->curr_idle_conns);
4648
4649
0
      for (thr = 0; thr < global.nbthread && srv->curr_idle_thr; thr++)
4650
0
        chunk_appendf(&trash, " %u", srv->curr_idle_thr[thr]);
4651
4652
0
      chunk_appendf(&trash, "\n");
4653
0
    }
4654
4655
0
    if (STRESS_RUN1(applet_putchk_stress(appctx, &trash) == -1,
4656
0
                    applet_putchk(appctx, &trash) == -1)) {
4657
0
      return 0;
4658
0
    }
4659
0
  }
4660
0
  return 1;
4661
0
}
4662
4663
/* Parses backend list or simply use backend name provided by the user to return
4664
 * states of servers to stdout. It takes its context from show_srv_ctx and dumps
4665
 * proxy ->px and stops if ->only_pxid is non-null.
4666
 */
4667
static int cli_io_handler_servers_state(struct appctx *appctx)
4668
0
{
4669
0
  struct show_srv_ctx *ctx = appctx->svcctx;
4670
0
  struct proxy *curproxy;
4671
4672
0
  if (ctx->state == SHOW_SRV_HEAD) {
4673
0
    if (ctx->show_conn == 0)
4674
0
      chunk_printf(&trash, "%d\n# %s\n", SRV_STATE_FILE_VERSION, SRV_STATE_FILE_FIELD_NAMES);
4675
0
    else
4676
0
      chunk_printf(&trash,
4677
0
                   "# bkname/svname bkid/svid addr port - purge_delay served used_cur used_max need_est idle_sess unsafe_nb safe_nb idle_lim idle_cur idle_per_thr[%d]\n",
4678
0
                   global.nbthread);
4679
4680
0
    if (applet_putchk(appctx, &trash) == -1)
4681
0
      return 0;
4682
4683
0
    ctx->state = SHOW_SRV_LIST;
4684
4685
0
    if (!ctx->px)
4686
0
      watcher_attach(&ctx->px_watch, main_proxies_first());
4687
0
  }
4688
4689
0
  for (; ctx->px; watcher_next(&ctx->px_watch, main_proxies_next(ctx->px))) {
4690
0
    curproxy = ctx->px;
4691
    /* servers are only in backends */
4692
0
    if ((curproxy->cap & PR_CAP_BE) && !(curproxy->cap & PR_CAP_INT)) {
4693
0
      if (!dump_servers_state(appctx))
4694
0
        return 0;
4695
0
    }
4696
    /* only the selected proxy is dumped */
4697
0
    if (ctx->only_pxid) {
4698
0
      watcher_detach(&ctx->px_watch);
4699
0
      break;
4700
0
    }
4701
0
  }
4702
4703
0
  return 1;
4704
0
}
4705
4706
/* release handler for "show servers conn|state" */
4707
static void cli_io_release_show_servers(struct appctx *appctx)
4708
0
{
4709
0
  struct show_srv_ctx *ctx = appctx->svcctx;
4710
0
  watcher_detach(&ctx->px_watch);
4711
0
  watcher_detach(&ctx->srv_watch);
4712
0
}
4713
4714
/* Parses backend list and simply report backend names. It keeps the proxy
4715
 * pointer in svcctx since there's nothing else to store there.
4716
 */
4717
static int cli_io_handler_show_backend(struct appctx *appctx)
4718
0
{
4719
0
  struct show_be_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
4720
0
  struct proxy *curproxy;
4721
4722
0
  chunk_reset(&trash);
4723
4724
0
  if (!ctx->px) {
4725
0
    chunk_printf(&trash, "# name\n");
4726
0
    if (applet_putchk(appctx, &trash) == -1)
4727
0
      return 0;
4728
4729
0
    watcher_init(&ctx->px_watch, &ctx->px, offsetof(struct proxy, watcher_list));
4730
    /* This will automatically update ctx->px pointer. */
4731
0
    watcher_attach(&ctx->px_watch, main_proxies_first());
4732
0
  }
4733
4734
0
  for (; ctx->px; watcher_next(&ctx->px_watch, main_proxies_next(ctx->px))) {
4735
0
    curproxy = ctx->px;
4736
4737
    /* looking for non-internal backends only */
4738
0
    if ((curproxy->cap & (PR_CAP_BE|PR_CAP_INT)) != PR_CAP_BE)
4739
0
      continue;
4740
4741
0
    chunk_appendf(&trash, "%s\n", curproxy->id);
4742
0
    if (STRESS_RUN1(applet_putchk_stress(appctx, &trash) == -1,
4743
0
                    applet_putchk(appctx, &trash) == -1)) {
4744
0
      return 0;
4745
0
    }
4746
0
  }
4747
4748
0
  return 1;
4749
0
}
4750
4751
/* release handler for "show backend" */
4752
static void cli_io_release_show_backend(struct appctx *appctx)
4753
0
{
4754
0
  struct show_be_ctx *ctx = appctx->svcctx;
4755
0
  if (ctx->px)
4756
0
    watcher_detach(&ctx->px_watch);
4757
0
}
4758
4759
/* Parses the "enable dynamic-cookies backend" directive, it always returns 1.
4760
 *
4761
 * Grabs the proxy lock and each server's lock.
4762
 */
4763
static int cli_parse_enable_dyncookie_backend(char **args, char *payload, struct appctx *appctx, void *private)
4764
0
{
4765
0
  struct proxy *px;
4766
0
  struct server *s;
4767
4768
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4769
0
    return 1;
4770
4771
0
  px = cli_find_backend(appctx, args[3]);
4772
0
  if (!px)
4773
0
    return 1;
4774
4775
0
  if (px->mode != PR_MODE_TCP && px->mode != PR_MODE_HTTP)
4776
0
    return cli_err(appctx, "Not available.\n");
4777
4778
  /* Note: this lock is to make sure this doesn't change while another
4779
   * thread is in srv_set_dyncookie().
4780
   */
4781
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
4782
0
  px->ck_opts |= PR_CK_DYNAMIC;
4783
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock);
4784
4785
0
  list_for_each_entry(s, &px->servers, el_px) {
4786
0
    HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
4787
0
    srv_set_dyncookie(s);
4788
0
    HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
4789
0
  }
4790
4791
0
  return 1;
4792
0
}
4793
4794
/* Parses the "disable dynamic-cookies backend" directive, it always returns 1.
4795
 *
4796
 * Grabs the proxy lock and each server's lock.
4797
 */
4798
static int cli_parse_disable_dyncookie_backend(char **args, char *payload, struct appctx *appctx, void *private)
4799
0
{
4800
0
  struct proxy *px;
4801
0
  struct server *s;
4802
4803
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4804
0
    return 1;
4805
4806
0
  px = cli_find_backend(appctx, args[3]);
4807
0
  if (!px)
4808
0
    return 1;
4809
4810
0
  if (px->mode != PR_MODE_TCP && px->mode != PR_MODE_HTTP)
4811
0
    return cli_err(appctx, "Not available.\n");
4812
4813
  /* Note: this lock is to make sure this doesn't change while another
4814
   * thread is in srv_set_dyncookie().
4815
   */
4816
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
4817
0
  px->ck_opts &= ~PR_CK_DYNAMIC;
4818
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock);
4819
4820
0
  list_for_each_entry(s, &px->servers, el_px) {
4821
0
    HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
4822
0
    if (!(s->flags & SRV_F_COOKIESET))
4823
0
      ha_free(&s->cookie);
4824
0
    HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
4825
0
  }
4826
4827
0
  return 1;
4828
0
}
4829
4830
/* Parses the "set dynamic-cookie-key backend" directive, it always returns 1.
4831
 *
4832
 * Grabs the proxy lock and each server's lock.
4833
 */
4834
static int cli_parse_set_dyncookie_key_backend(char **args, char *payload, struct appctx *appctx, void *private)
4835
0
{
4836
0
  struct proxy *px;
4837
0
  struct server *s;
4838
0
  char *newkey;
4839
4840
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4841
0
    return 1;
4842
4843
0
  px = cli_find_backend(appctx, args[3]);
4844
0
  if (!px)
4845
0
    return 1;
4846
4847
0
  if (px->mode != PR_MODE_TCP && px->mode != PR_MODE_HTTP)
4848
0
    return cli_err(appctx, "Not available.\n");
4849
4850
0
  if (!*args[4])
4851
0
    return cli_err(appctx, "String value expected.\n");
4852
4853
0
  newkey = strdup(args[4]);
4854
0
  if (!newkey)
4855
0
    return cli_err(appctx, "Failed to allocate memory.\n");
4856
4857
  /* Note: this lock is to make sure this doesn't change while another
4858
   * thread is in srv_set_dyncookie().
4859
   */
4860
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
4861
0
  free(px->dyncookie_key);
4862
0
  px->dyncookie_key = newkey;
4863
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock);
4864
4865
0
  list_for_each_entry(s, &px->servers, el_px) {
4866
0
    HA_SPIN_LOCK(SERVER_LOCK, &s->lock);
4867
0
    srv_set_dyncookie(s);
4868
0
    HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock);
4869
0
  }
4870
4871
0
  return 1;
4872
0
}
4873
4874
/* Parses the "set maxconn frontend" directive, it always returns 1.
4875
 *
4876
 * Grabs the proxy lock.
4877
 */
4878
static int cli_parse_set_maxconn_frontend(char **args, char *payload, struct appctx *appctx, void *private)
4879
0
{
4880
0
  struct proxy *px;
4881
0
  struct listener *l;
4882
0
  int v;
4883
4884
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4885
0
    return 1;
4886
4887
0
  px = cli_find_frontend(appctx, args[3]);
4888
0
  if (!px)
4889
0
    return 1;
4890
4891
0
  if (!*args[4])
4892
0
    return cli_err(appctx, "Integer value expected.\n");
4893
4894
0
  v = atoi(args[4]);
4895
0
  if (v < 0)
4896
0
    return cli_err(appctx, "Value out of range.\n");
4897
4898
  /* OK, the value is fine, so we assign it to the proxy and to all of
4899
   * its listeners. The blocked ones will be dequeued.
4900
   */
4901
0
  HA_RWLOCK_WRLOCK(PROXY_LOCK, &px->lock);
4902
4903
0
  px->maxconn = v;
4904
0
  list_for_each_entry(l, &px->conf.listeners, by_fe) {
4905
0
    if (l->state == LI_FULL)
4906
0
      relax_listener(l, 1, 0);
4907
0
  }
4908
4909
0
  if (px->maxconn > px->feconn)
4910
0
    dequeue_proxy_listeners(px, 1);
4911
4912
0
  HA_RWLOCK_WRUNLOCK(PROXY_LOCK, &px->lock);
4913
4914
0
  return 1;
4915
0
}
4916
4917
/* Parses the "shutdown frontend" directive, it always returns 1.
4918
 *
4919
 * Grabs the proxy lock.
4920
 */
4921
static int cli_parse_shutdown_frontend(char **args, char *payload, struct appctx *appctx, void *private)
4922
0
{
4923
0
  struct proxy *px;
4924
4925
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4926
0
    return 1;
4927
4928
0
  px = cli_find_frontend(appctx, args[2]);
4929
0
  if (!px)
4930
0
    return 1;
4931
4932
0
  if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
4933
0
    return cli_msg(appctx, LOG_NOTICE, "Frontend was already shut down.\n");
4934
4935
0
  stop_proxy(px);
4936
0
  return 1;
4937
0
}
4938
4939
/* Parses a "add backend" CLI command to allocate a new backend instance,
4940
 * derived from a default proxy instance. This operation is performed under
4941
 * thread isolation.
4942
 *
4943
 * Always returns 1.
4944
 */
4945
static int cli_parse_add_backend(char **args, char *payload, struct appctx *appctx, void *private)
4946
0
{
4947
0
  struct proxy *px, *defpx;
4948
0
  struct post_proxy_check_fct *ppcf;
4949
0
  const char *be_name, *def_name, *guid = NULL, *err;
4950
0
  char *msg = NULL;
4951
0
  enum pr_mode mode = 0;
4952
0
  int err_code = ERR_NONE;
4953
4954
0
  usermsgs_clr("CLI");
4955
4956
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
4957
0
    return 1;
4958
4959
0
  ++args;
4960
0
  be_name = args[1];
4961
0
  if (!*be_name) {
4962
0
    cli_err(appctx, "Require backend name.\n");
4963
0
    return 1;
4964
0
  }
4965
0
  if ((err = invalid_char(be_name))) {
4966
0
    cli_dynerr(appctx, memprintf(&msg, "Invalid character '%c' in backend name.\n", *err));
4967
0
    return 1;
4968
0
  }
4969
4970
0
  ++args;
4971
0
  def_name = args[2];
4972
0
  if (!*args[1] || !*def_name || strcmp(args[1], "from") != 0) {
4973
0
    cli_err(appctx, "Usage: add backend <name> from <defproxy>.\n");
4974
0
    return 1;
4975
0
  }
4976
4977
  /* Parse optional arguments */
4978
0
  args += 2;
4979
0
  while (*args[1]) {
4980
    /* "mode" */
4981
0
    if (*args[2] && !mode && strcmp(args[1], "mode") == 0) {
4982
0
      mode = str_to_proxy_mode(args[2]);
4983
0
      if (mode == PR_MODES) {
4984
0
        cli_err(appctx, "Unknown proxy mode.\n");
4985
0
        return 1;
4986
0
      }
4987
0
      if (mode != PR_MODE_TCP && mode != PR_MODE_HTTP) {
4988
0
        cli_err(appctx, "Dynamic backends are compatible with only TCP or HTTP mode.\n");
4989
0
        return 1;
4990
0
      }
4991
0
    }
4992
    /* guid */
4993
0
    else if (*args[2] && !guid && strcmp(args[1], "guid") == 0) {
4994
0
      guid = args[2];
4995
0
    }
4996
    /* unknown, malformed or duplicate argument */
4997
0
    else {
4998
0
      cli_err(appctx, "Usage: add backend <name> from <defproxy> [mode <px_mode>] [guid <val>].\n");
4999
0
      return 1;
5000
0
    }
5001
5002
0
    args += 2;
5003
0
  }
5004
5005
0
  defpx = proxy_find_by_name(def_name, PR_CAP_DEF, 0);
5006
0
  if (!defpx) {
5007
0
    cli_dynerr(appctx, memprintf(&msg, "Cannot find default proxy '%s'.\n", def_name));
5008
0
    return 1;
5009
0
  }
5010
0
  if (!(defpx->flags & PR_FL_DEF_EXPLICIT_MODE) && !mode) {
5011
0
    cli_dynerr(appctx, memprintf(&msg, "Mode is required as '%s' default proxy does not explicitly defines it.\n", def_name));
5012
0
    return 1;
5013
0
  }
5014
0
  if (defpx->mode != PR_MODE_TCP && defpx->mode != PR_MODE_HTTP) {
5015
0
    cli_dynerr(appctx, memprintf(&msg, "Dynamic backends only support TCP or HTTP mode, whereas default proxy '%s' uses 'mode %s'.\n",
5016
0
               def_name, proxy_mode_str(defpx->mode)));
5017
0
    return 1;
5018
0
  }
5019
5020
0
  thread_isolate();
5021
5022
0
  if ((px = proxy_find_by_name(be_name, PR_CAP_NONE, 0)) ||
5023
0
      (px = proxy_find_by_name(be_name, PR_CAP_DEF, 0))) {
5024
0
    memprintf(&msg,
5025
0
      "name is already used by other proxy '%s %s'",
5026
0
      proxy_cap_str(px->cap), be_name);
5027
0
    px = NULL;
5028
0
    goto err;
5029
0
  }
5030
5031
0
  px = alloc_new_proxy(be_name, PR_CAP_BE, &msg);
5032
0
  if (!px)
5033
0
    goto err;
5034
5035
0
  if (guid && guid_insert(&px->obj_type, guid, &msg)) {
5036
0
    memprintf(&msg, "GUID insertion : %s", msg);
5037
0
    goto err;
5038
0
  }
5039
5040
0
  if (proxy_defproxy_cpy(px, defpx, &msg))
5041
0
    goto err;
5042
5043
  /* Override default-proxy mode if defined. */
5044
0
  if (mode)
5045
0
    px->mode = mode;
5046
5047
0
  if (proxy_ref_defaults(px, defpx, &msg))
5048
0
    goto err;
5049
5050
0
  proxy_init_per_thr(px);
5051
5052
0
  if (proxy_finalize(px, &err_code))
5053
0
    goto err;
5054
5055
0
  list_for_each_entry(ppcf, &post_proxy_check_list, list) {
5056
0
    err_code |= ppcf->fct(px);
5057
0
    if (err_code & (ERR_ABORT|ERR_FATAL))
5058
0
      goto err;
5059
0
  }
5060
5061
0
  px->flags |= PR_FL_BE_UNPUBLISHED;
5062
5063
0
  if (!stats_allocate_proxy_counters_internal(&px->extra_counters_be,
5064
0
                                              COUNTERS_BE,
5065
0
                                              STATS_PX_CAP_BE,
5066
0
                                              &px->per_tgrp->extra_counters_be_storage,
5067
0
                                              &px->per_tgrp[1].extra_counters_be_storage -
5068
0
                                              &px->per_tgrp[0].extra_counters_be_storage)) {
5069
0
    memprintf(&msg, "failed to allocate extra counters");
5070
0
    goto err;
5071
0
  }
5072
5073
  /* Assign automatically proxy ID. */
5074
0
  px->uuid = proxy_get_next_id(dynpx_next_id);
5075
0
  if (!px->uuid) {
5076
0
    memprintf(&msg, "no spare proxy ID available");
5077
0
    goto err;
5078
0
  }
5079
0
  proxy_index_id(px);
5080
0
  dynpx_next_id = px->uuid;
5081
5082
  /* Insert <px> into <main_proxies> list of visible proxies. Note that
5083
   * insertion in <all_proxies> has already been performed in
5084
   * setup_new_proxy() via alloc_new_proxy().
5085
   */
5086
0
  main_proxies_register(px);
5087
0
  thread_release();
5088
5089
0
  if (unlikely(!be_supports_dynamic_srv(px, &msg)))
5090
0
    memprintf(&msg, "New backend registered (no support for dynamic servers: %s)", msg);
5091
0
  else
5092
0
    memprintf(&msg, "New backend registered");
5093
0
  ha_notice("%s.\n", msg);
5094
0
  ha_free(&msg);
5095
0
  cli_umsg(appctx, LOG_INFO);
5096
5097
0
  return 1;
5098
5099
0
 err:
5100
  /* This ensures any potential refcounting on defpx is decremented. */
5101
0
  proxy_drop(px);
5102
0
  thread_release();
5103
5104
0
  if (msg) {
5105
0
    memprintf(&msg, "Error during backend creation : %s.\n", msg);
5106
0
    cli_dynerr(appctx, msg);
5107
0
  }
5108
0
  else {
5109
0
    ha_alert("Error during backend creation.\n");
5110
0
    cli_umsgerr(appctx);
5111
0
  }
5112
5113
0
  return 1;
5114
0
}
5115
5116
/* Test if the backend instance named <bename> can be deleted.
5117
 *
5118
 * Returns a positive integer if backend can be deleted. Else, 0 is returned if
5119
 * backend should be deletable after some delay. A negative value indicates
5120
 * that backend cannot be deleted without any external action.
5121
 *
5122
 * If <pb> is not NULL, it will be set to point to the backend instance if name
5123
 * is found. If <pm> is not NULL, it will be used on error to point to the
5124
 * description failure.
5125
 */
5126
int be_check_for_deletion(const char *bename, struct proxy **pb, const char **pm)
5127
0
{
5128
0
  struct proxy *be = NULL;
5129
0
  const char *msg = NULL;
5130
0
  int ret;
5131
5132
  /* First, unrecoverable errors */
5133
0
  ret = -1;
5134
5135
0
  if (!(be = proxy_be_by_name(bename))) {
5136
0
    msg = "No such backend.";
5137
0
    goto out;
5138
0
  }
5139
5140
0
  if (be->cap & PR_CAP_FE) {
5141
0
    msg = "Cannot delete a listen section.";
5142
0
    goto out;
5143
0
  }
5144
5145
0
  if (be->table) {
5146
0
    msg = "Cannot remove a backend with stick-table.";
5147
0
    goto out;
5148
0
  }
5149
5150
0
  if (be->flags & PR_FL_NON_PURGEABLE) {
5151
0
    msg = "This proxy cannot be removed at runtime due to other configuration elements pointing to it.";
5152
0
    goto out;
5153
0
  }
5154
5155
0
  if (be->mode != PR_MODE_TCP && be->mode != PR_MODE_HTTP) {
5156
0
    msg = "Only TCP or HTTP proxies can be removed at runtime.";
5157
0
    goto out;
5158
0
  }
5159
5160
0
  if (!(be->flags & PR_FL_BE_UNPUBLISHED)) {
5161
0
    msg = "Backend must be unpublished prior to its deletion.";
5162
0
    goto out;
5163
0
  }
5164
5165
0
  if (!LIST_ISEMPTY(&be->servers)) {
5166
0
    msg = "Only a backend without server can be deleted.";
5167
0
    goto out;
5168
0
  }
5169
5170
  /* Second, conditions that may change over time */
5171
0
  ret = 0;
5172
5173
0
  if (be->beconn) {
5174
0
    msg = "Backend still has attached streams on it.";
5175
0
    goto out;
5176
0
  }
5177
5178
0
  ret = 1;
5179
5180
0
 out:
5181
0
  if (pb)
5182
0
    *pb = be;
5183
0
  if (pm)
5184
0
    *pm = msg;
5185
0
  return ret;
5186
0
}
5187
5188
/* Handler for "delete backend". Runs under thread isolation. Always returns 1. */
5189
static int cli_parse_delete_backend(char **args, char *payload, struct appctx *appctx, void *private)
5190
0
{
5191
0
  struct watcher *px_watch;
5192
0
  struct proxy *px;
5193
0
  const char *msg;
5194
0
  char *be_name;
5195
0
  int ret;
5196
5197
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
5198
0
    return 1;
5199
5200
0
  if (*args[3]) {
5201
0
    cli_err(appctx, "Usage: del backend <name>.\n");
5202
0
    return 1;
5203
0
  }
5204
5205
0
  thread_isolate_full();
5206
5207
0
  be_name = args[2];
5208
0
  ret = be_check_for_deletion(be_name, &px, &msg);
5209
0
  if (ret <= 0) {
5210
0
    cli_err(appctx, msg);
5211
0
    goto out;
5212
0
  }
5213
5214
0
  while (!MT_LIST_ISEMPTY(&px->watcher_list)) {
5215
0
    px_watch = MT_LIST_NEXT(&px->watcher_list, struct watcher *, el);
5216
0
    watcher_next(px_watch, main_proxies_next(px));
5217
0
  }
5218
5219
0
  ceb32_item_delete(&used_proxy_id, conf.uuid_node, uuid, px);
5220
0
  cebis_item_delete(&proxy_by_name, conf.name_node, id, px);
5221
5222
  /* Detach backend from global main_proxies. */
5223
0
  LIST_DELETE(&px->el);
5224
5225
0
  px->flags |= PR_FL_DELETED;
5226
5227
0
  thread_release();
5228
5229
0
  ha_notice("Backend deleted.\n");
5230
0
  proxy_drop(px);
5231
5232
0
  cli_umsg(appctx, LOG_INFO);
5233
0
  return 1;
5234
5235
0
 out:
5236
0
  thread_release();
5237
0
  return 1;
5238
0
}
5239
5240
/* Parses the "disable frontend" directive, it always returns 1.
5241
 *
5242
 * Grabs the proxy lock.
5243
 */
5244
static int cli_parse_disable_frontend(char **args, char *payload, struct appctx *appctx, void *private)
5245
0
{
5246
0
  struct proxy *px;
5247
0
  int ret;
5248
5249
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
5250
0
    return 1;
5251
5252
0
  px = cli_find_frontend(appctx, args[2]);
5253
0
  if (!px)
5254
0
    return 1;
5255
5256
0
  if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
5257
0
    return cli_msg(appctx, LOG_NOTICE, "Frontend was previously shut down, cannot disable.\n");
5258
5259
0
  if (!px->li_ready)
5260
0
    return cli_msg(appctx, LOG_NOTICE, "All sockets are already disabled.\n");
5261
5262
  /* pause_proxy will take PROXY_LOCK */
5263
0
  ret = pause_proxy(px);
5264
5265
0
  if (!ret)
5266
0
    return cli_err(appctx, "Failed to pause frontend, check logs for precise cause.\n");
5267
5268
0
  return 1;
5269
0
}
5270
5271
/* Parses the "enable frontend" directive, it always returns 1.
5272
 *
5273
 * Grabs the proxy lock.
5274
 */
5275
static int cli_parse_enable_frontend(char **args, char *payload, struct appctx *appctx, void *private)
5276
0
{
5277
0
  struct proxy *px;
5278
0
  int ret;
5279
5280
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
5281
0
    return 1;
5282
5283
0
  px = cli_find_frontend(appctx, args[2]);
5284
0
  if (!px)
5285
0
    return 1;
5286
5287
0
  if (px->flags & (PR_FL_DISABLED|PR_FL_STOPPED))
5288
0
    return cli_err(appctx, "Frontend was previously shut down, cannot enable.\n");
5289
5290
0
  if (px->li_ready == px->li_all)
5291
0
    return cli_msg(appctx, LOG_NOTICE, "All sockets are already enabled.\n");
5292
5293
  /* resume_proxy will take PROXY_LOCK */
5294
0
  ret = resume_proxy(px);
5295
5296
0
  if (!ret)
5297
0
    return cli_err(appctx, "Failed to resume frontend, check logs for precise cause (port conflict?).\n");
5298
0
  return 1;
5299
0
}
5300
5301
static int cli_parse_publish_backend(char **args, char *payload, struct appctx *appctx, void *private)
5302
0
{
5303
0
  struct proxy *px;
5304
5305
0
  usermsgs_clr("CLI");
5306
5307
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
5308
0
    return 1;
5309
5310
0
  px = cli_find_backend(appctx, args[2]);
5311
0
  if (!px)
5312
0
    return cli_err(appctx, "No such backend.\n");
5313
5314
0
  if (px->flags & PR_FL_DISABLED)
5315
0
    return cli_err(appctx, "No effect on a disabled backend.\n");
5316
5317
0
  thread_isolate();
5318
0
  px->flags &= ~PR_FL_BE_UNPUBLISHED;
5319
0
  thread_release();
5320
5321
0
  ha_notice("Backend published.\n");
5322
0
  return cli_umsg(appctx, LOG_INFO);
5323
0
}
5324
5325
static int cli_parse_unpublish_backend(char **args, char *payload, struct appctx *appctx, void *private)
5326
0
{
5327
0
  struct proxy *px;
5328
5329
0
  usermsgs_clr("CLI");
5330
5331
0
  if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
5332
0
    return 1;
5333
5334
0
  px = cli_find_backend(appctx, args[2]);
5335
0
  if (!px)
5336
0
    return cli_err(appctx, "No such backend.\n");
5337
5338
0
  if (px->flags & PR_FL_DISABLED)
5339
0
    return cli_err(appctx, "No effect on a disabled backend.\n");
5340
5341
0
  thread_isolate();
5342
0
  px->flags |= PR_FL_BE_UNPUBLISHED;
5343
0
  thread_release();
5344
5345
0
  ha_notice("Backend unpublished.\n");
5346
0
  return cli_umsg(appctx, LOG_INFO);
5347
0
}
5348
5349
/* appctx context used during "show errors" */
5350
struct show_errors_ctx {
5351
  struct proxy *px; /* current proxy being dumped, NULL = not started yet. */
5352
  unsigned int flag;  /* bit0: buffer being dumped, 0 = req, 1 = resp ; bit1=skip req ; bit2=skip resp. */
5353
  unsigned int ev_id; /* event ID of error being dumped */
5354
  int iid;    /* if >= 0, ID of the proxy to filter on */
5355
  int ptr;    /* <0: headers, >=0 : text pointer to restart from */
5356
  int bol;    /* pointer to beginning of current line */
5357
5358
  struct watcher px_watch; /* watcher to automatically update px pointer on backend deletion */
5359
};
5360
5361
/* "show errors" handler for the CLI. Returns 0 if wants to continue, 1 to stop
5362
 * now.
5363
 */
5364
static int cli_parse_show_errors(char **args, char *payload, struct appctx *appctx, void *private)
5365
0
{
5366
0
  struct show_errors_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
5367
5368
0
  if (!cli_has_level(appctx, ACCESS_LVL_OPER))
5369
0
    return 1;
5370
5371
0
  if (*args[2]) {
5372
0
    struct proxy *px;
5373
5374
0
    px = proxy_find_by_name(args[2], 0, 0);
5375
0
    if (px)
5376
0
      ctx->iid = px->uuid;
5377
0
    else
5378
0
      ctx->iid = atoi(args[2]);
5379
5380
0
    if (!ctx->iid)
5381
0
      return cli_err(appctx, "No such proxy.\n");
5382
0
  }
5383
0
  else
5384
0
    ctx->iid  = -1; // dump all proxies
5385
5386
0
  ctx->flag = 0;
5387
0
  if (strcmp(args[3], "request") == 0)
5388
0
    ctx->flag |= 4; // ignore response
5389
0
  else if (strcmp(args[3], "response") == 0)
5390
0
    ctx->flag |= 2; // ignore request
5391
5392
0
  ctx->px = NULL;
5393
0
  watcher_init(&ctx->px_watch, &ctx->px, offsetof(struct proxy, watcher_list));
5394
5395
0
  return 0;
5396
0
}
5397
5398
/* This function dumps all captured errors onto the stream connector's
5399
 * read buffer. It returns 0 if the output buffer is full and it needs
5400
 * to be called again, otherwise non-zero.
5401
 */
5402
static int cli_io_handler_show_errors(struct appctx *appctx)
5403
0
{
5404
0
  struct show_errors_ctx *ctx = appctx->svcctx;
5405
0
  extern const char *monthname[12];
5406
5407
0
  chunk_reset(&trash);
5408
5409
0
  if (!ctx->px) {
5410
    /* the function had not been called yet, let's prepare the
5411
     * buffer for a response.
5412
     */
5413
0
    struct tm tm;
5414
5415
0
    get_localtime(date.tv_sec, &tm);
5416
0
    chunk_appendf(&trash, "Total events captured on [%02d/%s/%04d:%02d:%02d:%02d.%03d] : %u\n",
5417
0
           tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
5418
0
           tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(date.tv_usec/1000),
5419
0
           error_snapshot_id);
5420
5421
0
    if (applet_putchk(appctx, &trash) == -1)
5422
0
      goto cant_send;
5423
5424
0
    watcher_attach(&ctx->px_watch, main_proxies_first());
5425
0
    ctx->bol = 0;
5426
0
    ctx->ptr = -1;
5427
0
  }
5428
5429
  /* we have two inner loops here, one for the proxy, the other one for
5430
   * the buffer.
5431
   */
5432
0
  while (ctx->px) {
5433
0
    struct error_snapshot *es;
5434
5435
0
    HA_RWLOCK_RDLOCK(PROXY_LOCK, &ctx->px->lock);
5436
5437
0
    if ((ctx->flag & 1) == 0) {
5438
0
      es = ctx->px->invalid_req;
5439
0
      if (ctx->flag & 2) // skip req
5440
0
        goto next;
5441
0
    }
5442
0
    else {
5443
0
      es = ctx->px->invalid_rep;
5444
0
      if (ctx->flag & 4) // skip resp
5445
0
        goto next;
5446
0
    }
5447
5448
0
    if (!es)
5449
0
      goto next;
5450
5451
0
    if (ctx->iid >= 0 &&
5452
0
        ctx->px->uuid != ctx->iid &&
5453
0
        (!es->oe || es->oe->uuid != ctx->iid))
5454
0
      goto next;
5455
5456
0
    if (ctx->ptr < 0) {
5457
      /* just print headers now */
5458
5459
0
      char pn[INET6_ADDRSTRLEN];
5460
0
      struct tm tm;
5461
0
      int port;
5462
5463
0
      get_localtime(es->when.tv_sec, &tm);
5464
0
      chunk_appendf(&trash, " \n[%02d/%s/%04d:%02d:%02d:%02d.%03d]",
5465
0
             tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
5466
0
             tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(es->when.tv_usec/1000));
5467
5468
0
      switch (addr_to_str(&es->src, pn, sizeof(pn))) {
5469
0
      case AF_INET:
5470
0
      case AF_INET6:
5471
0
        port = get_host_port(&es->src);
5472
0
        break;
5473
0
      default:
5474
0
        port = 0;
5475
0
      }
5476
5477
0
      switch (ctx->flag & 1) {
5478
0
      case 0:
5479
0
        chunk_appendf(&trash,
5480
0
               " frontend %s (#%d): invalid request\n"
5481
0
               "  backend %s (#%d)",
5482
0
               ctx->px->id, ctx->px->uuid,
5483
0
               (es->oe && es->oe->cap & PR_CAP_BE) ? es->oe->id : "<NONE>",
5484
0
               (es->oe && es->oe->cap & PR_CAP_BE) ? es->oe->uuid : -1);
5485
0
        break;
5486
0
      case 1:
5487
0
        chunk_appendf(&trash,
5488
0
               " backend %s (#%d): invalid response\n"
5489
0
               "  frontend %s (#%d)",
5490
0
               ctx->px->id, ctx->px->uuid,
5491
0
               es->oe ? es->oe->id : "<NONE>" , es->oe ? es->oe->uuid : -1);
5492
0
        break;
5493
0
      }
5494
5495
0
      chunk_appendf(&trash,
5496
0
                    ", server %s (#%d), event #%u, src %s:%d\n"
5497
0
                    "  buffer starts at %llu (including %u out), %u free,\n"
5498
0
                    "  len %u, wraps at %u, error at position %u\n",
5499
0
                    es->srv ? es->srv->id : "<NONE>",
5500
0
                    es->srv ? es->srv->puid : -1,
5501
0
                    es->ev_id, pn, port,
5502
0
                    es->buf_ofs, es->buf_out,
5503
0
                    es->buf_size - es->buf_out - es->buf_len,
5504
0
                    es->buf_len, es->buf_wrap, es->buf_err);
5505
5506
0
      if (es->show)
5507
0
        es->show(&trash, es);
5508
5509
0
      chunk_appendf(&trash, "  \n");
5510
5511
0
      if (STRESS_RUN1(applet_putchk_stress(appctx, &trash) == -1,
5512
0
                      applet_putchk(appctx, &trash) == -1)) {
5513
0
        goto cant_send_unlock;
5514
0
      }
5515
5516
0
      ctx->ptr = 0;
5517
0
      ctx->ev_id = es->ev_id;
5518
0
    }
5519
5520
0
    if (ctx->ev_id != es->ev_id) {
5521
      /* the snapshot changed while we were dumping it */
5522
0
      chunk_appendf(&trash,
5523
0
             "  WARNING! update detected on this snapshot, dump interrupted. Please re-check!\n");
5524
0
      if (applet_putchk(appctx, &trash) == -1)
5525
0
        goto cant_send_unlock;
5526
5527
0
      goto next;
5528
0
    }
5529
5530
    /* OK, ptr >= 0, so we have to dump the current line */
5531
0
    while (ctx->ptr < es->buf_len && ctx->ptr < es->buf_size) {
5532
0
      int newptr;
5533
0
      int newline;
5534
5535
0
      newline = ctx->bol;
5536
0
      newptr = dump_text_line(&trash, es->buf, es->buf_size, es->buf_len, &newline, ctx->ptr);
5537
0
      if (newptr == ctx->ptr) {
5538
0
        applet_fl_set(appctx, APPCTX_FL_OUTBLK_FULL);
5539
0
        goto cant_send_unlock;
5540
0
      }
5541
5542
0
      if (STRESS_RUN1(applet_putchk_stress(appctx, &trash) == -1,
5543
0
                      applet_putchk(appctx, &trash) == -1)) {
5544
0
        goto cant_send_unlock;
5545
0
      }
5546
5547
0
      ctx->ptr = newptr;
5548
0
      ctx->bol = newline;
5549
0
    };
5550
0
  next:
5551
0
    HA_RWLOCK_RDUNLOCK(PROXY_LOCK, &ctx->px->lock);
5552
0
    ctx->bol = 0;
5553
0
    ctx->ptr = -1;
5554
0
    ctx->flag ^= 1;
5555
0
    if (!(ctx->flag & 1))
5556
0
      watcher_next(&ctx->px_watch, main_proxies_next(ctx->px));
5557
0
  }
5558
5559
  /* dump complete */
5560
0
  return 1;
5561
5562
0
 cant_send_unlock:
5563
0
  HA_RWLOCK_RDUNLOCK(PROXY_LOCK, &ctx->px->lock);
5564
0
 cant_send:
5565
0
  return 0;
5566
0
}
5567
5568
/* release handler for "show errors" */
5569
static void cli_io_release_show_errors(struct appctx *appctx)
5570
0
{
5571
0
  struct show_errors_ctx *ctx = appctx->svcctx;
5572
0
  watcher_detach(&ctx->px_watch);
5573
0
}
5574
5575
/* register cli keywords */
5576
static struct cli_kw_list cli_kws = {{ },{
5577
  { { "add", "backend", NULL },                       "add backend <backend>                   : add a new backend",                                              cli_parse_add_backend, NULL, NULL, NULL, 0 },
5578
  { { "del", "backend", NULL },                       "del backend <backend>                   : delete a backend",                                               cli_parse_delete_backend, NULL, NULL, NULL, 0 },
5579
  { { "disable", "frontend",  NULL },                 "disable frontend <frontend>             : temporarily disable specific frontend",                          cli_parse_disable_frontend, NULL, NULL },
5580
  { { "enable", "frontend",  NULL },                  "enable frontend <frontend>              : re-enable specific frontend",                                    cli_parse_enable_frontend, NULL, NULL },
5581
  { { "publish", "backend",  NULL },                  "publish backend <backend>               : mark backend as ready for traffic",                              cli_parse_publish_backend, NULL, NULL },
5582
  { { "set", "maxconn", "frontend",  NULL },          "set maxconn frontend <frontend> <value> : change a frontend's maxconn setting",                            cli_parse_set_maxconn_frontend, NULL },
5583
  { { "show", "default-server", NULL },               "show default-server [<backend>]         : list default-server instances in all or a single backend",       cli_parse_show_default_server, cli_io_handler_show_default_server, cli_io_release_show_default_server, },
5584
  { { "show", "defaults", NULL },                     "show defaults                           : list all proxies defaults sections",                             NULL, cli_io_handler_show_defaults },
5585
  { { "show","servers", "conn",  NULL },              "show servers conn [<backend>]           : dump server connections status (all or for a single backend)",   cli_parse_show_servers, cli_io_handler_servers_state, cli_io_release_show_servers, },
5586
  { { "show","servers", "state",  NULL },             "show servers state [<backend>]          : dump volatile server information (all or for a single backend)", cli_parse_show_servers, cli_io_handler_servers_state, cli_io_release_show_servers, },
5587
  { { "show", "backend", NULL },                      "show backend                            : list backends in the current running config",                    NULL, cli_io_handler_show_backend, cli_io_release_show_backend, },
5588
  { { "shutdown", "frontend",  NULL },                "shutdown frontend <frontend>            : stop a specific frontend",                                       cli_parse_shutdown_frontend, NULL, NULL },
5589
  { { "set", "dynamic-cookie-key", "backend", NULL }, "set dynamic-cookie-key backend <bk> <k> : change a backend secret key for dynamic cookies",                cli_parse_set_dyncookie_key_backend, NULL },
5590
  { { "unpublish", "backend",  NULL },                "unpublish backend <backend>             : remove backend for traffic processing",                          cli_parse_unpublish_backend, NULL, NULL },
5591
  { { "enable", "dynamic-cookie", "backend", NULL },  "enable dynamic-cookie backend <bk>      : enable dynamic cookies on a specific backend",                   cli_parse_enable_dyncookie_backend, NULL },
5592
  { { "disable", "dynamic-cookie", "backend", NULL }, "disable dynamic-cookie backend <bk>     : disable dynamic cookies on a specific backend",                  cli_parse_disable_dyncookie_backend, NULL },
5593
  { { "show", "errors", NULL },                       "show errors [<px>] [request|response]   : report last request and/or response errors for each proxy",      cli_parse_show_errors, cli_io_handler_show_errors, cli_io_release_show_errors, },
5594
  {{},}
5595
}};
5596
5597
INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
5598
5599
/*
5600
 * Local variables:
5601
 *  c-indent-level: 8
5602
 *  c-basic-offset: 8
5603
 * End:
5604
 */