1 /* $OpenBSD: check_tls.c,v 1.2 2019/09/15 19:23:29 rob 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 void *buf; 97 98 if (event == EV_TIMEOUT) { 99 cte->host->up = HOST_DOWN; 100 check_tls_cleanup(cte); 101 hce_notify_done(cte->host, HCE_TLS_WRITE_TIMEOUT); 102 return; 103 } 104 105 if (cte->table->sendbinbuf != NULL) { 106 len = ibuf_size(cte->table->sendbinbuf); 107 buf = cte->table->sendbinbuf->buf; 108 log_debug("%s: table %s sending binary", __func__, 109 cte->table->conf.name); 110 print_hex(cte->table->sendbinbuf->buf, 0, len); 111 } else { 112 len = strlen(cte->table->sendbuf); 113 buf = cte->table->sendbuf; 114 } 115 116 ret = tls_write(cte->tls, buf, len); 117 118 if (ret > 0) { 119 if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == 120 NULL) 121 fatalx("ssl_write: cannot create dynamic buffer"); 122 123 event_again(&cte->ev, s, EV_TIMEOUT|EV_READ, check_tls_read, 124 &cte->tv_start, &cte->table->conf.timeout, cte); 125 return; 126 } else if (ret == TLS_WANT_POLLIN) { 127 retry_flag = EV_READ; 128 } else if (ret == TLS_WANT_POLLOUT) { 129 retry_flag = EV_WRITE; 130 } else { 131 cte->host->up = HOST_DOWN; 132 check_tls_error(cte, cte->host->conf.name, "cannot write"); 133 check_tls_cleanup(cte); 134 hce_notify_done(cte->host, HCE_TLS_WRITE_ERROR); 135 return; 136 } 137 138 event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, check_tls_write, 139 &cte->tv_start, &cte->table->conf.timeout, cte); 140 } 141 142 void 143 check_tls_handshake(int fd, short event, void *arg) 144 { 145 struct ctl_tcp_event *cte = arg; 146 int retry_flag = 0; 147 int ret; 148 149 if (event == EV_TIMEOUT) { 150 cte->host->up = HOST_DOWN; 151 hce_notify_done(cte->host, HCE_TLS_CONNECT_TIMEOUT); 152 check_tls_cleanup(cte); 153 return; 154 } 155 156 ret = tls_handshake(cte->tls); 157 if (ret == 0) { 158 if (cte->table->conf.check == CHECK_TCP) { 159 cte->host->up = HOST_UP; 160 hce_notify_done(cte->host, HCE_TLS_CONNECT_OK); 161 check_tls_cleanup(cte); 162 return; 163 } 164 if (cte->table->sendbuf != NULL) { 165 event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, 166 check_tls_write, &cte->tv_start, 167 &cte->table->conf.timeout, cte); 168 return; 169 } 170 if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == 171 NULL) 172 fatalx("ssl_connect: cannot create dynamic buffer"); 173 event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, 174 check_tls_read, &cte->tv_start, &cte->table->conf.timeout, 175 cte); 176 return; 177 } else if (ret == TLS_WANT_POLLIN) { 178 retry_flag = EV_READ; 179 } else if (ret == TLS_WANT_POLLOUT) { 180 retry_flag = EV_WRITE; 181 } else { 182 cte->host->up = HOST_DOWN; 183 check_tls_error(cte, cte->host->conf.name, 184 "cannot connect"); 185 hce_notify_done(cte->host, HCE_TLS_CONNECT_FAIL); 186 check_tls_cleanup(cte); 187 return; 188 } 189 190 event_again(&cte->ev, cte->s, EV_TIMEOUT|retry_flag, 191 check_tls_handshake, 192 &cte->tv_start, &cte->table->conf.timeout, cte); 193 } 194 195 void 196 check_tls_cleanup(struct ctl_tcp_event *cte) 197 { 198 tls_close(cte->tls); 199 tls_reset(cte->tls); 200 close(cte->s); 201 ibuf_free(cte->buf); 202 cte->buf = NULL; 203 } 204 205 void 206 check_tls_error(struct ctl_tcp_event *cte, const char *where, const char *what) 207 { 208 if (log_getverbose() < 2) 209 return; 210 log_debug("TLS error: %s: %s: %s", where, what, tls_error(cte->tls)); 211 } 212 213 void 214 check_tls(struct ctl_tcp_event *cte) 215 { 216 if (cte->tls == NULL) { 217 cte->tls = tls_client(); 218 if (cte->tls == NULL) 219 fatal("cannot create TLS connection"); 220 } 221 /* need to re-configure because of tls_reset */ 222 if (tls_configure(cte->tls, cte->table->tls_cfg) == -1) 223 fatal("cannot configure TLS connection"); 224 225 if (tls_connect_socket(cte->tls, cte->s, NULL) == -1) { 226 check_tls_error(cte, cte->host->conf.name, 227 "cannot connect"); 228 tls_close(cte->tls); 229 tls_reset(cte->tls); 230 cte->host->up = HOST_UNKNOWN; 231 hce_notify_done(cte->host, HCE_TLS_CONNECT_ERROR); 232 return; 233 } 234 235 event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, check_tls_handshake, 236 &cte->tv_start, &cte->table->conf.timeout, cte); 237 } 238