diff --git a/app/app.iml b/app/app.iml index 9449018a..4c1ac093 100644 --- a/app/app.iml +++ b/app/app.iml @@ -100,7 +100,6 @@ - diff --git a/app/src/main/jni/netguard/icmp.c b/app/src/main/jni/netguard/icmp.c index 78941cc7..e3313b55 100644 --- a/app/src/main/jni/netguard/icmp.c +++ b/app/src/main/jni/netguard/icmp.c @@ -22,6 +22,58 @@ extern struct icmp_session *icmp_session; extern FILE *pcap_file; +int check_icmp_sessions(const struct arguments *args) { + time_t now = time(NULL); + + int count = 0; + struct icmp_session *ic = icmp_session; + while (ic != NULL) { + if (!ic->stop) + count++; + ic = ic->next; + } + + struct icmp_session *il = NULL; + struct icmp_session *i = icmp_session; + while (i != NULL) { + int timeout = ICMP_TIMEOUT; + if (i->stop || i->time + timeout < now) { + char source[INET6_ADDRSTRLEN + 1]; + char dest[INET6_ADDRSTRLEN + 1]; + if (i->version == 4) { + inet_ntop(AF_INET, &i->saddr.ip4, source, sizeof(source)); + inet_ntop(AF_INET, &i->daddr.ip4, dest, sizeof(dest)); + } + else { + inet_ntop(AF_INET6, &i->saddr.ip6, source, sizeof(source)); + inet_ntop(AF_INET6, &i->daddr.ip6, dest, sizeof(dest)); + } + log_android(ANDROID_LOG_WARN, "ICMP idle %d/%d sec stop %d from %s to %s", + now - i->time, timeout, i->stop, dest, source); + + if (close(i->socket)) + log_android(ANDROID_LOG_ERROR, "ICMP close %d error %d: %s", + i->socket, errno, strerror(errno)); + i->socket = -1; + + if (il == NULL) + icmp_session = i->next; + else + il->next = i->next; + + struct icmp_session *c = i; + i = i->next; + free(c); + } + else { + il = i; + i = i->next; + } + } + + return count; +} + void check_icmp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds, fd_set *efds) { struct icmp_session *cur = icmp_session; while (cur != NULL) { diff --git a/app/src/main/jni/netguard/netguard.h b/app/src/main/jni/netguard/netguard.h index 80a8439f..1e3f9584 100644 --- a/app/src/main/jni/netguard/netguard.h +++ b/app/src/main/jni/netguard/netguard.h @@ -48,7 +48,7 @@ #define TCP_SEND_WINDOW 16384 // bytes (maximum) #define TCP_INIT_TIMEOUT 30 // seconds ~net.inet.tcp.keepinit #define TCP_IDLE_TIMEOUT 300 // seconds ~net.inet.tcp.keepidle -#define TCP_CLOSE_TIMEOUT 3 // seconds +#define TCP_CLOSE_TIMEOUT 30 // seconds #define TCP_KEEP_TIMEOUT 300 // seconds #define TCP_TIMEOUT_SCALE 50 // https://en.wikipedia.org/wiki/Maximum_segment_lifetime @@ -291,7 +291,11 @@ void report_exit(const struct arguments *args, const char *fmt, ...); void check_allowed(const struct arguments *args); -void check_sessions(const struct arguments *args, int isessions, int usessions, int tsessions); +int check_icmp_sessions(const struct arguments *args); + +int check_udp_sessions(const struct arguments *args); + +int check_tcp_sessions(const struct arguments *args); int get_select_timeout(int isessions, int usessions, int tsessions); diff --git a/app/src/main/jni/netguard/session.c b/app/src/main/jni/netguard/session.c index 9a5729e5..07907319 100644 --- a/app/src/main/jni/netguard/session.c +++ b/app/src/main/jni/netguard/session.c @@ -126,31 +126,11 @@ void *handle_events(void *a) { while (!stopping) { log_android(ANDROID_LOG_DEBUG, "Loop thread %x", thread_id); - // Count sessions - int isessions = 0; - struct icmp_session *i = icmp_session; - while (i != NULL) { - if (!i->stop) - isessions++; - i = i->next; - } - int usessions = 0; - struct udp_session *u = udp_session; - while (u != NULL) { - if (u->state == UDP_ACTIVE) - usessions++; - u = u->next; - } - int tsessions = 0; - struct tcp_session *t = tcp_session; - while (t != NULL) { - if (t->state != TCP_CLOSING && t->state != TCP_CLOSE) - tsessions++; - t = t->next; - } - // Check sessions - check_sessions(args, isessions, usessions, tsessions); + int isessions = check_icmp_sessions(args); + int usessions = check_udp_sessions(args); + int tsessions = check_tcp_sessions(args); + // https://bugzilla.mozilla.org/show_bug.cgi?id=1093893 int idle = (tsessions + usessions + tsessions == 0 && sdk >= 16); log_android(ANDROID_LOG_DEBUG, "sessions ICMP %d UDP %d TCP %d idle %d sdk %d", @@ -469,172 +449,3 @@ void check_allowed(const struct arguments *args) { } } -void check_sessions(const struct arguments *args, int isessions, int usessions, int tsessions) { - time_t now = time(NULL); - - // Check ICMP sessions - struct icmp_session *il = NULL; - struct icmp_session *i = icmp_session; - while (i != NULL) { - int timeout = ICMP_TIMEOUT; - if (i->stop || i->time + timeout < now) { - char source[INET6_ADDRSTRLEN + 1]; - char dest[INET6_ADDRSTRLEN + 1]; - if (i->version == 4) { - inet_ntop(AF_INET, &i->saddr.ip4, source, sizeof(source)); - inet_ntop(AF_INET, &i->daddr.ip4, dest, sizeof(dest)); - } - else { - inet_ntop(AF_INET6, &i->saddr.ip6, source, sizeof(source)); - inet_ntop(AF_INET6, &i->daddr.ip6, dest, sizeof(dest)); - } - log_android(ANDROID_LOG_WARN, "ICMP idle %d/%d sec stop %d from %s to %s", - now - i->time, timeout, i->stop, dest, source); - - if (close(i->socket)) - log_android(ANDROID_LOG_ERROR, "ICMP close %d error %d: %s", - i->socket, errno, strerror(errno)); - i->socket = -1; - - if (il == NULL) - icmp_session = i->next; - else - il->next = i->next; - - struct icmp_session *c = i; - i = i->next; - free(c); - } - else { - il = i; - i = i->next; - } - } - - // Check UDP sessions - struct udp_session *ul = NULL; - struct udp_session *u = udp_session; - while (u != NULL) { - char source[INET6_ADDRSTRLEN + 1]; - char dest[INET6_ADDRSTRLEN + 1]; - if (u->version == 4) { - inet_ntop(AF_INET, &u->saddr.ip4, source, sizeof(source)); - inet_ntop(AF_INET, &u->daddr.ip4, dest, sizeof(dest)); - } - else { - inet_ntop(AF_INET6, &u->saddr.ip6, source, sizeof(source)); - inet_ntop(AF_INET6, &u->daddr.ip6, dest, sizeof(dest)); - } - - // Check session timeout - int timeout = get_udp_timeout(u, usessions); - if (u->state == UDP_ACTIVE && u->time + timeout < now) { - log_android(ANDROID_LOG_WARN, "UDP idle %d/%d sec state %d from %s/%u to %s/%u", - now - u->time, timeout, u->state, - source, ntohs(u->source), dest, ntohs(u->dest)); - u->state = UDP_FINISHING; - } - - // Check finished sessions - if (u->state == UDP_FINISHING) { - log_android(ANDROID_LOG_INFO, "UDP close from %s/%u to %s/%u socket %d", - source, ntohs(u->source), dest, ntohs(u->dest), u->socket); - - if (close(u->socket)) - log_android(ANDROID_LOG_ERROR, "UDP close %d error %d: %s", - u->socket, errno, strerror(errno)); - u->socket = -1; - - u->time = time(NULL); - u->state = UDP_CLOSED; - } - - // Cleanup lingering sessions - if ((u->state == UDP_CLOSED || u->state == UDP_BLOCKED) && - u->time + UDP_KEEP_TIMEOUT < now) { - if (ul == NULL) - udp_session = u->next; - else - ul->next = u->next; - - struct udp_session *c = u; - u = u->next; - free(c); - } - else { - ul = u; - u = u->next; - } - } - - // Check TCP sessions - struct tcp_session *tl = NULL; - struct tcp_session *t = tcp_session; - while (t != NULL) { - char source[INET6_ADDRSTRLEN + 1]; - char dest[INET6_ADDRSTRLEN + 1]; - if (t->version == 4) { - inet_ntop(AF_INET, &t->saddr.ip4, source, sizeof(source)); - inet_ntop(AF_INET, &t->daddr.ip4, dest, sizeof(dest)); - } else { - inet_ntop(AF_INET6, &t->saddr.ip6, source, sizeof(source)); - inet_ntop(AF_INET6, &t->daddr.ip6, dest, sizeof(dest)); - } - - char session[250]; - sprintf(session, "TCP socket from %s/%u to %s/%u %s socket %d", - source, ntohs(t->source), dest, ntohs(t->dest), strstate(t->state), t->socket); - - // Check session timeout - int timeout = get_tcp_timeout(t, tsessions); - if (t->state != TCP_CLOSING && t->state != TCP_CLOSE && t->time + timeout < now) { - // TODO send keep alives? - log_android(ANDROID_LOG_WARN, "%s idle %d/%d sec ", - session, now - t->time, timeout); - if (t->state == TCP_CLOSE_WAIT && t->forward == NULL) { - t->remote_seq++; // remote FIN - if (write_fin_ack(args, t) >= 0) { - log_android(ANDROID_LOG_WARN, "%s finished idle", session); - t->local_seq++; // local FIN - t->state = TCP_LAST_ACK; - } - } - else { - log_android(ANDROID_LOG_WARN, "%s reset idle", session); - write_rst(args, t); - } - } - - // Check closing sessions - if (t->state == TCP_CLOSING) { - if (t->socket >= 0) { - if (close(t->socket)) - log_android(ANDROID_LOG_ERROR, "%s close error %d: %s", - session, errno, strerror(errno)); - else - log_android(ANDROID_LOG_WARN, "%s close", session); - t->socket = -1; - } - - t->time = time(NULL); - t->state = TCP_CLOSE; - } - - // Cleanup lingering sessions - if (t->state == TCP_CLOSE && t->time + TCP_KEEP_TIMEOUT < now) { - if (tl == NULL) - tcp_session = t->next; - else - tl->next = t->next; - - struct tcp_session *c = t; - t = t->next; - clear_tcp_data(c); - free(c); - } - else { - tl = t; - t = t->next; - } - } -} diff --git a/app/src/main/jni/netguard/tcp.c b/app/src/main/jni/netguard/tcp.c index 298dd3e3..585bd7be 100644 --- a/app/src/main/jni/netguard/tcp.c +++ b/app/src/main/jni/netguard/tcp.c @@ -39,6 +39,90 @@ int get_tcp_timeout(const struct tcp_session *t, int sessions) { return timeout; } +int check_tcp_sessions(const struct arguments *args) { + time_t now = time(NULL); + + int count = 0; + struct tcp_session *tc = tcp_session; + while (tc != NULL) { + if (tc->state != TCP_CLOSING && tc->state != TCP_CLOSE) + count++; + tc = tc->next; + } + + struct tcp_session *tl = NULL; + struct tcp_session *t = tcp_session; + while (t != NULL) { + char source[INET6_ADDRSTRLEN + 1]; + char dest[INET6_ADDRSTRLEN + 1]; + if (t->version == 4) { + inet_ntop(AF_INET, &t->saddr.ip4, source, sizeof(source)); + inet_ntop(AF_INET, &t->daddr.ip4, dest, sizeof(dest)); + } else { + inet_ntop(AF_INET6, &t->saddr.ip6, source, sizeof(source)); + inet_ntop(AF_INET6, &t->daddr.ip6, dest, sizeof(dest)); + } + + char session[250]; + sprintf(session, "TCP socket from %s/%u to %s/%u %s socket %d", + source, ntohs(t->source), dest, ntohs(t->dest), strstate(t->state), t->socket); + + // Check session timeout + int timeout = get_tcp_timeout(t, count); + if (t->state != TCP_CLOSING && t->state != TCP_CLOSE && t->time + timeout < now) { + // TODO send keep alives? + log_android(ANDROID_LOG_WARN, "%s idle %d/%d sec ", + session, now - t->time, timeout); + if (t->state == TCP_CLOSE_WAIT && t->forward == NULL) { + t->remote_seq++; // remote FIN + if (write_fin_ack(args, t) >= 0) { + log_android(ANDROID_LOG_WARN, "%s finished idle", session); + t->local_seq++; // local FIN + t->state = TCP_LAST_ACK; + } + } + else { + log_android(ANDROID_LOG_WARN, "%s reset idle", session); + write_rst(args, t); + } + } + + // Check closing sessions + if (t->state == TCP_CLOSING) { + if (t->socket >= 0) { + if (close(t->socket)) + log_android(ANDROID_LOG_ERROR, "%s close error %d: %s", + session, errno, strerror(errno)); + else + log_android(ANDROID_LOG_WARN, "%s close", session); + t->socket = -1; + } + + t->time = time(NULL); + t->state = TCP_CLOSE; + } + + // Cleanup lingering sessions + if (t->state == TCP_CLOSE && t->time + TCP_KEEP_TIMEOUT < now) { + if (tl == NULL) + tcp_session = t->next; + else + tl->next = t->next; + + struct tcp_session *c = t; + t = t->next; + clear_tcp_data(c); + free(c); + } + else { + tl = t; + t = t->next; + } + } + + return count; +} + void check_tcp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds, fd_set *efds) { struct tcp_session *cur = tcp_session; while (cur != NULL) { diff --git a/app/src/main/jni/netguard/udp.c b/app/src/main/jni/netguard/udp.c index b6835ed6..eef7893d 100644 --- a/app/src/main/jni/netguard/udp.c +++ b/app/src/main/jni/netguard/udp.c @@ -33,6 +33,75 @@ int get_udp_timeout(const struct udp_session *u, int sessions) { return timeout; } +int check_udp_sessions(const struct arguments *args) { + time_t now = time(NULL); + + int count = 0; + struct udp_session *uc = udp_session; + while (uc != NULL) { + if (uc->state == UDP_ACTIVE) + count++; + uc = uc->next; + } + + struct udp_session *ul = NULL; + struct udp_session *u = udp_session; + while (u != NULL) { + char source[INET6_ADDRSTRLEN + 1]; + char dest[INET6_ADDRSTRLEN + 1]; + if (u->version == 4) { + inet_ntop(AF_INET, &u->saddr.ip4, source, sizeof(source)); + inet_ntop(AF_INET, &u->daddr.ip4, dest, sizeof(dest)); + } + else { + inet_ntop(AF_INET6, &u->saddr.ip6, source, sizeof(source)); + inet_ntop(AF_INET6, &u->daddr.ip6, dest, sizeof(dest)); + } + + // Check session timeout + int timeout = get_udp_timeout(u, count); + if (u->state == UDP_ACTIVE && u->time + timeout < now) { + log_android(ANDROID_LOG_WARN, "UDP idle %d/%d sec state %d from %s/%u to %s/%u", + now - u->time, timeout, u->state, + source, ntohs(u->source), dest, ntohs(u->dest)); + u->state = UDP_FINISHING; + } + + // Check finished sessions + if (u->state == UDP_FINISHING) { + log_android(ANDROID_LOG_INFO, "UDP close from %s/%u to %s/%u socket %d", + source, ntohs(u->source), dest, ntohs(u->dest), u->socket); + + if (close(u->socket)) + log_android(ANDROID_LOG_ERROR, "UDP close %d error %d: %s", + u->socket, errno, strerror(errno)); + u->socket = -1; + + u->time = time(NULL); + u->state = UDP_CLOSED; + } + + // Cleanup lingering sessions + if ((u->state == UDP_CLOSED || u->state == UDP_BLOCKED) && + u->time + UDP_KEEP_TIMEOUT < now) { + if (ul == NULL) + udp_session = u->next; + else + ul->next = u->next; + + struct udp_session *c = u; + u = u->next; + free(c); + } + else { + ul = u; + u = u->next; + } + } + + return count; +} + void check_udp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds, fd_set *efds) { struct udp_session *cur = udp_session; while (cur != NULL) {