GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/check_tls.c Lines: 0 110 0.0 %
Date: 2017-11-07 Branches: 0 50 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: check_tls.c,v 1.1 2017/05/27 08:33:25 claudio Exp $	*/
2
3
/*
4
 * Copyright (c) 2017 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
6
 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
 */
20
21
#include <sys/types.h>
22
#include <sys/queue.h>
23
#include <sys/uio.h>
24
25
#include <limits.h>
26
#include <event.h>
27
#include <unistd.h>
28
#include <string.h>
29
#include <imsg.h>
30
31
#include "relayd.h"
32
33
void	check_tls_read(int, short, void *);
34
void	check_tls_write(int, short, void *);
35
void	check_tls_handshake(int, short, void *);
36
void	check_tls_cleanup(struct ctl_tcp_event *);
37
void	check_tls_error(struct ctl_tcp_event *, const char *, const char *);
38
39
void
40
check_tls_read(int s, short event, void *arg)
41
{
42
	char			 rbuf[SMALL_READ_BUF_SIZE];
43
	struct ctl_tcp_event	*cte = arg;
44
	int			 retry_flag = EV_READ;
45
	int			 ret;
46
47
	if (event == EV_TIMEOUT) {
48
		cte->host->up = HOST_DOWN;
49
		check_tls_cleanup(cte);
50
		hce_notify_done(cte->host, HCE_TLS_READ_TIMEOUT);
51
		return;
52
	}
53
54
	bzero(rbuf, sizeof(rbuf));
55
56
	ret = tls_read(cte->tls, rbuf, sizeof(rbuf));
57
	if (ret > 0) {
58
		if (ibuf_add(cte->buf, rbuf, ret) == -1)
59
			fatal("check_tls_read: buf_add error");
60
		if (cte->validate_read != NULL &&
61
		    cte->validate_read(cte) == 0) {
62
			check_tls_cleanup(cte);
63
			hce_notify_done(cte->host, cte->host->he);
64
			return;
65
		}
66
	} else if (ret == 0) {
67
		cte->host->up = HOST_DOWN;
68
		(void)cte->validate_close(cte);
69
		check_tls_cleanup(cte);
70
		hce_notify_done(cte->host, cte->host->he);
71
		return;
72
	} else if (ret == TLS_WANT_POLLIN) {
73
		retry_flag = EV_READ;
74
	} else if (ret == TLS_WANT_POLLOUT) {
75
		retry_flag = EV_WRITE;
76
	} else {
77
		cte->host->up = HOST_DOWN;
78
		check_tls_error(cte, cte->host->conf.name, "cannot read");
79
		check_tls_cleanup(cte);
80
		hce_notify_done(cte->host, HCE_TLS_READ_ERROR);
81
		return;
82
	}
83
84
	event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, check_tls_read,
85
	    &cte->tv_start, &cte->table->conf.timeout, cte);
86
	return;
87
}
88
89
void
90
check_tls_write(int s, short event, void *arg)
91
{
92
	struct ctl_tcp_event	*cte = arg;
93
	int			 retry_flag = EV_WRITE;
94
	int			 len;
95
	int			 ret;
96
97
	if (event == EV_TIMEOUT) {
98
		cte->host->up = HOST_DOWN;
99
		check_tls_cleanup(cte);
100
		hce_notify_done(cte->host, HCE_TLS_WRITE_TIMEOUT);
101
		return;
102
	}
103
104
	len = strlen(cte->table->sendbuf);
105
106
	ret = tls_write(cte->tls, cte->table->sendbuf, len);
107
	if (ret > 0) {
108
		if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) ==
109
		    NULL)
110
			fatalx("ssl_write: cannot create dynamic buffer");
111
112
		event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, check_tls_read,
113
		    &cte->tv_start, &cte->table->conf.timeout, cte);
114
		return;
