#include <openssl/ssl.h>#include <openssl/err.h>#include <string>#include <vector>#include <functional>#define MY_MAX(x,y) ((x)>(y)?(x):(y))#define MY_MIN(x,y) ((x)>(y)?(y):(x))#define MY_BUFFER_SIZE 128#ifdef MY_OS_WINDOWS#include <winsock2.h>#include <ws2tcpip.h>#define inet_aton(str,addr) inet_pton(AF_INET, str, addr)typedef HANDLE task_handle_t;static int fd_is_valid(int fd) {char buffer[1];recv(fd, buffer, 1, MSG_PEEK);return (WSAECONNRESET != WSAGetLastError());}#define my_delay(ms) Sleep(ms)#endif#ifdef MY_OS_LINUX#include <fcntl.h>#include <errno.h>#include <pthread.h>#include <sys/socket.h>#include <netinet/in.h>#define closesocket closetypedef pthread_t task_handle_t;typedef int SOCKET;static int fd_is_valid(int fd) {return fcntl(fd, F_GETFD, 0) != -1 || errno != EBADF;}#define my_delay(ms) sleep(ms/1000)#endif#define MY_LOG(tag, format, ...) printf("[%s] " format "\n", tag, ##__VA_ARGS__)#define TAG_CLIENT "CLIENT"#define TAG_SERVER "SERVER"#define TAG_MAIN "MAIN"struct str_t {const char *data;uint32_t size;};struct url_t {const char *url;str_t protocol;str_t hostname;str_t port;str_t path;str_t search;str_t hash;};// http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocumentstatic bool parse_url(const char *url, url_t *val) {if (!url || !*url || !val) return false;memset(val, 0, sizeof(url_t));val->url = url;val->protocol.data = url;url = strstr(url, "://");if (!url) return false;val->protocol.size = url - val->protocol.data;val->hostname.data = url + 3;url = strchr(val->hostname.data, ':');if (url) {val->hostname.size = url - val->hostname.data;val->port.data = url + 1;url = strchr(val->port.data, '/');if (url) {val->port.size = url - val->port.data;val->path.data = url;} else {val->port.size = strlen(val->port.data);return true;}} else {url = strchr(val->hostname.data, '/');if (url) {val->hostname.size = url - val->hostname.data;val->path.data = url;} else {val->hostname.size = strlen(val->hostname.data);return true;}}url = strchr(val->path.data, '?');if (url) {val->path.size = url - val->path.data;val->search.data = url + 1;} else {val->path.size = strlen(val->path.data);return true;}url = strchr(val->search.data, '#');if (url) {val->search.size = url - val->search.data;val->hash.data = url + 1;val->hash.size = strlen(val->hash.data);} else {val->search.size = strlen(val->search.data);return true;}return true;}static void show_url(const url_t *url) {if (!url) return;printf("---------- show_url begin ----------\n");printf("url: %s\n", url->url);printf("protocol: %.*s\n", url->protocol.size, url->protocol.data);printf("hostname: %.*s\n", url->hostname.size, url->hostname.data);printf("port: %.*s\n", url->port.size, url->port.data);printf("path: %.*s\n", url->path.size, url->path.data);printf("search: %.*s\n", url->search.size, url->search.data);printf("hash: %.*s\n", url->hash.size, url->hash.data);printf("---------- show_url end ----------\n");}static void show_hex(const char *data, int len) {for (int i = 0; i < len; ++i) {if (i % 4 == 0) {if (i % 8 == 0) {if (i) printf("| \n");}else printf("| ");}printf("%02X ", (unsigned char)data[i]);}printf("\n");}static bool parse_url(const char *urlstr, std::string *hostname, std::string *path, uint16_t *port) {url_t url = { 0 };if (!parse_url(urlstr, &url)) return false;std::string strport;hostname->assign(url.hostname.data, url.hostname.size);path->assign(url.path.data, url.path.size);strport.assign(url.port.data, url.port.size);if (hostname->empty()) return false;if (strport.empty()) {strport = 0 == strncmp("https", url.protocol.data, url.protocol.size)? "443" : "80";}if (path->empty()) *path = "/";*port = atoi(strport.c_str());return true;}bool client(const char *hostname, uint16_t port, void *udata, std::function<bool(SSL *ssl, void *udata)> callback) {bool ret = false;SSL *ssl = 0;SSL_CTX *ctx = 0;SOCKET fd = -1;sockaddr_in addr = { 0 };hostent *p = 0;SSL_library_init();OpenSSL_add_all_algorithms();SSL_load_error_strings();ctx = SSL_CTX_new(SSLv23_client_method());if (!ctx) {MY_LOG(TAG_CLIENT, "SSL_CTX_new error.");goto lb_err;}SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);ssl = SSL_new(ctx);if (!ssl) {MY_LOG(TAG_CLIENT, "SSL_new error.");goto lb_err;}fd = socket(AF_INET, SOCK_STREAM, 0);if (fd < 0) {MY_LOG(TAG_CLIENT, "create socket error.");goto lb_err;}addr.sin_addr.S_un.S_addr = 0;addr.sin_port = htons(0);addr.sin_family = AF_INET;if (bind(fd, (const sockaddr*)&addr, sizeof(SOCKADDR_IN)) != NOERROR) {MY_LOG(TAG_CLIENT, "bind error.");goto lb_err;}p = gethostbyname(hostname);if (!p) {MY_LOG(TAG_CLIENT, "gethostbyname error.");goto lb_err;}addr.sin_family = p->h_addrtype;addr.sin_addr.S_un.S_addr = *(ULONG*)(p->h_addr_list[0]);addr.sin_port = htons(port);if (connect(fd, (sockaddr*)&addr, sizeof(addr)) != NOERROR) {MY_LOG(TAG_CLIENT, "connect error.");goto lb_err;}//MY_LOG(TAG_CLIENT, "connect ok.");if (SSL_set_fd(ssl, fd) != SSL_SUCCESS) {MY_LOG(TAG_CLIENT, "SSL_set_fd error.");goto lb_err;}if (SSL_connect(ssl) != SSL_SUCCESS) {MY_LOG(TAG_CLIENT, "SSL_connect error.");goto lb_err;}//MY_LOG(TAG_CLIENT, "connected with %s encryption.", SSL_get_cipher(ssl));if (callback)ret = callback(ssl, udata);ret = true;lb_err:if (ssl) {SSL_shutdown(ssl);SSL_free(ssl);}if (fd) closesocket(fd);if (ctx) SSL_CTX_free(ctx);return ret;}bool http_get(const char *urlstr, void *udata, std::function<void(const char *data, int32_t size, void *udata)> callback) {std::string hostname, path;uint16_t port;if (!parse_url(urlstr, &hostname, &path, &port))return false;char header[1024 * 8];sprintf(header,"GET %s HTTP/1.1 \r\n""Host: %s \r\n""User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0 \r\n""Accept-Type: */* \r\n""Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 \r\n""Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 \r\n""Connection: Close \r\n\r\n", path.c_str(), hostname.c_str());return client(hostname.c_str(), port, udata, [&] (SSL *ssl, void *udata) -> bool {int header_len = strlen(header);int ret = SSL_write(ssl, header, header_len);if (ret != header_len) return false;if (!callback) return true;char buf[MY_BUFFER_SIZE];while (true) {ret = SSL_read(ssl, buf, MY_BUFFER_SIZE);if (ret <= 0) break;callback(buf, ret, udata);}return true;});}typedef struct {SOCKET fd;SSL *ssl;} conn_t;bool server(const char *cert_file, const char *key_file, uint16_t port, void *udata, std::function<bool(conn_t *conn, void *udata)> callback) {bool ret = false;SSL_CTX *ctx = 0;SOCKET fd_listen;sockaddr_in addr = { 0 };if (!cert_file || !key_file) return false;if (!callback) return false;SSL_library_init();OpenSSL_add_all_algorithms();SSL_load_error_strings();ctx = SSL_CTX_new(SSLv23_server_method());if (!ctx) {MY_LOG(TAG_SERVER, "ssl create ctx error.");goto lb_err;}if (SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM) != SSL_SUCCESS) {MY_LOG(TAG_SERVER, "ssl load cert file error.");goto lb_err;}if (SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM) != SSL_SUCCESS) {MY_LOG(TAG_SERVER, "ssl load key file error.");goto lb_err;}if (SSL_CTX_check_private_key(ctx) != SSL_SUCCESS) {MY_LOG(TAG_SERVER, "ssl check key error.");goto lb_err;}SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);fd_listen = socket(AF_INET, SOCK_STREAM, 0);if (fd_listen < 0) {MY_LOG(TAG_SERVER, "create socket error.");goto lb_err;}addr.sin_family = AF_INET;addr.sin_addr.S_un.S_addr = INADDR_ANY;addr.sin_port = htons(port);if (bind(fd_listen, (const sockaddr*)&addr, sizeof(SOCKADDR_IN)) != NOERROR) {MY_LOG(TAG_SERVER, "bind error.");goto lb_err;}if (listen(fd_listen, 5) != NOERROR) {MY_LOG(TAG_SERVER, "listen error.");goto lb_err;}MY_LOG(TAG_SERVER, "listen in 0.0.0.0:%d.", port);bool quit = false;while (!quit) {SSL *ssl = 0;bool is_ssl = false;char handshake[8];conn_t conn = { 0 };struct sockaddr_in addr_from;socklen_t addr_from_len = sizeof(addr_from);SOCKET fd_conn = accept(fd_listen, (struct sockaddr *)&addr_from, &addr_from_len);if (fd_conn < 0) {MY_LOG(TAG_SERVER, "accept error.");goto lb_finish;}int ret = recv(fd_conn, (char*)&handshake, sizeof(handshake), MSG_PEEK);if (ret < 0) {MY_LOG(TAG_SERVER, "recv error.");goto lb_finish;} else if (ret == 0) {MY_LOG(TAG_SERVER, "close fd %d.", (int)fd_conn);goto lb_finish;} else {if ((unsigned char)handshake[0] == 0x16 // content type&& (unsigned char)handshake[5] == 0x01) { // handshake typeis_ssl = true;}MY_LOG(TAG_SERVER, "check is ssl: %d", is_ssl);show_hex((const char*)&handshake, ret);}if (is_ssl) {ssl = SSL_new(ctx);if (!ssl) {MY_LOG(TAG_SERVER, "SSL_new error.");goto lb_finish;}if (SSL_set_fd(ssl, fd_conn) != SSL_SUCCESS) {MY_LOG(TAG_SERVER, "SSL_set_fd error.");goto lb_finish;}if (SSL_accept(ssl) != SSL_SUCCESS) {MY_LOG(TAG_SERVER, "SSL_accept error.");goto lb_finish;}conn.fd = fd_conn;conn.ssl = ssl;} else {conn.fd = fd_conn;}quit = !callback(&conn, udata);lb_finish:if (ssl) {SSL_shutdown(ssl);SSL_free(ssl);}if (fd_conn >= 0) closesocket(fd_conn);}lb_err:if (fd_listen >= 0) closesocket(fd_listen);if (ctx) SSL_CTX_free(ctx);return ret;}bool tcp_echo(const char *cert_file, const char *key_file, uint16_t port) {return server(cert_file, key_file, port, 0, [](conn_t *conn, void *udata) -> bool {char buf[MY_BUFFER_SIZE];while (true) {int ret = SSL_read(conn->ssl, buf, MY_BUFFER_SIZE);if (ret <= 0) break;printf("%.*s", ret, buf);SSL_write(conn->ssl, buf, ret);}return true;});}str_t parse_request(const char *req) {str_t ret = { 0 };if (!req || !*req) return ret;// GET /?url=https://www.baidu.com?a=1&b=2 HTTP/1.1if (strncmp(req, "GET /", 5) != 0) return ret;const char *bp = req + 4;const char *ep = strchr(bp, ' ');if (!ep) return ret;ret.data = bp;ret.size = ep - bp;return ret;}int user_main(int argc, char *argv[]) {if (argc != 5) {MY_LOG(TAG_MAIN, "#> https <cert file> <cert key> <port> <dest>");MY_LOG(TAG_MAIN, "such as: https server.cert server.key 8888 https://s.dzlua.top");return 0;}const char *crt = argv[1];const char *key = argv[2];uint16_t port = atoi(argv[3]);const char *dest = argv[4];bool ok = server(crt, key, port, (void*)dest, [](conn_t *conn, void *udata) -> bool {std::string strRecv;printf("---------- begin ----------\n");printf("is ssl: %s\n", (conn->ssl ? "true" : "false"));if (conn->ssl) {std::string path;char buf[MY_BUFFER_SIZE];while (true) {int ret = SSL_read(conn->ssl, buf, MY_BUFFER_SIZE);if (ret <= 0) break;strRecv.append(buf, ret);printf("%.*s", ret, buf);str_t tmp = parse_request(strRecv.c_str());path.assign(tmp.data, tmp.size);if (!path.empty()) break;}printf("\n----------\n");path = (const char*)udata + path;http_get(path.c_str(), conn->ssl, [](const char *data, int32_t size, void *udata) {printf("%.*s", size, data);SSL_write((SSL*)udata, data, size);});} else {return true;}printf("\n---------- end ----------\n");return true;});return 0;}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。