struct proxy *findproxy_mode(const char *name, int mode, int cap) { struct proxy *curproxy, *target = NULL; struct ebpt_node *node; for (node = ebis_lookup(&proxy_by_name, name); node; node = ebpt_next(node)) { curproxy = container_of(node, struct proxy, conf.by_name); if (strcmp(curproxy->id, name) != 0) break; if ((curproxy->cap & cap) != cap) continue; if (curproxy->mode != mode && !(curproxy->mode == PR_MODE_HTTP && mode == PR_MODE_TCP)) { Alert("Unable to use proxy '%s' with wrong mode, required: %s, has: %s.\n", name, proxy_mode_str(mode), proxy_mode_str(curproxy->mode)); Alert("You may want to use 'mode %s'.\n", proxy_mode_str(mode)); return NULL; } if (!target) { target = curproxy; continue; } Alert("Refusing to use duplicated proxy '%s' with overlapping capabilities: %s/%s!\n", name, proxy_type_str(curproxy), proxy_type_str(target)); return NULL; } return target; }
struct proxy *findproxy_mode(const char *name, int mode, int cap) { struct proxy *curproxy, *target = NULL; for (curproxy = proxy; curproxy; curproxy = curproxy->next) { if ((curproxy->cap & cap)!=cap || strcmp(curproxy->id, name)) continue; if (curproxy->mode != mode) { Alert("Unable to use proxy '%s' with wrong mode, required: %s, has: %s.\n", name, proxy_mode_str(mode), proxy_mode_str(curproxy->mode)); Alert("You may want to use 'mode %s'.\n", proxy_mode_str(mode)); return NULL; } if (!target) { target = curproxy; continue; } Alert("Refusing to use duplicated proxy '%s' with overlapping capabilities: %s/%s!\n", name, proxy_type_str(curproxy), proxy_type_str(target)); return NULL; } return target; }
/* sends a log message when a backend goes down, and also sets last * change date. */ void set_backend_down(struct proxy *be) { be->last_change = now.tv_sec; be->down_trans++; Alert("%s '%s' has no server available!\n", proxy_type_str(be), be->id); send_log(be, LOG_EMERG, "%s %s has no server available!\n", proxy_type_str(be), be->id); }
/* * This function creates all proxy sockets. It should be done very early, * typically before privileges are dropped. The sockets will be registered * but not added to any fd_set, in order not to loose them across the fork(). * The proxies also start in IDLE state, meaning that it will be * maintain_proxies that will finally complete their loading. * * Its return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL. * Retryable errors will only be printed if <verbose> is not zero. */ int start_proxies(int verbose) { struct proxy *curproxy; struct listener *listener; int lerr, err = ERR_NONE; int pxerr; char msg[100]; for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) { if (curproxy->state != PR_STNEW) continue; /* already initialized */ pxerr = 0; for (listener = curproxy->listen; listener != NULL; listener = listener->next) { if (listener->state != LI_ASSIGNED) continue; /* already started */ lerr = tcp_bind_listener(listener, msg, sizeof(msg)); /* errors are reported if <verbose> is set or if they are fatal */ if (verbose || (lerr & (ERR_FATAL | ERR_ABORT))) { if (lerr & ERR_ALERT) Alert("Starting %s %s: %s\n", proxy_type_str(curproxy), curproxy->id, msg); else if (lerr & ERR_WARN) Warning("Starting %s %s: %s\n", proxy_type_str(curproxy), curproxy->id, msg); } err |= lerr; if (lerr & (ERR_ABORT | ERR_FATAL)) { pxerr |= 1; break; } else if (lerr & ERR_CODE) { pxerr |= 1; continue; } } if (!pxerr) { curproxy->state = PR_STIDLE; send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id); } if (err & ERR_ABORT) break; } return err; }
/* This function parses a "max-keep-alive-queue" statement in a proxy section. * It returns -1 if there is any error, 1 for a warning, otherwise zero. If it * does not return zero, it will write an error or warning message into a * preallocated buffer returned at <err>. The function must be called with * <args> pointing to the first command line word, with <proxy> pointing to * the proxy being parsed, and <defpx> to the default proxy or NULL. */ static int proxy_parse_max_ka_queue(char **args, int section, struct proxy *proxy, struct proxy *defpx, const char *file, int line, char **err) { int retval; char *res; unsigned int val; retval = 0; if (*args[1] == 0) { memprintf(err, "'%s' expects expects an integer value (or -1 to disable)", args[0]); return -1; } val = strtol(args[1], &res, 0); if (*res) { memprintf(err, "'%s' : unexpected character '%c' in integer value '%s'", args[0], *res, args[1]); return -1; } if (!(proxy->cap & PR_CAP_BE)) { memprintf(err, "%s will be ignored because %s '%s' has no backend capability", args[0], proxy_type_str(proxy), proxy->id); retval = 1; } /* we store <val+1> so that a user-facing value of -1 is stored as zero (default) */ proxy->max_ka_queue = val + 1; return retval; }
/* This function parses a "rate-limit" statement in a proxy section. It returns * -1 if there is any error, 1 for a warning, otherwise zero. If it does not * return zero, it may write an error message into the <err> buffer, for at * most <errlen> bytes, trailing zero included. The trailing '\n' must not * be written. The function must be called with <args> pointing to the first * command line word, with <proxy> pointing to the proxy being parsed, and * <defpx> to the default proxy or NULL. */ static int proxy_parse_rate_limit(char **args, int section, struct proxy *proxy, struct proxy *defpx, char *err, int errlen) { int retval, cap; char *res, *name; unsigned int *tv = NULL; unsigned int *td = NULL; unsigned int val; retval = 0; /* simply skip "rate-limit" */ if (strcmp(args[0], "rate-limit") == 0) args++; name = args[0]; if (!strcmp(args[0], "sessions")) { name = "sessions"; tv = &proxy->fe_sps_lim; td = &defpx->fe_sps_lim; cap = PR_CAP_FE; } else { snprintf(err, errlen, "%s '%s': must be 'sessions'", "rate-limit", args[0]); return -1; } if (*args[1] == 0) { snprintf(err, errlen, "%s %s expects expects an integer value (in sessions/second)", "rate-limit", name); return -1; } val = strtoul(args[1], &res, 0); if (*res) { snprintf(err, errlen, "%s %s: unexpected character '%c' in integer value '%s'", "rate-limit", name, *res, args[1]); return -1; } if (!(proxy->cap & cap)) { snprintf(err, errlen, "%s %s will be ignored because %s '%s' has no %s capability", "rate-limit", name, proxy_type_str(proxy), proxy->id, (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } else if (defpx && *tv != *td) { snprintf(err, errlen, "overwriting %s %s which was already specified", "rate-limit", name); retval = 1; } *tv = val; return retval; }
/* This function checks that the designated proxy has no http directives * enabled. It will output a warning if there are, and will fix some of them. * It returns the number of fatal errors encountered. This should be called * at the end of the configuration parsing if the proxy is not in http mode. * The <file> argument is used to construct the error message. */ int proxy_cfg_ensure_no_http(struct proxy *curproxy) { if (curproxy->cookie_name != NULL) { Warning("config : cookie will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->rsp_exp != NULL) { Warning("config : server regular expressions will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->req_exp != NULL) { Warning("config : client regular expressions will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->monitor_uri != NULL) { Warning("config : monitor-uri will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->lbprm.algo & BE_LB_PROP_L7) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_RR; Warning("config : Layer 7 hash not possible for %s '%s' (needs 'mode http'). Falling back to round robin.\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->to_log & (LW_REQ | LW_RESP)) { curproxy->to_log &= ~(LW_REQ | LW_RESP); Warning("config : 'option httplog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'.\n", proxy_type_str(curproxy), curproxy->id); } /* This one must be removed in TCP mode because it aborts clients after the timeout */ curproxy->options &= ~PR_O_FORCE_CLO; return 0; }
/* This function checks that the designated proxy has no http directives * enabled. It will output a warning if there are, and will fix some of them. * It returns the number of fatal errors encountered. This should be called * at the end of the configuration parsing if the proxy is not in http mode. * The <file> argument is used to construct the error message. */ int proxy_cfg_ensure_no_http(struct proxy *curproxy) { if (curproxy->cookie_name != NULL) { Warning("config : cookie will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->rsp_exp != NULL) { Warning("config : server regular expressions will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->req_exp != NULL) { Warning("config : client regular expressions will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->monitor_uri != NULL) { Warning("config : monitor-uri will be ignored for %s '%s' (needs 'mode http').\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->lbprm.algo & BE_LB_NEED_HTTP) { curproxy->lbprm.algo &= ~BE_LB_ALGO; curproxy->lbprm.algo |= BE_LB_ALGO_RR; Warning("config : Layer 7 hash not possible for %s '%s' (needs 'mode http'). Falling back to round robin.\n", proxy_type_str(curproxy), curproxy->id); } if (curproxy->to_log & (LW_REQ | LW_RESP)) { curproxy->to_log &= ~(LW_REQ | LW_RESP); Warning("config : 'option httplog' not usable with %s '%s' (needs 'mode http'). Falling back to 'option tcplog'.\n", proxy_type_str(curproxy), curproxy->id); } return 0; }
/* This function parses a "rate-limit" statement in a proxy section. It returns * -1 if there is any error, 1 for a warning, otherwise zero. If it does not * return zero, it will write an error or warning message into a preallocated * buffer returned at <err>. The function must be called with <args> pointing * to the first command line word, with <proxy> pointing to the proxy being * parsed, and <defpx> to the default proxy or NULL. */ static int proxy_parse_rate_limit(char **args, int section, struct proxy *proxy, struct proxy *defpx, const char *file, int line, char **err) { int retval, cap; char *res; unsigned int *tv = NULL; unsigned int *td = NULL; unsigned int val; retval = 0; if (strcmp(args[1], "sessions") == 0) { tv = &proxy->fe_sps_lim; td = &defpx->fe_sps_lim; cap = PR_CAP_FE; } else { memprintf(err, "'%s' only supports 'sessions' (got '%s')", args[0], args[1]); return -1; } if (*args[2] == 0) { memprintf(err, "'%s %s' expects expects an integer value (in sessions/second)", args[0], args[1]); return -1; } val = strtoul(args[2], &res, 0); if (*res) { memprintf(err, "'%s %s' : unexpected character '%c' in integer value '%s'", args[0], args[1], *res, args[2]); return -1; } if (!(proxy->cap & cap)) { memprintf(err, "%s %s will be ignored because %s '%s' has no %s capability", args[0], args[1], proxy_type_str(proxy), proxy->id, (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } else if (defpx && *tv != *td) { memprintf(err, "overwriting %s %s which was already specified", args[0], args[1]); retval = 1; } *tv = val; return retval; }
/* This function parses a "timeout" statement in a proxy section. It returns * -1 if there is any error, 1 for a warning, otherwise zero. If it does not * return zero, it will write an error or warning message into a preallocated * buffer returned at <err>. The trailing is not be written. The function must * be called with <args> pointing to the first command line word, with <proxy> * pointing to the proxy being parsed, and <defpx> to the default proxy or NULL. * As a special case for compatibility with older configs, it also accepts * "{cli|srv|con}timeout" in args[0]. */ static int proxy_parse_timeout(char **args, int section, struct proxy *proxy, struct proxy *defpx, const char *file, int line, char **err) { unsigned timeout; int retval, cap; const char *res, *name; int *tv = NULL; int *td = NULL; int warn = 0; retval = 0; /* simply skip "timeout" but remain compatible with old form */ if (strcmp(args[0], "timeout") == 0) args++; name = args[0]; if (!strcmp(args[0], "client") || (!strcmp(args[0], "clitimeout") && (warn = WARN_CLITO_DEPRECATED))) { name = "client"; tv = &proxy->timeout.client; td = &defpx->timeout.client; cap = PR_CAP_FE; } else if (!strcmp(args[0], "tarpit")) { tv = &proxy->timeout.tarpit; td = &defpx->timeout.tarpit; cap = PR_CAP_FE | PR_CAP_BE; } else if (!strcmp(args[0], "http-keep-alive")) { tv = &proxy->timeout.httpka; td = &defpx->timeout.httpka; cap = PR_CAP_FE | PR_CAP_BE; } else if (!strcmp(args[0], "http-request")) { tv = &proxy->timeout.httpreq; td = &defpx->timeout.httpreq; cap = PR_CAP_FE | PR_CAP_BE; } else if (!strcmp(args[0], "server") || (!strcmp(args[0], "srvtimeout") && (warn = WARN_SRVTO_DEPRECATED))) { name = "server"; tv = &proxy->timeout.server; td = &defpx->timeout.server; cap = PR_CAP_BE; } else if (!strcmp(args[0], "connect") || (!strcmp(args[0], "contimeout") && (warn = WARN_CONTO_DEPRECATED))) { name = "connect"; tv = &proxy->timeout.connect; td = &defpx->timeout.connect; cap = PR_CAP_BE; } else if (!strcmp(args[0], "check")) { tv = &proxy->timeout.check; td = &defpx->timeout.check; cap = PR_CAP_BE; } else if (!strcmp(args[0], "queue")) { tv = &proxy->timeout.queue; td = &defpx->timeout.queue; cap = PR_CAP_BE; } else if (!strcmp(args[0], "tunnel")) { tv = &proxy->timeout.tunnel; td = &defpx->timeout.tunnel; cap = PR_CAP_BE; } else if (!strcmp(args[0], "client-fin")) { tv = &proxy->timeout.clientfin; td = &defpx->timeout.clientfin; cap = PR_CAP_FE; } else if (!strcmp(args[0], "server-fin")) { tv = &proxy->timeout.serverfin; td = &defpx->timeout.serverfin; cap = PR_CAP_BE; } else { memprintf(err, "'timeout' supports 'client', 'server', 'connect', 'check', " "'queue', 'http-keep-alive', 'http-request', 'tunnel', 'tarpit', " "'client-fin' and 'server-fin' (got '%s')", args[0]); return -1; } if (*args[1] == 0) { memprintf(err, "'timeout %s' expects an integer value (in milliseconds)", name); return -1; } res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); if (res) { memprintf(err, "unexpected character '%c' in 'timeout %s'", *res, name); return -1; } if (!(proxy->cap & cap)) { memprintf(err, "'timeout %s' will be ignored because %s '%s' has no %s capability", name, proxy_type_str(proxy), proxy->id, (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } else if (defpx && *tv != *td) { memprintf(err, "overwriting 'timeout %s' which was already specified", name); retval = 1; } else if (warn) { if (!already_warned(warn)) { memprintf(err, "the '%s' directive is now deprecated in favor of 'timeout %s', and will not be supported in future versions.", args[0], name); retval = 1; } } if (*args[2] != 0) { memprintf(err, "'timeout %s' : unexpected extra argument '%s' after value '%s'.", name, args[2], args[1]); retval = -1; } *tv = MS_TO_TICKS(timeout); return retval; }
/* This function parses a "timeout" statement in a proxy section. It returns * -1 if there is any error, 1 for a warning, otherwise zero. If it does not * return zero, it may write an error message into the <err> buffer, for at * most <errlen> bytes, trailing zero included. The trailing '\n' must not * be written. The function must be called with <args> pointing to the first * command line word, with <proxy> pointing to the proxy being parsed, and * <defpx> to the default proxy or NULL. As a special case for compatibility * with older configs, it also accepts "{cli|srv|con}timeout" in args[0]. */ static int proxy_parse_timeout(char **args, int section, struct proxy *proxy, struct proxy *defpx, char *err, int errlen) { unsigned timeout; int retval, cap; const char *res, *name; int *tv = NULL; int *td = NULL; retval = 0; /* simply skip "timeout" but remain compatible with old form */ if (strcmp(args[0], "timeout") == 0) args++; name = args[0]; if (!strcmp(args[0], "client") || !strcmp(args[0], "clitimeout")) { name = "client"; tv = &proxy->timeout.client; td = &defpx->timeout.client; cap = PR_CAP_FE; } else if (!strcmp(args[0], "tarpit")) { tv = &proxy->timeout.tarpit; td = &defpx->timeout.tarpit; cap = PR_CAP_FE | PR_CAP_BE; } else if (!strcmp(args[0], "http-request")) { tv = &proxy->timeout.httpreq; td = &defpx->timeout.httpreq; cap = PR_CAP_FE; } else if (!strcmp(args[0], "server") || !strcmp(args[0], "srvtimeout")) { name = "server"; tv = &proxy->timeout.server; td = &defpx->timeout.server; cap = PR_CAP_BE; } else if (!strcmp(args[0], "connect") || !strcmp(args[0], "contimeout")) { name = "connect"; tv = &proxy->timeout.connect; td = &defpx->timeout.connect; cap = PR_CAP_BE; } else if (!strcmp(args[0], "check")) { tv = &proxy->timeout.check; td = &defpx->timeout.check; cap = PR_CAP_BE; } else if (!strcmp(args[0], "appsession")) { snprintf(err, errlen, "undocumented 'timeout appsession' may not do what you think and will be removed in next version"); retval = 1; tv = &proxy->timeout.appsession; td = &defpx->timeout.appsession; cap = PR_CAP_BE; } else if (!strcmp(args[0], "queue")) { tv = &proxy->timeout.queue; td = &defpx->timeout.queue; cap = PR_CAP_BE; } else { snprintf(err, errlen, "timeout '%s': must be 'client', 'server', 'connect', 'check', " "'appsession', 'queue', 'http-request' or 'tarpit'", args[0]); return -1; } if (*args[1] == 0) { snprintf(err, errlen, "%s timeout expects an integer value (in milliseconds)", name); return -1; } res = parse_time_err(args[1], &timeout, TIME_UNIT_MS); if (res) { snprintf(err, errlen, "unexpected character '%c' in %s timeout", *res, name); return -1; } if (!(proxy->cap & cap)) { snprintf(err, errlen, "%s timeout will be ignored because %s '%s' has no %s capability", name, proxy_type_str(proxy), proxy->id, (cap & PR_CAP_BE) ? "backend" : "frontend"); retval = 1; } else if (defpx && *tv != *td) { snprintf(err, errlen, "overwriting %s timeout which was already specified", name); retval = 1; } *tv = MS_TO_TICKS(timeout); return retval; }