📄 easy-tls.c
字号:
int w = n >= 2; /* loop over all (i, w) in {0,1}x{0,1} */ int fd; if (i == 0 && w == 0) fd = read_select_1; else if (i == 1 && w == 0) fd = read_select_2; else if (i == 0 && w == 1) fd = write_select_1; else { assert(i == 1 && w == 1); fd = write_select_2; } if (fd >= 0) { if (w == 0) FD_SET(fd, &reads); else /* w == 1 */ FD_SET(fd, &writes); } } if (seconds >= 0) { timeout.tv_sec = seconds; timeout.tv_usec = 0; timeout_p = &timeout; } else timeout_p = NULL; DEBUG_MSG2("select no.", ++tls_select_count); select(maxfd + 1, &reads, &writes, (fd_set *) NULL, timeout_p); DEBUG_MSG("cont.");}/*****************************************************************************/#define TUNNELBUFSIZE (16*1024)struct tunnelbuf { char buf[TUNNELBUFSIZE]; size_t len; size_t offset;};static int tls_connect_attempt(SSL *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);static int tls_accept_attempt(SSL *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);static int tls_write_attempt(SSL *, struct tunnelbuf *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);static int tls_read_attempt(SSL *, struct tunnelbuf *, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref);static int write_attempt(int fd, struct tunnelbuf *, int *select, int *closed, int *progress);static int read_attempt(int fd, struct tunnelbuf *, int *select, int *closed, int *progress);static void write_info(SSL *ssl, int *info_fd){ if (*info_fd != -1) { long v; int v_ok; struct tls_x509_name_string peer; char infobuf[TLS_INFO_SIZE]; int r; DEBUG_MSG("write_info"); v = SSL_get_verify_result(ssl); v_ok = (v == X509_V_OK) ? 'A' : 'E'; /* Auth./Error */ { X509 *peercert; peercert = SSL_get_peer_certificate(ssl); tls_get_x509_subject_name_oneline(peercert, &peer); if (peercert != NULL) X509_free(peercert); } if (peer.str[0] == '\0') v_ok = '0'; /* no cert at all */ else if (strchr(peer.str, '\n')) { /* should not happen, but make sure */ *strchr(peer.str, '\n') = '\0'; } r = snprintf(infobuf, sizeof infobuf, "%c:%s\n%s\n", v_ok, X509_verify_cert_error_string(v), peer.str); DEBUG_MSG2("snprintf", r); if (r == -1 || r >= sizeof infobuf) r = sizeof infobuf - 1; write(*info_fd, infobuf, r); close (*info_fd); *info_fd = -1; }}/* tls_proxy expects that all fds are closed after return */static voidtls_proxy(int clear_fd, int tls_fd, int info_fd, SSL_CTX *ctx, int client_p){ struct tunnelbuf clear_to_tls, tls_to_clear; SSL *ssl; BIO *rbio, *wbio; int closed, in_handshake; const char *err_pref_1 = "", *err_pref_2 = ""; const char *err_def = NULL; assert(clear_fd != -1); assert(tls_fd != -1); assert(clear_fd < FD_SETSIZE); assert(tls_fd < FD_SETSIZE); /* info_fd may be -1 */ assert(ctx != NULL); tls_rand_seed_uniquely(); tls_socket_nonblocking(clear_fd); DEBUG_MSG2("clear_fd", clear_fd); tls_socket_nonblocking(tls_fd); DEBUG_MSG2("tls_fd", tls_fd); ssl = SSL_new(ctx); if (ssl == NULL) goto err; DEBUG_MSG("SSL_new"); if (!SSL_set_fd(ssl, tls_fd)) goto err; rbio = SSL_get_rbio(ssl); wbio = SSL_get_wbio(ssl); /* should be the same, but who cares */ assert(rbio != NULL); assert(wbio != NULL); if (client_p) SSL_set_connect_state(ssl); else SSL_set_accept_state(ssl); closed = 0; in_handshake = 1; tls_to_clear.len = 0; tls_to_clear.offset = 0; clear_to_tls.len = 0; clear_to_tls.offset = 0; err_def = "I/O error"; /* loop finishes as soon as we detect that one side closed; * when all (program and OS) buffers have enough space, * the data from the last succesful read in each direction is transferred * before close */ do { int clear_read_select = 0, clear_write_select = 0, tls_read_select = 0, tls_write_select = 0, progress = 0; int r; unsigned long num_read = BIO_number_read(rbio), num_written = BIO_number_written(wbio); DEBUG_MSG2("loop iteration", ++tls_loop_count); if (in_handshake) { DEBUG_MSG("in_handshake"); if (client_p) r = tls_connect_attempt(ssl, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); else r = tls_accept_attempt(ssl, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); if (r != 0) { write_info(ssl, &info_fd); goto err; } if (closed) goto err_return; if (!SSL_in_init(ssl)) { in_handshake = 0; write_info(ssl, &info_fd); } } if (clear_to_tls.len != 0 && !in_handshake) { assert(!closed); r = tls_write_attempt(ssl, &clear_to_tls, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); if (r != 0) goto err; if (closed) { assert(progress); tls_to_clear.offset = 0; tls_to_clear.len = 0; } } if (tls_to_clear.len != 0) { assert(!closed); r = write_attempt(clear_fd, &tls_to_clear, &clear_write_select, &closed, &progress); if (r != 0) goto err_return; if (closed) { assert(progress); clear_to_tls.offset = 0; clear_to_tls.len = 0; } } if (!closed) { if (clear_to_tls.offset + clear_to_tls.len < sizeof clear_to_tls.buf) { r = read_attempt(clear_fd, &clear_to_tls, &clear_read_select, &closed, &progress); if (r != 0) goto err_return; if (closed) { r = SSL_shutdown(ssl); DEBUG_MSG2("SSL_shutdown", r); } } } if (!closed && !in_handshake) { if (tls_to_clear.offset + tls_to_clear.len < sizeof tls_to_clear.buf) { r = tls_read_attempt(ssl, &tls_to_clear, &tls_write_select, &tls_read_select, &closed, &progress, &err_pref_1); if (r != 0) goto err; if (closed) { r = SSL_shutdown(ssl); DEBUG_MSG2("SSL_shutdown", r); } } } if (!progress) { DEBUG_MSG("!progress?"); if (num_read != BIO_number_read(rbio) || num_written != BIO_number_written(wbio)) progress = 1; if (!progress) { DEBUG_MSG("!progress"); assert(clear_read_select || tls_read_select || clear_write_select || tls_write_select); tls_sockets_select(clear_read_select ? clear_fd : -1, tls_read_select ? tls_fd : -1, clear_write_select ? clear_fd : -1, tls_write_select ? tls_fd : -1, -1); } } } while (!closed); return; err: tls_openssl_errors(err_pref_1, err_pref_2, err_def, tls_child_apparg); err_return: return;}static inttls_get_error(SSL *ssl, int r, int *write_select, int *read_select, int *closed, int *progress){ int err = SSL_get_error(ssl, r); if (err == SSL_ERROR_NONE) { assert(r > 0); *progress = 1; return 0; } assert(r <= 0); switch (err) { case SSL_ERROR_ZERO_RETURN: assert(r == 0); *closed = 1; *progress = 1; return 0; case SSL_ERROR_WANT_WRITE: *write_select = 1; return 0; case SSL_ERROR_WANT_READ: *read_select = 1; return 0; } return -1;}static inttls_connect_attempt(SSL *ssl, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref){ int n, r; DEBUG_MSG("tls_connect_attempt"); n = SSL_connect(ssl); DEBUG_MSG2("SSL_connect",n); r = tls_get_error(ssl, n, write_select, read_select, closed, progress); if (r == -1) *err_pref = " during SSL_connect"; return r;}static inttls_accept_attempt(SSL *ssl, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref){ int n, r; DEBUG_MSG("tls_accept_attempt"); n = SSL_accept(ssl); DEBUG_MSG2("SSL_accept",n); r = tls_get_error(ssl, n, write_select, read_select, closed, progress); if (r == -1) *err_pref = " during SSL_accept"; return r;}static inttls_write_attempt(SSL *ssl, struct tunnelbuf *buf, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref){ int n, r; DEBUG_MSG("tls_write_attempt"); n = SSL_write(ssl, buf->buf + buf->offset, buf->len); DEBUG_MSG2("SSL_write",n); r = tls_get_error(ssl, n, write_select, read_select, closed, progress); if (n > 0) { buf->len -= n; assert(buf->len >= 0); if (buf->len == 0) buf->offset = 0; else buf->offset += n; } if (r == -1) *err_pref = " during SSL_write"; return r;}static inttls_read_attempt(SSL *ssl, struct tunnelbuf *buf, int *write_select, int *read_select, int *closed, int *progress, const char **err_pref){ int n, r; size_t total; DEBUG_MSG("tls_read_attempt"); total = buf->offset + buf->len; assert(total < sizeof buf->buf); n = SSL_read(ssl, buf->buf + total, (sizeof buf->buf) - total); DEBUG_MSG2("SSL_read",n); r = tls_get_error(ssl, n, write_select, read_select, closed, progress); if (n > 0) { buf->len += n; assert(buf->offset + buf->len <= sizeof buf->buf); } if (r == -1) *err_pref = " during SSL_read"; return r;}static intget_error(int r, int *select, int *closed, int *progress){ if (r >= 0) { *progress = 1; if (r == 0) *closed = 1; return 0; } else { assert(r == -1); if (errno == EAGAIN || errno == EWOULDBLOCK) { *select = 1; return 0; } else if (errno == EPIPE) { *progress = 1; *closed = 1; return 0; } else return -1; }}static int write_attempt(int fd, struct tunnelbuf *buf, int *select, int *closed, int *progress){ int n, r; DEBUG_MSG("write_attempt"); n = write(fd, buf->buf + buf->offset, buf->len); DEBUG_MSG2("write",n); r = get_error(n, select, closed, progress); if (n > 0) { buf->len -= n; assert(buf->len >= 0); if (buf->len == 0) buf->offset = 0; else buf->offset += n; } if (r == -1) tls_errprintf(1, tls_child_apparg, "write error: %s\n", strerror(errno)); return r;} static intread_attempt(int fd, struct tunnelbuf *buf, int *select, int *closed, int *progress){ int n, r; size_t total; DEBUG_MSG("read_attempt"); total = buf->offset + buf->len; assert(total < sizeof buf->buf); n = read(fd, buf->buf + total, (sizeof buf->buf) - total); DEBUG_MSG2("read",n); r = get_error(n, select, closed, progress); if (n > 0) { buf->len += n; assert(buf->offset + buf->len <= sizeof buf->buf); } if (r == -1) tls_errprintf(1, tls_child_apparg, "read error: %s\n", strerror(errno)); return r;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -