tls隧道建立+传输数据
建立tls后copy数据到clean_in 然后写入到ssl加密,从from_ssl 读取加密后的数据然后发送
/* * Take cleartext user data, and encrypt it into the output buffer, * to send to the client at the other end of the SSL connection. */ int tls_handshake_send(tls_session_t *ssn) { int err; /* * If there's un-encrypted data in 'clean_in', then write * that data to the SSL session, and then call the BIO function * to get that encrypted data from the SSL session, into * a buffer which we can then package into an EAP packet. * * Based on Server's logic this clean_in is expected to * contain the data to send to the client. */ if (ssn->clean_in.used > 0) { int written; written = SSL_write(ssn->ssl, ssn->clean_in.data, ssn->clean_in.used); record_minus(&ssn->clean_in, NULL, written); /* Get the dirty data from Bio to send it */ err = BIO_read(ssn->from_ssl, ssn->dirty_out.data + ssn->dirty_out.used, sizeof(ssn->dirty_out.data) - ssn->dirty_out.used); if (err > 0) { ssn->dirty_out.used += err; } else { if (!tls_error_io_log(, ssn, err, "Failed writing to OpenSSL")) { return 0 } } } return 1; }
2、读取加密数据并解密后解析
tls_application_data(tls_session_t *ssn) { int err; VALUE_PAIR **certs; /* * Decrypt the complete record. */ if (ssn->dirty_in.used > 0) { err = BIO_write(ssn->into_ssl, ssn->dirty_in.data, ssn->dirty_in.used); if (err != (int) ssn->dirty_in.used) { REDEBUG("(TLS) Failed writing %zd bytes to SSL BIO: %d", ssn->dirty_in.used, err); record_init(&ssn->dirty_in); return FR_TLS_FAIL; } record_init(&ssn->dirty_in); } /* * tls_handshake_recv() may read application data. So * don't touch clean_out. But only if the BIO_write() * above didn't do anything. */ else if (ssn->clean_out.used > 0) { RDEBUG("(TLS) We already have %zd bytes of application data, processing it.", (ssn->clean_out.used)); goto add_certs; } /* * Read (and decrypt) the tunneled data from the * SSL session, and put it into the decrypted * data buffer. */ err = SSL_read(ssn->ssl, ssn->clean_out.data + ssn->clean_out.used, sizeof(ssn->clean_out.data) - ssn->clean_out.used); if (err <= 0) { int code; RDEBUG3("(TLS) SSL_read Error"); code = SSL_get_error(ssn->ssl, err); switch (code) { case SSL_ERROR_WANT_READ: if (ssn->clean_out.used > 0) { /* just process what application data we have */ err = 0; break; } RDEBUG("(TLS) OpenSSL says that it needs to read more data."); return FR_TLS_MORE_FRAGMENTS; case SSL_ERROR_WANT_WRITE: if (ssn->clean_out.used > 0) { /* just process what application data we have */ err = 0; break; } REDEBUG("(TLS) Error in fragmentation logic: SSL_WANT_WRITE"); return FR_TLS_FAIL; case SSL_ERROR_NONE: RDEBUG2("(TLS) No application data received. Assuming handshake is continuing..."); err = 0; break; case SSL_ERROR_ZERO_RETURN: RDEBUG2("(TLS) Other end closed the TLS tunnel."); return FR_TLS_FAIL; default: REDEBUG("(TLS) Error in fragmentation logic - code %d", code); tls_error_io_log(ssn, err, "Failed reading application data from OpenSSL"); return FR_TLS_FAIL; } } /* * Passed all checks, successfully decrypted data */ ssn->clean_out.used += err; add_certs: /* * Add the certificates to intermediate packets, so that * the inner tunnel policies can use them. */ certs = (VALUE_PAIR **)SSL_get_ex_data(ssn->ssl, fr_tls_ex_index_certs); return FR_TLS_OK; }
对于TCP流来说:
int dual_tls_recv(rad_listen_t *listener) { RADIUS_PACKET *packet; RAD_REQUEST_FUNP fun = NULL; listen_socket_t *sock = listener->data; RADCLIENT *client = sock->client; BIO *rbio; #ifdef WITH_COA_TUNNEL bool is_reply = false; #endif if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0; redo: if (!tls_socket_recv(listener)) { return 0; } //process data /* * Check for more application data. * * If there is pending SSL data, "peek" at the * application data. If we get at least one byte of * application data, go back to tls_socket_recv(). * SSL_peek() will set SSL_pending(), and * tls_socket_recv() will read another packet. */ rbio = SSL_get_rbio(sock->ssn->ssl); if (BIO_ctrl_pending(rbio)) { char buf[1]; int peek = SSL_peek(sock->ssn->ssl, buf, 1); if (peek > 0) { DEBUG("(TLS) more TLS records after dual_tls_recv"); goto redo; } } return 1; }
tls_socket_recv(rad_listen_t *listener) { bool doing_init = false, already_read = false; ssize_t rcode; RADIUS_PACKET *packet; REQUEST *request; listen_socket_t *sock = listener->data; fr_tls_status_t status; RADCLIENT *client = sock->client; /* * Allocate a REQUEST for debugging, and initialize the TLS session. */ if (!sock->request) { request->packet = talloc_steal(request, sock->packet); request->component = "<tls-connect>"; request->reply = rad_alloc(request, false); if (!request->reply) return 0; rad_assert(sock->ssn == NULL); sock->ssn = tls_new_session(sock, listener->tls, sock->request, listener->tls->require_client_cert, true); if (!sock->ssn) { TALLOC_FREE(sock->request); sock->packet = NULL; return 0; } SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request); SSL_set_ex_data(sock->ssn->ssl, fr_tls_ex_index_certs, (void *) &sock->certs); SSL_set_ex_data(sock->ssn->ssl, FR_TLS_EX_INDEX_TALLOC, sock); sock->ssn->quick_session_tickets = true; /* we don't have inner-tunnel authentication */ doing_init = true; } rad_assert(sock->request != NULL); rad_assert(sock->request->packet != NULL); rad_assert(sock->packet != NULL); rad_assert(sock->ssn != NULL); request = sock->request; if (sock->state == LISTEN_TLS_SETUP) { RDEBUG3("(TLS) Setting connection state to RUNNING"); sock->state = LISTEN_TLS_RUNNING; if (sock->ssn->clean_out.used < 20) { goto get_application_data; } goto read_application_data; } RDEBUG3("(TLS) Reading from socket %d", request->packet->sockfd); PTHREAD_MUTEX_LOCK(&sock->mutex); /* * If there is pending application data, as set up by * SSL_peek(), read that before reading more data from * the socket. */ if (SSL_pending(sock->ssn->ssl)) { RDEBUG3("(TLS) Reading pending buffered data"); sock->ssn->dirty_in.used = 0; goto check_for_setup; } if (!already_read) { rcode = read(request->packet->sockfd, sock->ssn->dirty_in.data, sizeof(sock->ssn->dirty_in.data)); if ((rcode < 0) && (errno == ECONNRESET)) { do_close: DEBUG("(TLS) Closing socket from client port %u", sock->other_port); tls_socket_close(listener); PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } if (rcode < 0) { RDEBUG("(TLS) Error reading socket: %s", fr_syserror(errno)); goto do_close; } /* * Normal socket close. */ if (rcode == 0) goto do_close; sock->ssn->dirty_in.used = rcode; } dump_hex("READ FROM SSL", sock->ssn->dirty_in.data, sock->ssn->dirty_in.used); /* * Catch attempts to use non-SSL. */ if (doing_init && (sock->ssn->dirty_in.data[0] != handshake)) { RDEBUG("(TLS) Non-TLS data sent to TLS socket: closing"); goto do_close; } /* * If we need to do more initialization, do that here. */ check_for_setup: if (!sock->ssn->is_init_finished) { if (!tls_handshake_recv(request, sock->ssn)) { RDEBUG("(TLS) Failed in TLS handshake receive"); goto do_close; } /* * More ACK data to send. Do so. */ if (sock->ssn->dirty_out.used > 0) { tls_socket_write(listener, request); PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } /* * If SSL handshake still isn't finished, then there * is more data to read. Release the mutex and * return so this function will be called again */ if (!SSL_is_init_finished(sock->ssn->ssl)) { PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } } /* * Run the request through a virtual server in * order to see if we like the certificate * presented by the client. */ if (sock->state == LISTEN_TLS_INIT) { if (!SSL_is_init_finished(sock->ssn->ssl)) { RDEBUG("(TLS) OpenSSL says that the TLS session is still negotiating, but there's no more data to send!"); goto do_close; } sock->ssn->is_init_finished = true; if (!listener->check_client_connections) { sock->state = LISTEN_TLS_RUNNING; goto get_application_data; } request->packet->vps = fr_pair_list_copy(request->packet, sock->certs); /* * Fake out a Status-Server packet, which * does NOT have a Message-Authenticator, * or any other contents. */ request->packet->code = PW_CODE_STATUS_SERVER; request->packet->data = talloc_zero_array(request->packet, uint8_t, 20); request->packet->data[0] = PW_CODE_STATUS_SERVER; request->packet->data[3] = 20; sock->state = LISTEN_TLS_CHECKING; PTHREAD_MUTEX_UNLOCK(&sock->mutex); /* * Don't read from the socket until the request * returns. */ listener->status = RAD_LISTEN_STATUS_PAUSE; radius_update_listener(listener); return 1; } /* * Try to get application data. */ get_application_data: status = tls_application_data(sock->ssn, request); RDEBUG3("(TLS) Application data status %d", status); if (status == FR_TLS_MORE_FRAGMENTS) { PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } if (sock->ssn->clean_out.used == 0) { PTHREAD_MUTEX_UNLOCK(&sock->mutex); return 0; } /* * Hold application data if we're not yet in the RUNNING * state. */ if (sock->state != LISTEN_TLS_RUNNING) { RDEBUG3("(TLS) Holding application data until setup is complete"); return 0; } read_application_data: /* * We now have a bunch of application data. */ dump_hex("TUNNELED DATA > ", sock->ssn->clean_out.data, sock->ssn->clean_out.used); /* * If the packet is a complete RADIUS packet, return it to * the caller. Otherwise... */ if ((sock->ssn->clean_out.used < 20) || (((sock->ssn->clean_out.data[2] << 8) | sock->ssn->clean_out.data[3]) != (int) sock->ssn->clean_out.used)) { RDEBUG("(TLS) Received bad packet: Length %zd contents %d", sock->ssn->clean_out.used, (sock->ssn->clean_out.data[2] << 8) | sock->ssn->clean_out.data[3]); goto do_close; } packet = sock->packet; packet->data = talloc_array(packet, uint8_t, sock->ssn->clean_out.used); packet->data_len = sock->ssn->clean_out.used; sock->ssn->record_minus(&sock->ssn->clean_out, packet->data, packet->data_len); packet->vps = NULL; PTHREAD_MUTEX_UNLOCK(&sock->mutex); FR_STATS_INC(auth, total_requests); return 1; }
/* * We are the server, we always get the dirty data * (Handshake data is also considered as dirty data) * During handshake, since SSL API handles itself, * After clean-up, dirty_out will be filled with * the data required for handshaking. So we check * if dirty_out is empty then we simply send it back. * As of now, if handshake is successful, then we keep going, * otherwise we fail. * * Fill the Bio with the dirty data to clean it * Get the cleaned data from SSL, if it is not Handshake data */ int tls_handshake_recv(REQUEST *request, tls_session_t *ssn) { int err; if (ssn->invalid_hb_used) { REDEBUG("(TLS) OpenSSL Heartbeat attack detected. Closing connection"); return 0; } if (ssn->dirty_in.used > 0) { err = BIO_write(ssn->into_ssl, ssn->dirty_in.data, ssn->dirty_in.used); if (err != (int) ssn->dirty_in.used) { REDEBUG("(TLS) Failed writing %zd bytes to SSL BIO: %d", ssn->dirty_in.used, err); record_init(&ssn->dirty_in); return 0; } record_init(&ssn->dirty_in); } err = SSL_read(ssn->ssl, ssn->clean_out.data + ssn->clean_out.used, sizeof(ssn->clean_out.data) - ssn->clean_out.used); if (err > 0) { ssn->clean_out.used += err; return 1; } if (!tls_error_io_log(request, ssn, err, "Failed reading from OpenSSL")) return 0; /* Some Extra STATE information for easy debugging */ if (!ssn->is_init_finished && SSL_is_init_finished(ssn->ssl)) { VALUE_PAIR *vp; char const *str_version; RDEBUG2("(TLS) Connection Established"); ssn->is_init_finished = true; vp = fr_pair_afrom_num(request->state_ctx, PW_TLS_SESSION_CIPHER_SUITE, 0); if (vp) { fr_pair_value_strcpy(vp, SSL_CIPHER_get_name(SSL_get_current_cipher(ssn->ssl))); fr_pair_add(&request->state, vp); RINDENT(); rdebug_pair(L_DBG_LVL_2, request, vp, NULL); REXDENT(); } switch (SSL_version(ssn->ssl)) { case SSL2_VERSION: str_version = "SSL 2.0"; break; case SSL3_VERSION: str_version = "SSL 3.0"; break; case TLS1_VERSION: str_version = "TLS 1.0"; break; #ifdef TLS1_1_VERSION case TLS1_1_VERSION: str_version = "TLS 1.1"; break; #endif #ifdef TLS1_2_VERSION case TLS1_2_VERSION: str_version = "TLS 1.2"; break; #endif #ifdef TLS1_3_VERSION case TLS1_3_VERSION: str_version = "TLS 1.3"; break; #endif default: str_version = "UNKNOWN"; break; } vp = fr_pair_afrom_num(request->state_ctx, PW_TLS_SESSION_VERSION, 0); if (vp) { fr_pair_value_strcpy(vp, str_version); fr_pair_add(&request->state, vp); RINDENT(); rdebug_pair(L_DBG_LVL_2, request, vp, NULL); REXDENT(); } } else if (SSL_in_init(ssn->ssl)) { RDEBUG2("(TLS) In Handshake Phase"); } else if (SSL_in_before(ssn->ssl)) { RDEBUG2("(TLS) Before Handshake Phase"); } else if (SSL_in_accept_init(ssn->ssl)) { RDEBUG2("(TLS) In Accept mode"); } else if (SSL_in_connect_init(ssn->ssl)) { RDEBUG2("(TLS) In Connect mode"); } #if OPENSSL_VERSION_NUMBER >= 0x10001000L /* * Cache the SSL_SESSION pointer. */ if (!ssn->ssl_session) { ssn->ssl_session = SSL_get_session(ssn->ssl); /* * Some versions of OpenSSL don't allow you to * get the session before the init is finished. * In that case, this error is a soft fail. * * If the session init is finished, then failure * to get the session is a hard fail. */ if (!ssn->ssl_session && ssn->is_init_finished) { RDEBUG("(TLS) Failed getting session"); return 0; } } #else #error You must use a newer version of OpenSSL #endif err = BIO_ctrl_pending(ssn->from_ssl); if (err > 0) { err = BIO_read(ssn->from_ssl, ssn->dirty_out.data, sizeof(ssn->dirty_out.data)); if (err > 0) { RDEBUG3("(TLS) got %d bytes of data", err); ssn->dirty_out.used = err; } else if (BIO_should_retry(ssn->from_ssl)) { record_init(&ssn->dirty_in); RDEBUG2("(TLS) Asking for more data in tunnel."); return 1; } else { tls_error_log(NULL, "Error reading from OpenSSL"); record_init(&ssn->dirty_in); return 0; } } else { RDEBUG2("(TLS) Application data."); /* Its clean application data, leave whatever is in the buffer */ #if 0 record_init(&ssn->clean_out); #endif } /* We are done with dirty_in, reinitialize it */ record_init(&ssn->dirty_in); return 1; }
http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!!
但行好事 莫问前程
--身高体重180的胖子
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南