diff --git a/doc/configuration.txt b/doc/configuration.txt index 3788ac025..ae830c0d6 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2628,11 +2628,13 @@ mode { tcp|http|health } brings HAProxy most of its value. health The instance will work in "health" mode. It will just reply "OK" - to incoming connections and close the connection. Nothing will be - logged. This mode is used to reply to external components health - checks. This mode is deprecated and should not be used anymore as - it is possible to do the same and even better by combining TCP or - HTTP modes with the "monitor" keyword. + to incoming connections and close the connection. Alternatively, + If the "httpchk" option is set, "HTTP/1.0 200 OK" will be sent + instead. Nothing will be logged in either case. This mode is used + to reply to external components health checks. This mode is + deprecated and should not be used anymore as it is possible to do + the same and even better by combining TCP or HTTP modes with the + "monitor" keyword. When doing content switching, it is mandatory that the frontend and the backend are in the same mode (generally HTTP), otherwise the configuration @@ -2701,13 +2703,16 @@ monitor-net accepted, the following response will be sent without waiting for a request, then the connection will be closed : "HTTP/1.0 200 OK". This is normally enough for any front-end HTTP probe to detect that the service is UP and - running without forwarding the request to a backend server. + running without forwarding the request to a backend server. Note that this + response is sent in raw format, without any transformation. This is important + as it means that it will not be SSL-encrypted on SSL listeners. - Monitor requests are processed very early. It is not possible to block nor - divert them using ACLs. They cannot be logged either, and it is the intended - purpose. They are only used to report HAProxy's health to an upper component, - nothing more. Right now, it is not possible to set failure conditions on - requests caught by "monitor-net". + Monitor requests are processed very early, just after tcp-request connection + ACLs which are the only ones able to block them. These connections are short + lived and never wait for any data from the client. They cannot be logged, and + it is the intended purpose. They are only used to report HAProxy's health to + an upper component, nothing more. Please note that "monitor fail" rules do + not apply to connections intercepted by "monitor-net". Last, please note that only one "monitor-net" statement can be specified in a frontend. If more than one is found, only the last one will be considered. diff --git a/src/frontend.c b/src/frontend.c index b2b6b1141..3bfd1e577 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -197,27 +197,6 @@ int frontend_accept(struct session *s) s->req->rto = s->fe->timeout.client; s->rep->wto = s->fe->timeout.client; - if (unlikely((s->fe->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) || - (s->fe->mode == PR_MODE_HEALTH && ((s->fe->options2 & PR_O2_CHK_ANY) == PR_O2_HTTP_CHK)))) { - /* Either we got a request from a monitoring system on an HTTP instance, - * or we're in health check mode with the 'httpchk' option enabled. In - * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit. - */ - struct chunk msg; - chunk_initstr(&msg, "HTTP/1.0 200 OK\r\n\r\n"); - stream_int_retnclose(&s->si[0], &msg); /* forge a 200 response */ - s->req->analysers = 0; - s->task->expire = s->rep->wex; - fd_stop_recv(cfd); - } - else if (unlikely(s->fe->mode == PR_MODE_HEALTH)) { /* health check mode, no client reading */ - struct chunk msg; - chunk_initstr(&msg, "OK\n"); - stream_int_retnclose(&s->si[0], &msg); /* forge an "OK" response */ - s->req->analysers = 0; - s->task->expire = s->rep->wex; - fd_stop_recv(cfd); - } /* everything's OK, let's go on */ return 1; diff --git a/src/listener.c b/src/listener.c index d704b4244..f63f9bae3 100644 --- a/src/listener.c +++ b/src/listener.c @@ -345,18 +345,6 @@ void listener_accept(int fd) } } - /* if this connection comes from a known monitoring system, we want to ignore - * it as soon as possible, which means closing it immediately if it is only a - * TCP-based monitoring check. - */ - if (unlikely((l->options & LI_O_CHK_MONNET) && - (p->mode == PR_MODE_TCP) && - addr.ss_family == AF_INET && - (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr)) { - close(cfd); - continue; - } - if (unlikely(cfd >= global.maxsock)) { send_log(p, LOG_EMERG, "Proxy %s reached the configured maximum connection limit. Please check the global 'maxconn' value.\n", diff --git a/src/session.c b/src/session.c index b98b87825..be25ccf7e 100644 --- a/src/session.c +++ b/src/session.c @@ -105,17 +105,6 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) proxy_inc_fe_conn_ctr(l, p); - /* if this session comes from a known monitoring system, we want to ignore - * it as soon as possible, which means closing it immediately for TCP, but - * cleanly. - */ - if (unlikely((l->options & LI_O_CHK_MONNET) && - addr->ss_family == AF_INET && - (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr)) { - s->flags |= SN_MONITOR; - s->logs.logwait = 0; - } - /* now evaluate the tcp-request layer4 rules. Since we expect to be able * to abort right here as soon as possible, we check the rules before * even initializing the stream interfaces. @@ -127,16 +116,44 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) goto out_free_session; } + /* Adjust some socket options */ + if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1)) + goto out_free_session; + + /* monitor-net and health mode are processed immediately after TCP + * connection rules. This way it's possible to block them, but they + * never use the lower data layers, they send directly over the socket, + * as they were designed for. We first flush the socket receive buffer + * in order to avoid emission of an RST by the system. We ignore any + * error. + */ + if (unlikely((p->mode == PR_MODE_HEALTH) || + ((l->options & LI_O_CHK_MONNET) && + addr->ss_family == AF_INET && + (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr))) { + /* we have 4 possibilities here : + * - HTTP mode, from monitoring address => send "HTTP/1.0 200 OK" + * - HEALTH mode with HTTP check => send "HTTP/1.0 200 OK" + * - HEALTH mode without HTTP check => just send "OK" + * - TCP mode from monitoring address => just close + */ + recv(cfd, trash, trashlen, 0&MSG_DONTWAIT); + if (p->mode == PR_MODE_HTTP || + (p->mode == PR_MODE_HEALTH && (p->options2 & PR_O2_CHK_ANY) == PR_O2_HTTP_CHK)) + send(cfd, "HTTP/1.0 200 OK\r\n\r\n", 19, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE); + else if (p->mode == PR_MODE_HEALTH) + send(cfd, "OK\n", 3, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE); + ret = 0; + goto out_free_session; + } + + /* wait for a PROXY protocol header */ if (l->options & LI_O_ACC_PROXY) { s->si[0].conn.flags |= CO_FL_ACCEPT_PROXY; conn_sock_want_recv(&s->si[0].conn); } - /* Adjust some socket options */ - if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1)) - goto out_free_session; - if (unlikely((t = task_new()) == NULL)) goto out_free_session;