diff --git a/openwrt/Makefile b/openwrt/Makefile index 4fce8dbe..e8f977cb 100644 --- a/openwrt/Makefile +++ b/openwrt/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=UA2F -PKG_VERSION:=4.4.0 +PKG_VERSION:=4.4.1 PKG_RELEASE:=1 PKG_LICENSE:=GPL-3.0-only diff --git a/src/handler.c b/src/handler.c index dbdc9421..18969780 100644 --- a/src/handler.c +++ b/src/handler.c @@ -226,7 +226,7 @@ void handle_packet(struct nf_queue *queue, struct nf_packet *pkt) { __auto_type tcp_hdr = nfq_tcp_get_hdr(pkt_buff); if (tcp_hdr == NULL) { - // This packet is not tcp, just pass it + // This packet is not tcp, pass it send_verdict(queue, pkt, (struct mark_op) {false, 0}, NULL); syslog(LOG_WARNING, "Received non-tcp packet. You may set wrong firewall rules."); goto end; @@ -239,8 +239,21 @@ void handle_packet(struct nf_queue *queue, struct nf_packet *pkt) { send_verdict(queue, pkt, get_next_mark(pkt, false), NULL); goto end; } + count_tcp_packet(); + // cannot find User-Agent: in this packet + if (tcp_payload_len - 2 < USER_AGENT_MATCH_LENGTH) { + send_verdict(queue, pkt, get_next_mark(pkt, false), NULL); + goto end; + } + + if (!is_http_protocol(tcp_payload, tcp_payload_len)) { + send_verdict(queue, pkt, get_next_mark(pkt, false), NULL); + goto end; + } + count_http_packet(); + void *search_start = tcp_payload; unsigned int search_length = tcp_payload_len; bool has_ua = false; @@ -298,4 +311,14 @@ void handle_packet(struct nf_queue *queue, struct nf_packet *pkt) { } try_print_statistics(); -} \ No newline at end of file +} + +#undef MAX_USER_AGENT_LENGTH +#undef USER_AGENT_MATCH_LENGTH + +#undef CONNMARK_ESTIMATE_LOWER +#undef CONNMARK_ESTIMATE_UPPER +#undef CONNMARK_ESTIMATE_VERDICT + +#undef CONNMARK_NOT_HTTP +#undef CONNMARK_HTTP \ No newline at end of file diff --git a/src/statistics.c b/src/statistics.c index 0e1b5500..c72bc21a 100644 --- a/src/statistics.c +++ b/src/statistics.c @@ -5,7 +5,9 @@ #include "statistics.h" static long long user_agent_packet_count = 0; +static long long http_packet_count = 0; static long long tcp_packet_count = 0; + static long long ipv4_packet_count = 0; static long long ipv6_packet_count = 0; static long long last_report_count = 4; @@ -25,6 +27,10 @@ void count_tcp_packet() { tcp_packet_count++; } +void count_http_packet() { + http_packet_count++; +} + void count_ipv4_packet() { ipv4_packet_count++; } @@ -33,33 +39,34 @@ void count_ipv6_packet() { ipv6_packet_count++; } -static char TimeStringBuffer[60]; +static char time_string_buffer[100]; char *fill_time_string(double sec) { int s = (int) sec; - memset(TimeStringBuffer, 0, sizeof(TimeStringBuffer)); + memset(time_string_buffer, 0, sizeof(time_string_buffer)); if (s <= 60) { - sprintf(TimeStringBuffer, "%d seconds", s); + sprintf(time_string_buffer, "%d seconds", s); } else if (s <= 3600) { - sprintf(TimeStringBuffer, "%d minutes and %d seconds", s / 60, s % 60); + sprintf(time_string_buffer, "%d minutes and %d seconds", s / 60, s % 60); } else if (s <= 86400) { - sprintf(TimeStringBuffer, "%d hours, %d minutes and %d seconds", s / 3600, s % 3600 / 60, s % 60); + sprintf(time_string_buffer, "%d hours, %d minutes and %d seconds", s / 3600, s % 3600 / 60, s % 60); } else { - sprintf(TimeStringBuffer, "%d days, %d hours, %d minutes and %d seconds", s / 86400, s % 86400 / 3600, + sprintf(time_string_buffer, "%d days, %d hours, %d minutes and %d seconds", s / 86400, s % 86400 / 3600, s % 3600 / 60, s % 60); } - return TimeStringBuffer; + return time_string_buffer; } void try_print_statistics() { - if (user_agent_packet_count / last_report_count == 2 || user_agent_packet_count - last_report_count >= 16384) { + if (user_agent_packet_count / last_report_count == 2 || user_agent_packet_count - last_report_count >= 8192) { last_report_count = user_agent_packet_count; time_t current_t = time(NULL); syslog( LOG_INFO, - "UA2F has handled %lld ua http, %lld tcp. %lld ipv4, %lld ipv6 packets in %s.", + "UA2F has handled %lld ua http, %lld http, %lld tcp. %lld ipv4, %lld ipv6 packets in %s.", user_agent_packet_count, + http_packet_count, tcp_packet_count, ipv4_packet_count, ipv6_packet_count, diff --git a/src/statistics.h b/src/statistics.h index a1dc195e..a22d4f18 100644 --- a/src/statistics.h +++ b/src/statistics.h @@ -9,6 +9,8 @@ void count_ipv4_packet(); void count_ipv6_packet(); +void count_http_packet(); + void init_statistics(); void try_print_statistics(); diff --git a/src/util.c b/src/util.c index bf182021..cb76294b 100644 --- a/src/util.c +++ b/src/util.c @@ -1,6 +1,7 @@ #include #include #include +#include void *memncasemem(const void *l, size_t l_len, const void *s, size_t s_len) { register char *cur, *last; @@ -16,7 +17,7 @@ void *memncasemem(const void *l, size_t l_len, const void *s, size_t s_len) { return NULL; /* special case where s_len == 1 */ - if (s_len == 1){ + if (s_len == 1) { for (cur = (char *) cl; l_len--; cur++) if (tolower(cur[0]) == tolower(cs[0])) return cur; @@ -33,4 +34,26 @@ void *memncasemem(const void *l, size_t l_len, const void *s, size_t s_len) { } return NULL; +} + +static bool probe_http_method(const char *p, int len, const char *opt) { + return !strncmp(p, opt, strlen(opt)); +} + +bool is_http_protocol(const char *p, unsigned int len) { + bool pass = false; + +#define PROBE_HTTP_METHOD(opt) if ((pass = probe_http_method(p, len, opt)) != false) return pass + + PROBE_HTTP_METHOD("GET"); + PROBE_HTTP_METHOD("POST"); + PROBE_HTTP_METHOD("OPTIONS"); + PROBE_HTTP_METHOD("HEAD"); + PROBE_HTTP_METHOD("PUT"); + PROBE_HTTP_METHOD("DELETE"); + PROBE_HTTP_METHOD("TRACE"); + PROBE_HTTP_METHOD("CONNECT"); + +#undef PROBE_HTTP_METHOD + return false; } \ No newline at end of file diff --git a/src/util.h b/src/util.h index 7f470586..6f80df2e 100644 --- a/src/util.h +++ b/src/util.h @@ -2,9 +2,11 @@ #define UA2F_UTIL_H #include +#include #define QUEUE_NUM 10010 void *memncasemem(const void *l, size_t l_len, const void *s, size_t s_len); +bool is_http_protocol(const char *p, unsigned int len); #endif //UA2F_UTIL_H diff --git a/test/util_test.cc b/test/util_test.cc index 1ddebece..23141090 100644 --- a/test/util_test.cc +++ b/test/util_test.cc @@ -69,4 +69,19 @@ TEST(MemNCaseMemTest, UserAgentStrange) { void *result = memncasemem(l, l_len, s, s_len); EXPECT_EQ(result, (void *) l); +} + +TEST(HttpProtocolTest, RealWorldRequests) { + const char* getPayload = "GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"; + const char* postPayload = "POST /submit HTTP/1.1\r\nHost: example.com\r\n\r\n"; + const char* optionsPayload = "OPTIONS /test HTTP/1.1\r\nHost: example.com\r\n\r\n"; + + EXPECT_TRUE(is_http_protocol(getPayload, strlen(getPayload))) << "GET method failed"; + EXPECT_TRUE(is_http_protocol(postPayload, strlen(postPayload))) << "POST method failed"; + EXPECT_TRUE(is_http_protocol(optionsPayload, strlen(optionsPayload))) << "OPTIONS method failed"; + + const char* invalidPayload = "INVALID string"; + + // Check that these cases return false + EXPECT_FALSE(is_http_protocol(invalidPayload, strlen(invalidPayload))) << "Invalid method passed"; } \ No newline at end of file