1*bce5c5ddSclaudio /* $OpenBSD: check_tcp.c,v 1.61 2023/07/03 09:38:08 claudio Exp $ */
2feb9ff76Sreyk
3feb9ff76Sreyk /*
436f5dc5eSpyr * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5feb9ff76Sreyk *
6feb9ff76Sreyk * Permission to use, copy, modify, and distribute this software for any
7feb9ff76Sreyk * purpose with or without fee is hereby granted, provided that the above
8feb9ff76Sreyk * copyright notice and this permission notice appear in all copies.
9feb9ff76Sreyk *
10feb9ff76Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11feb9ff76Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12feb9ff76Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13feb9ff76Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14feb9ff76Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15feb9ff76Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16feb9ff76Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17feb9ff76Sreyk */
18feb9ff76Sreyk
19f04ff968Sreyk #include <sys/types.h>
20f04ff968Sreyk #include <sys/time.h>
21feb9ff76Sreyk #include <sys/socket.h>
221d267cb9Sreyk
230ca734d7Sreyk #include <netinet/in.h>
241d267cb9Sreyk
25feb9ff76Sreyk #include <limits.h>
26feb9ff76Sreyk #include <event.h>
27feb9ff76Sreyk #include <fcntl.h>
28feb9ff76Sreyk #include <unistd.h>
29feb9ff76Sreyk #include <string.h>
307e351ffdSreyk #include <stdlib.h>
31feb9ff76Sreyk #include <errno.h>
321d267cb9Sreyk #include <fnmatch.h>
331d267cb9Sreyk #include <sha1.h>
34f04ff968Sreyk #include <imsg.h>
35e8fb3979Spyr
36748ceb64Sreyk #include "relayd.h"
37feb9ff76Sreyk
387e351ffdSreyk void tcp_write(int, short, void *);
39a2195becSreyk void tcp_host_up(struct ctl_tcp_event *);
40a2195becSreyk void tcp_close(struct ctl_tcp_event *, int);
4192b666f1Spyr void tcp_send_req(int, short, void *);
4292b666f1Spyr void tcp_read_buf(int, short, void *);
43feb9ff76Sreyk
44b98a9b93Spyr int check_http_code(struct ctl_tcp_event *);
45b98a9b93Spyr int check_http_digest(struct ctl_tcp_event *);
46b98a9b93Spyr int check_send_expect(struct ctl_tcp_event *);
47b98a9b93Spyr
487e351ffdSreyk void
check_tcp(struct ctl_tcp_event * cte)497e351ffdSreyk check_tcp(struct ctl_tcp_event *cte)
50feb9ff76Sreyk {
51feb9ff76Sreyk int s;
52feb9ff76Sreyk socklen_t len;
53feb9ff76Sreyk struct timeval tv;
547e351ffdSreyk struct linger lng;
55bb8fa3feSreyk int he = HCE_TCP_SOCKET_OPTION;
56feb9ff76Sreyk
5768b79041Spyr switch (cte->host->conf.ss.ss_family) {
58feb9ff76Sreyk case AF_INET:
5968b79041Spyr ((struct sockaddr_in *)&cte->host->conf.ss)->sin_port =
6068b79041Spyr cte->table->conf.port;
61feb9ff76Sreyk break;
62feb9ff76Sreyk case AF_INET6:
6368b79041Spyr ((struct sockaddr_in6 *)&cte->host->conf.ss)->sin6_port =
6468b79041Spyr cte->table->conf.port;
65feb9ff76Sreyk break;
66feb9ff76Sreyk }
67feb9ff76Sreyk
6868b79041Spyr len = ((struct sockaddr *)&cte->host->conf.ss)->sa_len;
69feb9ff76Sreyk
70b045ffeeSreyk if ((s = socket(cte->host->conf.ss.ss_family,
71b045ffeeSreyk SOCK_STREAM | SOCK_NONBLOCK, 0)) == -1) {
72bb8fa3feSreyk if (errno == EMFILE || errno == ENFILE)
73bb8fa3feSreyk he = HCE_TCP_SOCKET_LIMIT;
74bb8fa3feSreyk else
75bb8fa3feSreyk he = HCE_TCP_SOCKET_ERROR;
767e351ffdSreyk goto bad;
77bb8fa3feSreyk }
787e351ffdSreyk
7976ccee27Sjsg cte->s = s;
8076ccee27Sjsg
817e351ffdSreyk bzero(&lng, sizeof(lng));
827e351ffdSreyk if (setsockopt(s, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng)) == -1)
837e351ffdSreyk goto bad;
847e351ffdSreyk
852102796bSbenno if (cte->host->conf.ttl > 0)
862102796bSbenno switch (cte->host->conf.ss.ss_family) {
872102796bSbenno case AF_INET:
8859354cb3Sreyk if (setsockopt(s, IPPROTO_IP, IP_TTL,
8959354cb3Sreyk &cte->host->conf.ttl, sizeof(int)) == -1)
9059354cb3Sreyk goto bad;
912102796bSbenno break;
922102796bSbenno case AF_INET6:
932102796bSbenno if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
942102796bSbenno &cte->host->conf.ttl, sizeof(int)) == -1)
952102796bSbenno goto bad;
962102796bSbenno break;
9759354cb3Sreyk }
9859354cb3Sreyk
9968b79041Spyr bcopy(&cte->table->conf.timeout, &tv, sizeof(tv));
10068b79041Spyr if (connect(s, (struct sockaddr *)&cte->host->conf.ss, len) == -1) {
101c0dc99f6Sreyk if (errno != EINPROGRESS) {
102c0dc99f6Sreyk he = HCE_TCP_CONNECT_FAIL;
1037e351ffdSreyk goto bad;
104316de847Spyr }
105c0dc99f6Sreyk }
106316de847Spyr
10705541978Sreyk cte->buf = NULL;
1087e351ffdSreyk cte->host->up = HOST_UP;
10922bd41a5Sjsg event_del(&cte->ev);
11001d85ec5Sreyk event_set(&cte->ev, s, EV_TIMEOUT|EV_WRITE, tcp_write, cte);
11101d85ec5Sreyk event_add(&cte->ev, &tv);
1127e351ffdSreyk return;
11301d85ec5Sreyk
1147e351ffdSreyk bad:
115a2195becSreyk tcp_close(cte, HOST_DOWN);
116c0dc99f6Sreyk hce_notify_done(cte->host, he);
117feb9ff76Sreyk }
1187e351ffdSreyk
1197e351ffdSreyk void
tcp_write(int s,short event,void * arg)1207e351ffdSreyk tcp_write(int s, short event, void *arg)
1217e351ffdSreyk {
1227e351ffdSreyk struct ctl_tcp_event *cte = arg;
1237e351ffdSreyk int err;
1247e351ffdSreyk socklen_t len;
1257e351ffdSreyk
1267e351ffdSreyk if (event == EV_TIMEOUT) {
127a2195becSreyk tcp_close(cte, HOST_DOWN);
128c0dc99f6Sreyk hce_notify_done(cte->host, HCE_TCP_CONNECT_TIMEOUT);
129de9b5e44Sreyk return;
130de9b5e44Sreyk }
131de9b5e44Sreyk
1327e351ffdSreyk len = sizeof(err);
1337e351ffdSreyk if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len))
134efc39811Sbenno fatal("%s: getsockopt", __func__);
135de9b5e44Sreyk if (err != 0) {
136a2195becSreyk tcp_close(cte, HOST_DOWN);
137c0dc99f6Sreyk hce_notify_done(cte->host, HCE_TCP_CONNECT_FAIL);
138de9b5e44Sreyk return;
139feb9ff76Sreyk }
140e8fb3979Spyr
141de9b5e44Sreyk cte->host->up = HOST_UP;
142a2195becSreyk tcp_host_up(cte);
1437e351ffdSreyk }
1447e351ffdSreyk
1457e351ffdSreyk void
tcp_close(struct ctl_tcp_event * cte,int status)146a2195becSreyk tcp_close(struct ctl_tcp_event *cte, int status)
1477e351ffdSreyk {
148a2195becSreyk close(cte->s);
149a2195becSreyk cte->s = -1;
150a2195becSreyk if (status != 0)
151a2195becSreyk cte->host->up = status;
152a2195becSreyk ibuf_free(cte->buf);
153a2195becSreyk cte->buf = NULL;
154a2195becSreyk }
155bf9a553dSreyk
156a2195becSreyk void
tcp_host_up(struct ctl_tcp_event * cte)157a2195becSreyk tcp_host_up(struct ctl_tcp_event *cte)
158a2195becSreyk {
15968b79041Spyr switch (cte->table->conf.check) {
1607e351ffdSreyk case CHECK_TCP:
1617bb52228Sreyk if (cte->table->conf.flags & F_TLS)
162e8fb3979Spyr break;
163a2195becSreyk tcp_close(cte, 0);
164c0dc99f6Sreyk hce_notify_done(cte->host, HCE_TCP_CONNECT_OK);
16592b666f1Spyr return;
1667e351ffdSreyk case CHECK_HTTP_CODE:
1676965b31bSbenno cte->validate_read = NULL;
16892b666f1Spyr cte->validate_close = check_http_code;
16992b666f1Spyr break;
1707e351ffdSreyk case CHECK_HTTP_DIGEST:
171130d360aSreyk cte->validate_read = NULL;
17292b666f1Spyr cte->validate_close = check_http_digest;
1737e351ffdSreyk break;
1743f229715Srob case CHECK_BINSEND_EXPECT:
175bf9a553dSreyk case CHECK_SEND_EXPECT:
17692b666f1Spyr cte->validate_read = check_send_expect;
17792b666f1Spyr cte->validate_close = check_send_expect;
178bf9a553dSreyk break;
1797e351ffdSreyk }
18092b666f1Spyr
1817bb52228Sreyk if (cte->table->conf.flags & F_TLS) {
18285e5f500Sclaudio check_tls(cte);
183e8fb3979Spyr return;
184e8fb3979Spyr }
185e8fb3979Spyr
1863f229715Srob if (cte->table->sendbuf != NULL || cte->table->sendbinbuf != NULL) {
187a2195becSreyk event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, tcp_send_req,
18868b79041Spyr &cte->tv_start, &cte->table->conf.timeout, cte);
18992b666f1Spyr return;
19092b666f1Spyr }
19192b666f1Spyr
192e39620e5Snicm if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
193efc39811Sbenno fatalx("%s: cannot create dynamic buffer", __func__);
194a2195becSreyk event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, tcp_read_buf,
19568b79041Spyr &cte->tv_start, &cte->table->conf.timeout, cte);
19692b666f1Spyr }
19792b666f1Spyr
19892b666f1Spyr void
tcp_send_req(int s,short event,void * arg)19992b666f1Spyr tcp_send_req(int s, short event, void *arg)
20092b666f1Spyr {
20192b666f1Spyr struct ctl_tcp_event *cte = arg;
2024b0d3762Sclaudio char *req;
20392b666f1Spyr int bs;
20492b666f1Spyr int len;
20592b666f1Spyr
20692b666f1Spyr if (event == EV_TIMEOUT) {
207a2195becSreyk tcp_close(cte, HOST_DOWN);
208c0dc99f6Sreyk hce_notify_done(cte->host, HCE_TCP_WRITE_TIMEOUT);
20992b666f1Spyr return;
21092b666f1Spyr }
2113f229715Srob
2123f229715Srob if (cte->table->sendbinbuf != NULL) {
2133f229715Srob len = ibuf_size(cte->table->sendbinbuf);
2144b0d3762Sclaudio req = ibuf_data(cte->table->sendbinbuf);
2153f229715Srob log_debug("%s: table %s sending binary", __func__,
2163f229715Srob cte->table->conf.name);
217*bce5c5ddSclaudio print_hex(req, 0, len);
2184b0d3762Sclaudio } else {
2194b0d3762Sclaudio len = strlen(cte->table->sendbuf);
2204b0d3762Sclaudio req = cte->table->sendbuf;
2214b0d3762Sclaudio }
2223f229715Srob
22392b666f1Spyr do {
2244b0d3762Sclaudio bs = write(s, req, len);
22592b666f1Spyr if (bs == -1) {
22692b666f1Spyr if (errno == EAGAIN || errno == EINTR)
22792b666f1Spyr goto retry;
228990115abSreyk log_warn("%s: cannot send request", __func__);
229a2195becSreyk tcp_close(cte, HOST_DOWN);
230c0dc99f6Sreyk hce_notify_done(cte->host, HCE_TCP_WRITE_FAIL);
23192b666f1Spyr return;
23292b666f1Spyr }
2334b0d3762Sclaudio req += bs;
23492b666f1Spyr len -= bs;
23592b666f1Spyr } while (len > 0);
23692b666f1Spyr
237e39620e5Snicm if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL)
238efc39811Sbenno fatalx("%s: cannot create dynamic buffer", __func__);
23992b666f1Spyr event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, tcp_read_buf,
24068b79041Spyr &cte->tv_start, &cte->table->conf.timeout, cte);
24192b666f1Spyr return;
24292b666f1Spyr
24392b666f1Spyr retry:
24492b666f1Spyr event_again(&cte->ev, s, EV_TIMEOUT|EV_WRITE, tcp_send_req,
24568b79041Spyr &cte->tv_start, &cte->table->conf.timeout, cte);
24692b666f1Spyr }
24792b666f1Spyr
24892b666f1Spyr void
tcp_read_buf(int s,short event,void * arg)24992b666f1Spyr tcp_read_buf(int s, short event, void *arg)
25092b666f1Spyr {
25192b666f1Spyr ssize_t br;
25292b666f1Spyr char rbuf[SMALL_READ_BUF_SIZE];
25392b666f1Spyr struct ctl_tcp_event *cte = arg;
25492b666f1Spyr
25592b666f1Spyr if (event == EV_TIMEOUT) {
256ec4241b5Sreyk if (ibuf_size(cte->buf))
257ec4241b5Sreyk (void)cte->validate_close(cte);
258ee1808f0Sbenno else {
259ec4241b5Sreyk cte->host->he = HCE_TCP_READ_TIMEOUT;
260ee1808f0Sbenno cte->host->up = HOST_DOWN;
261ee1808f0Sbenno }
262ec4241b5Sreyk tcp_close(cte, cte->host->up == HOST_UP ? 0 : HOST_DOWN);
263ec4241b5Sreyk hce_notify_done(cte->host, cte->host->he);
26492b666f1Spyr return;
26592b666f1Spyr }
26692b666f1Spyr
26792b666f1Spyr bzero(rbuf, sizeof(rbuf));
26892b666f1Spyr br = read(s, rbuf, sizeof(rbuf) - 1);
269316de847Spyr switch (br) {
270316de847Spyr case -1:
27192b666f1Spyr if (errno == EAGAIN || errno == EINTR)
27292b666f1Spyr goto retry;
273a2195becSreyk tcp_close(cte, HOST_DOWN);
274c0dc99f6Sreyk hce_notify_done(cte->host, HCE_TCP_READ_FAIL);
275130d360aSreyk return;
276316de847Spyr case 0:
27792b666f1Spyr cte->host->up = HOST_DOWN;
27892b666f1Spyr (void)cte->validate_close(cte);
279a2195becSreyk tcp_close(cte, 0);
280c0dc99f6Sreyk hce_notify_done(cte->host, cte->host->he);
28192b666f1Spyr return;
282316de847Spyr default:
283e39620e5Snicm if (ibuf_add(cte->buf, rbuf, br) == -1)
284efc39811Sbenno fatal("%s: buf_add error", __func__);
28592b666f1Spyr if (cte->validate_read != NULL) {
28692b666f1Spyr if (cte->validate_read(cte) != 0)
28792b666f1Spyr goto retry;
288a2195becSreyk tcp_close(cte, 0);
289c0dc99f6Sreyk hce_notify_done(cte->host, cte->host->he);
29092b666f1Spyr return;
29192b666f1Spyr }
292316de847Spyr break; /* retry */
293316de847Spyr }
29492b666f1Spyr retry:
29592b666f1Spyr event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, tcp_read_buf,
29668b79041Spyr &cte->tv_start, &cte->table->conf.timeout, cte);
297feb9ff76Sreyk }
2981d267cb9Sreyk
2991d267cb9Sreyk int
check_send_expect(struct ctl_tcp_event * cte)3001d267cb9Sreyk check_send_expect(struct ctl_tcp_event *cte)
3011d267cb9Sreyk {
3021d267cb9Sreyk u_char *b;
3031d267cb9Sreyk
3043f229715Srob if (cte->table->conf.check == CHECK_BINSEND_EXPECT) {
3054b0d3762Sclaudio size_t exlen;
3064b0d3762Sclaudio
3074b0d3762Sclaudio exlen = strlen(cte->table->conf.exbuf) / 2;
3083f229715Srob log_debug("%s: table %s expecting binary",
3093f229715Srob __func__, cte->table->conf.name);
3104b0d3762Sclaudio print_hex(cte->table->conf.exbinbuf, 0, exlen);
3113f229715Srob
3124b0d3762Sclaudio if (ibuf_size(cte->buf) >= exlen && memcmp(ibuf_data(cte->buf),
3134b0d3762Sclaudio cte->table->conf.exbinbuf, exlen) == 0) {
3143f229715Srob cte->host->he = HCE_SEND_EXPECT_OK;
3153f229715Srob cte->host->up = HOST_UP;
3163f229715Srob return (0);
3174b0d3762Sclaudio } else if (ibuf_size(cte->buf) >= exlen) {
3183f229715Srob log_debug("%s: table %s received mismatching binary",
3193f229715Srob __func__, cte->table->conf.name);
3204b0d3762Sclaudio print_hex(ibuf_data(cte->buf), 0, ibuf_size(cte->buf));
3213f229715Srob }
3223f229715Srob } else if (cte->table->conf.check == CHECK_SEND_EXPECT) {
3231d267cb9Sreyk /*
3241d267cb9Sreyk * ensure string is nul-terminated.
3251d267cb9Sreyk */
326*bce5c5ddSclaudio b = strndup(ibuf_data(cte->buf), ibuf_size(cte->buf));
3271d267cb9Sreyk if (b == NULL)
3281d267cb9Sreyk fatal("out of memory");
329d2b99c18Sclaudio if (fnmatch(cte->table->conf.exbuf, b, 0) == 0) {
330c0dc99f6Sreyk cte->host->he = HCE_SEND_EXPECT_OK;
3311d267cb9Sreyk cte->host->up = HOST_UP;
332d2b99c18Sclaudio free(b);
3331d267cb9Sreyk return (0);
3341d267cb9Sreyk }
335d2b99c18Sclaudio free(b);
3363f229715Srob }
337d2b99c18Sclaudio
338c0dc99f6Sreyk cte->host->he = HCE_SEND_EXPECT_FAIL;
3391d267cb9Sreyk cte->host->up = HOST_UNKNOWN;
3401d267cb9Sreyk return (1);
3411d267cb9Sreyk }
3421d267cb9Sreyk
3431d267cb9Sreyk int
check_http_code(struct ctl_tcp_event * cte)3441d267cb9Sreyk check_http_code(struct ctl_tcp_event *cte)
3451d267cb9Sreyk {
3461d267cb9Sreyk char *head;
3471d267cb9Sreyk char scode[4];
3481d267cb9Sreyk const char *estr;
3491d267cb9Sreyk int code;
350c4c83138Sreyk struct host *host;
3511d267cb9Sreyk
3521d267cb9Sreyk /*
3531d267cb9Sreyk * ensure string is nul-terminated.
3541d267cb9Sreyk */
355f69b700dSclaudio if (ibuf_add_zero(cte->buf, 1) == -1)
3561d267cb9Sreyk fatal("out of memory");
3571d267cb9Sreyk
3584b0d3762Sclaudio head = ibuf_data(cte->buf);
359c4c83138Sreyk host = cte->host;
360c0dc99f6Sreyk host->he = HCE_HTTP_CODE_ERROR;
361c48fdb1dSbenno host->code = 0;
362c0dc99f6Sreyk
3631d267cb9Sreyk if (strncmp(head, "HTTP/1.1 ", strlen("HTTP/1.1 ")) &&
3641d267cb9Sreyk strncmp(head, "HTTP/1.0 ", strlen("HTTP/1.0 "))) {
36585a8c65fSreyk log_debug("%s: %s failed (cannot parse HTTP version)",
36685a8c65fSreyk __func__, host->conf.name);
367c4c83138Sreyk host->up = HOST_DOWN;
3681d267cb9Sreyk return (1);
3691d267cb9Sreyk }
3701d267cb9Sreyk head += strlen("HTTP/1.1 ");
3711d267cb9Sreyk if (strlen(head) < 5) /* code + \r\n */ {
372c4c83138Sreyk host->up = HOST_DOWN;
3731d267cb9Sreyk return (1);
3741d267cb9Sreyk }
375a82f8bfbSreyk (void)strlcpy(scode, head, sizeof(scode));
3761d267cb9Sreyk code = strtonum(scode, 100, 999, &estr);
3771d267cb9Sreyk if (estr != NULL) {
37885a8c65fSreyk log_debug("%s: %s failed (cannot parse HTTP code)",
37985a8c65fSreyk __func__, host->conf.name);
380c4c83138Sreyk host->up = HOST_DOWN;
3811d267cb9Sreyk return (1);
3821d267cb9Sreyk }
38368b79041Spyr if (code != cte->table->conf.retcode) {
384c48fdb1dSbenno log_debug("%s: %s failed (invalid HTTP code %d returned)",
385c48fdb1dSbenno __func__, host->conf.name, code);
386c0dc99f6Sreyk host->he = HCE_HTTP_CODE_FAIL;
387c4c83138Sreyk host->up = HOST_DOWN;
388c48fdb1dSbenno host->code = code;
389c0dc99f6Sreyk } else {
390c0dc99f6Sreyk host->he = HCE_HTTP_CODE_OK;
391c4c83138Sreyk host->up = HOST_UP;
392c0dc99f6Sreyk }
393c4c83138Sreyk return (!(host->up == HOST_UP));
3941d267cb9Sreyk }
3951d267cb9Sreyk
3961d267cb9Sreyk int
check_http_digest(struct ctl_tcp_event * cte)3971d267cb9Sreyk check_http_digest(struct ctl_tcp_event *cte)
3981d267cb9Sreyk {
3991d267cb9Sreyk char *head;
40031a3ea06Sreyk char digest[SHA1_DIGEST_STRING_LENGTH];
401c4c83138Sreyk struct host *host;
4021d267cb9Sreyk
4031d267cb9Sreyk /*
4041d267cb9Sreyk * ensure string is nul-terminated.
4051d267cb9Sreyk */
406f69b700dSclaudio if (ibuf_add_zero(cte->buf, 1) == -1)
4071d267cb9Sreyk fatal("out of memory");
4081d267cb9Sreyk
4094b0d3762Sclaudio head = ibuf_data(cte->buf);
410c4c83138Sreyk host = cte->host;
411c0dc99f6Sreyk host->he = HCE_HTTP_DIGEST_ERROR;
412c0dc99f6Sreyk
4131d267cb9Sreyk if ((head = strstr(head, "\r\n\r\n")) == NULL) {
41485a8c65fSreyk log_debug("%s: %s failed (no end of headers)",
41585a8c65fSreyk __func__, host->conf.name);
416c4c83138Sreyk host->up = HOST_DOWN;
4171d267cb9Sreyk return (1);
4181d267cb9Sreyk }
4191d267cb9Sreyk head += strlen("\r\n\r\n");
42031a3ea06Sreyk
4217ae0cc5eSreyk digeststr(cte->table->conf.digest_type, head, strlen(head), digest);
4221d267cb9Sreyk
42368b79041Spyr if (strcmp(cte->table->conf.digest, digest)) {
42485a8c65fSreyk log_warnx("%s: %s failed (wrong digest)",
42585a8c65fSreyk __func__, host->conf.name);
426c0dc99f6Sreyk host->he = HCE_HTTP_DIGEST_FAIL;
427c4c83138Sreyk host->up = HOST_DOWN;
428c0dc99f6Sreyk } else {
429c0dc99f6Sreyk host->he = HCE_HTTP_DIGEST_OK;
430c4c83138Sreyk host->up = HOST_UP;
431c0dc99f6Sreyk }
432c4c83138Sreyk return (!(host->up == HOST_UP));
4331d267cb9Sreyk }
434