diff --git a/conev.h b/conev.h index 4a8d928..f98a59e 100644 --- a/conev.h +++ b/conev.h @@ -78,8 +78,11 @@ struct eval { struct sockaddr_in6 in6; }; ssize_t recv_count; + unsigned int round_count; + char last_round; int attempt; char cache; + char mark; // }; struct poolhd { diff --git a/extend.c b/extend.c index d1a2df6..5f6db8b 100644 --- a/extend.c +++ b/extend.c @@ -49,28 +49,50 @@ int mode_add_get(struct sockaddr_ina *dst, int m) { // m < 0: get, m > 0: set, m == 0: delete assert(m >= -1 && m < params.dp_count); + struct { + uint16_t port; + union { + struct in_addr i4; + struct in6_addr i6; + }; + } key = { .port = dst->in.sin_port }; time_t t = 0; struct elem *val = 0; - char *str = (char *)&dst->in; - int len = 0; + int len = sizeof(dst->in.sin_port); if (dst->sa.sa_family == AF_INET) { - len = sizeof(dst->in); + len += sizeof(dst->in.sin_addr); + key.i4 = dst->in.sin_addr; } else { - len = sizeof(dst->in6) - sizeof(dst->in6.sin6_scope_id); + len += sizeof(dst->in6.sin6_addr); + key.i6 = dst->in6.sin6_addr; } - len -= sizeof(dst->sa.sa_family); - assert(len > 0); + + if (m < 0) { + val = mem_get(params.mempool, (char *)&key, len); + if (!val) { + return -1; + } + time(&t); + if (t > val->time + params.cache_ttl) { + LOG(LOG_S, "time=%jd, now=%jd, ignore\n", (intmax_t)val->time, (intmax_t)t); + return 0; + } + return val->m; + } + INIT_ADDR_STR((*dst)); if (m == 0) { - mem_delete(params.mempool, str, len); + LOG(LOG_S, "delete ip: %s\n", ADDR_STR); + mem_delete(params.mempool, (char *)&key, len); return 0; } - else if (m > 0) { + else { + LOG(LOG_S, "save ip: %s, m=%d\n", ADDR_STR, m); time(&t); - val = mem_add(params.mempool, str, len); + val = mem_add(params.mempool, (char *)&key, len); if (!val) { uniperror("mem_add"); return -1; @@ -79,16 +101,7 @@ int mode_add_get(struct sockaddr_ina *dst, int m) val->time = t; return 0; } - val = mem_get(params.mempool, str, len); - if (!val) { - return -1; - } - time(&t); - if (t > val->time + params.cache_ttl) { - LOG(LOG_S, "time=%jd, now=%jd, ignore\n", (intmax_t)val->time, (intmax_t)t); - return 0; - } - return val->m; + } @@ -188,21 +201,36 @@ int on_torst(struct poolhd *pool, struct eval *val) { int m = val->pair->attempt + 1; - for (; m < params.dp_count; m++) { - struct desync_params *dp = ¶ms.dp[m]; - if (!dp->detect) { - return -1; + bool can_reconn = ( + val->pair->buff.data && !val->recv_count + ); + if (can_reconn || params.auto_level >= 1) { + for (; m < params.dp_count; m++) { + struct desync_params *dp = ¶ms.dp[m]; + if (!dp->detect) { + return -1; + } + if (dp->detect & DETECT_TORST) { + break; + } } - if (dp->detect & DETECT_TORST) { - break; + if (m >= params.dp_count) { + if (m > 1) mode_add_get( + (struct sockaddr_ina *)&val->in6, 0); } + else if (can_reconn) + return reconnect(pool, val, m); + else + mode_add_get( + (struct sockaddr_ina *)&val->in6, m); } - if (m >= params.dp_count) { - mode_add_get( - (struct sockaddr_ina *)&val->in6, 0); + struct linger l = { .l_onoff = 1 }; + if (setsockopt(val->pair->fd, SOL_SOCKET, + SO_LINGER, (char *)&l, sizeof(l)) < 0) { + uniperror("setsockopt SO_LINGER"); return -1; } - return reconnect(pool, val, m); + return -1; } @@ -210,21 +238,44 @@ int on_fin(struct poolhd *pool, struct eval *val) { int m = val->pair->attempt + 1; + bool can_reconn = ( + val->pair->buff.data && !val->recv_count + ); + if (!can_reconn && params.auto_level < 1) { + return -1; + } + bool ssl_err = 0; + + if (can_reconn) { + char *req = val->pair->buff.data; + ssize_t qn = val->pair->buff.size; + + ssl_err = is_tls_chello(req, qn); + } + else if (val->mark && val->round_count <= 1) { + ssl_err = 1; + } + if (!ssl_err) { + return -1; + } for (; m < params.dp_count; m++) { struct desync_params *dp = ¶ms.dp[m]; if (!dp->detect) { return -1; } - if (!(dp->detect & DETECT_TLS_ERR)) { - continue; + if (dp->detect & DETECT_TLS_ERR) { + if (can_reconn) + return reconnect(pool, val, m); + else { + mode_add_get( + (struct sockaddr_ina *)&val->in6, m); + return -1; + } } - char *req = val->pair->buff.data; - ssize_t qn = val->pair->buff.size; - - if (!is_tls_chello(req, qn)) { - continue; - } - return reconnect(pool, val, m); + } + if (m > 1) { // delete + mode_add_get( + (struct sockaddr_ina *)&val->in6, 0); } return -1; } @@ -279,20 +330,25 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val, assert(!out); ssize_t n = recv(val->fd, buffer, bfsize, 0); if (n < 1) { - if (n) uniperror("recv"); + if (!n) { + return on_fin(pool, val); + } + uniperror("recv"); switch (get_e()) { case ECONNRESET: case ECONNREFUSED: case ETIMEDOUT: return on_torst(pool, val); } - return on_fin(pool, val); + return -1; } // if (on_response(pool, val, buffer, n) == 0) { return 0; } val->recv_count += n; + val->round_count = 1; + val->last_round = 1; struct eval *pair = val->pair; ssize_t sn = send(pair->fd, buffer, n, 0); @@ -300,9 +356,12 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val, uniperror("send"); return -1; } + if (params.auto_level > 0 && params.dp_count > 1) { + val->mark = is_tls_chello(pair->buff.data, pair->buff.size); + } to_tunnel(pair); - if (params.timeout && + if (params.timeout && params.auto_level < 1 && set_timeout(val->fd, 0)) { return -1; } @@ -315,15 +374,7 @@ int on_tunnel_check(struct poolhd *pool, struct eval *val, if (!pair->cache) { return 0; } - struct sockaddr_ina *addr = (struct sockaddr_ina *)&val->in6; - - if (m == 0) { - LOG(LOG_S, "delete ip: m=%d\n", m); - } else { - INIT_ADDR_STR((*addr)); - LOG(LOG_S, "save ip: %s, m=%d\n", ADDR_STR, m); - } - return mode_add_get(addr, m); + return mode_add_get((struct sockaddr_ina *)&val->in6, m); } @@ -385,6 +436,7 @@ int on_desync(struct poolhd *pool, struct eval *val, } val->buff.size += n; val->recv_count += n; + val->round_count = 1; val->buff.data = realloc(val->buff.data, val->buff.size); if (val->buff.data == 0) { diff --git a/extend.h b/extend.h index 36bce5b..439b4e3 100644 --- a/extend.h +++ b/extend.h @@ -19,6 +19,10 @@ int on_desync(struct poolhd *pool, struct eval *val, ssize_t udp_hook(struct eval *val, char *buffer, size_t bfsize, ssize_t n, struct sockaddr_ina *dst); +int on_torst(struct poolhd *pool, struct eval *val); + +int on_fin(struct poolhd *pool, struct eval *val); + #ifdef __linux__ int protect(int conn_fd, const char *path); #else diff --git a/main.c b/main.c index a299b73..6a8bc54 100644 --- a/main.c +++ b/main.c @@ -54,7 +54,8 @@ struct params params = { .laddr = { .sin6_family = AF_INET }, - .debug = 0 + .debug = 0, + .auto_level = 0 }; @@ -77,6 +78,7 @@ const char help_text[] = { #endif " -A, --auto Try desync params after this option\n" " Detect: torst,redirect,ssl_err,none\n" + " -L, --auto-mode <0|1> 1 - handle trigger after several packets\n" " -u, --cache-ttl Lifetime of cached desync params for IP\n" #ifdef TIMEOUT_SUPPORT " -T, --timeout Timeout waiting for response, after which trigger auto\n" @@ -131,6 +133,7 @@ const struct option options[] = { {"tfo ", 0, 0, 'F'}, #endif {"auto", 1, 0, 'A'}, + {"auto-mode", 1, 0, 'L'}, {"cache-ttl", 1, 0, 'u'}, #ifdef TIMEOUT_SUPPORT {"timeout", 1, 0, 'T'}, @@ -561,6 +564,14 @@ int main(int argc, char **argv) params.tfo = 1; break; + case 'L': + val = strtol(optarg, &end, 0); + if (val < 0 || val > 1 || *end) + invalid = 1; + else + params.auto_level = val; + break; + case 'A': dp = add((void *)¶ms.dp, ¶ms.dp_count, sizeof(struct desync_params)); diff --git a/params.h b/params.h index 13a27fc..02992f6 100644 --- a/params.h +++ b/params.h @@ -96,6 +96,7 @@ struct params { char tfo; unsigned int timeout; + int auto_level; long cache_ttl; char ipv6; char resolve; diff --git a/proxy.c b/proxy.c index ed9e343..b1c4698 100644 --- a/proxy.c +++ b/proxy.c @@ -667,11 +667,30 @@ int on_tunnel(struct poolhd *pool, struct eval *val, if (n < 0 && get_e() == EAGAIN) { break; } - if (n < 1) { - if (n) uniperror("recv"); + if (n == 0) { + if (val->flag != FLAG_CONN) + val = val->pair; + on_fin(pool, val); + return -1; + } + if (n < 0) { + uniperror("recv"); + switch (get_e()) { + case ECONNRESET: + case ETIMEDOUT: + if (val->flag == FLAG_CONN) + on_torst(pool, val); + else + on_fin(pool, val->pair); + } return -1; } val->recv_count += n; + if (!val->last_round) { + val->round_count++; + val->last_round = 1; + pair->last_round = 0; + } ssize_t sn = send(pair->fd, buffer, n, 0); if (sn != n) { @@ -893,7 +912,10 @@ static inline int on_connect(struct poolhd *pool, struct eval *val, int e) void close_conn(struct poolhd *pool, struct eval *val) { - LOG(LOG_S, "close: fds=%d,%d\n", val->fd, val->pair ? val->pair->fd : -1); + LOG(LOG_S, "close: fds=%d,%d, recv: %zd,%zd, rounds: %d,%d\n", + val->fd, val->pair ? val->pair->fd : -1, + val->recv_count, val->pair ? val->pair->recv_count : 0, + val->round_count, val->pair ? val->pair->round_count : 0); del_event(pool, val); }