115
	} else if (ret == TLS_WANT_POLLIN) {
116
		retry_flag = EV_READ;
117
	} else if (ret == TLS_WANT_POLLOUT) {
118
		retry_flag = EV_WRITE;
119
	} else {
120
		cte->host->up = HOST_DOWN;
121
		check_tls_error(cte, cte->host->conf.name, "cannot write");
122
		check_tls_cleanup(cte);
123
		hce_notify_done(cte->host, HCE_TLS_WRITE_ERROR);
124
		return;
125
	}
126
127
	event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, check_tls_write,
128
	    &cte->tv_start, &cte->table->conf.timeout, cte);
129
}
130
131
void
132
check_tls_handshake(int fd, short event, void *arg)
133
{
134
	struct ctl_tcp_event	*cte = arg;
135
	int			 retry_flag = 0;
136
	int			 ret;
137
138
	if (event == EV_TIMEOUT) {
139
		cte->host->up = HOST_DOWN;
140
		hce_notify_done(cte->host, HCE_TLS_CONNECT_TIMEOUT);
141
		check_tls_cleanup(cte);
142
		return;
143
	}
144
145
	ret = tls_handshake(cte->tls);
146
	if (ret == 0) {
147
		if (cte->table->conf.check == CHECK_TCP) {
148
			cte->host->up = HOST_UP;
149
			hce_notify_done(cte->host, HCE_TLS_CONNECT_OK);
150
			check_tls_cleanup(cte);
151
			return;
152
		}
153
		if (cte->table->sendbuf != NULL) {
154
			event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE,
155
			    check_tls_write, &cte->tv_start,
156
			    &cte->table->conf.timeout, cte);
157
			return;
158
		}
159
		if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) ==
160
		    NULL)
161
			fatalx("ssl_connect: cannot create dynamic buffer");
162
		event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ,
163
		    check_tls_read, &cte->tv_start, &cte->table->conf.timeout,
164
		    cte);
165
		return;
166
	} else if (ret == TLS_WANT_POLLIN) {
167
		retry_flag = EV_READ;
168
	} else if (ret == TLS_WANT_POLLOUT) {
169
		retry_flag = EV_WRITE;
170
	} else {
171
		cte->host->up = HOST_DOWN;
172
		check_tls_error(cte, cte->host->conf.name,
173
		   "cannot connect");
174
		hce_notify_done(cte->host, HCE_TLS_CONNECT_FAIL);
175
		check_tls_cleanup(cte);
176
		return;
177
	}
178
179
	event_again(&cte->ev, cte->s, EV_TIMEOUT|retry_flag,
180
	    check_tls_handshake,
181
	    &cte->tv_start, &cte->table->conf.timeout, cte);
182
}
183
184
void
185
check_tls_cleanup(struct ctl_tcp_event *cte)
186
{
187
	tls_close(cte->tls);
188
	tls_reset(cte->tls);
189
	close(cte->s);
190
	ibuf_free(cte->buf);
191
	cte->buf = NULL;
192
}
193
194
void
195
check_tls_error(struct ctl_tcp_event *cte, const char *where, const char *what)
196
{
197
	if (log_getverbose() < 2)
198
		return;
199
	log_debug("TLS error: %s: %s: %s", where, what, tls_error(cte->tls));
200
}
201
202
void
203
check_tls(struct ctl_tcp_event *cte)
204
{
205
	if (cte->tls == NULL) {
206
		cte->tls = tls_client();
207
		if (cte->tls == NULL)
208
			fatal("cannot create TLS connection");
209
	}
210
	/* need to re-configure because of tls_reset */
211
	if (tls_configure(cte->tls, cte->table->tls_cfg) == -1)
212
		fatal("cannot configure TLS connection");
213
214
	if (tls_connect_socket(cte->tls, cte->s, NULL) == -1) {
215
		check_tls_error(cte, cte->host->conf.name,
216
		    "cannot connect");
217
		tls_close(cte->tls);
218
		tls_reset(cte->tls);
219
		cte->host->up = HOST_UNKNOWN;
220
		hce_notify_done(cte->host, HCE_TLS_CONNECT_ERROR);
221
		return;
222
	}
223
224
	event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, check_tls_handshake,
225
	    &cte->tv_start, &cte->table->conf.timeout, cte);
226
}