diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b6e0129 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,13 @@ +name: C/C++ CI + +on: + push: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + diff --git a/Makefile b/Makefile index 2576532..f1d6631 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ include $(TOPDIR)/rules.mk PKG_NAME:=UA2F -PKG_VERSION:=2.2 +PKG_VERSION:=3.1 -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) diff --git a/README.md b/README.md index 9ae5f5e..8b9b8de 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ iptables -t mangle -A ua2f -p tcp --dport 443 -j RETURN iptables -t mangle -A ua2f -p tcp --dport 22 -j RETURN # 不处理 SSH 和 https iptables -t mangle -A ua2f -p tcp --dport 80 -j CONNMARK --set-mark 24 iptables -t mangle -A ua2f -m set --set nohttp dst,dst -j RETURN -iptables -t mangle -A ua2f -m connmark --mark 23 -j RETURN # 不处理标记为非 http 的流 (实验性) +iptables -t mangle -A ua2f -m connmark --mark 28 -j RETURN # 不处理标记为非 http 的流 (实验性) iptables -t mangle -A ua2f -j NFQUEUE --queue-num 10010 iptables -t mangle -A FORWARD -p tcp -m conntrack --ctdir ORIGINAL -j ua2f diff --git a/src/ua2f.c b/src/ua2f.c index 55dfa75..e26651f 100644 --- a/src/ua2f.c +++ b/src/ua2f.c @@ -20,8 +20,6 @@ #include -#include -// #include #include #include @@ -29,7 +27,6 @@ #include #include #include -#include #define NF_ACCEPT 1 @@ -37,13 +34,13 @@ static struct mnl_socket *nl; static const int queue_number = 10010; -static long long httpcount = 0; -static long long httpnouacount = 0; +static long long UAcount = 0; +//static long long httpnouacount = 0; static long long tcpcount = 0; -static long long httpmark = 0; -static long long nohttpmark = 0; +static long long UAmark = 0; +static long long noUAmark = 0; static long long oldhttpcount = 4; -static long long http1_0count = 0; +//static long long http1_0count = 0; static time_t start_t, current_t; @@ -80,85 +77,41 @@ static int parse_attrs(const struct nlattr *attr, void *data) { // static bool http_sign_check(bool firstcheck, unsigned int tcplen, unsigned char *tcppayload); -static bool stringCmp(const char *charp_to, const char charp_from[]) { - return memcmp(charp_to, charp_from, strlen(charp_from)) == 0; -} - -static int probe_http_method(const char *p, const char *opt) { - return !strncmp(p, opt, strlen(opt)); -} - -static bool http_judge(char *tcppayload, unsigned int tcplen) { -// if (*tcppayload < 65 || *tcppayload > 90) { // ASCII +//static int probe_http_method(const char *p, const char *opt) { +// return !strncmp(p, opt, strlen(opt)); +//} +// +//static bool http_judge(char *tcppayload, unsigned int tcplen) { +// +// if (tcplen <= 12) { // return false; // } -// switch (*tcppayload) { -// case 'G': -// return http_sign_check(stringCmp(tcppayload, "GET"), tcplen, tcppayload); -// case 'P': -// return http_sign_check( -// stringCmp(tcppayload, "POST") || stringCmp(tcppayload, "PUT") || stringCmp(tcppayload, "PATCH"), -// tcplen, tcppayload); -// case 'C': -// return stringCmp(tcppayload, "CONNECT"); // 这个应该有bug -// case 'D': -// return http_sign_check(stringCmp(tcppayload, "DELETE"), tcplen, tcppayload); -// case 'H': -// return http_sign_check(stringCmp(tcppayload, "HEAD"), tcplen, tcppayload); -// case 'T': -// return http_sign_check(stringCmp(tcppayload, "TRACE"), tcplen, tcppayload); -// case 'O': -// return http_sign_check(stringCmp(tcppayload, "OPTIONS"), tcplen, tcppayload); -// default: -// return false; +// +// if (memmem(tcppayload, tcplen, "HTTP", 4)) { +// return true; // } - - if (tcplen <= 12) { - return false; - } - - if (memmem(tcppayload, tcplen, "HTTP", 4)) { - return true; - } - -#define PROBE_HTTP_METHOD(option) if(probe_http_method(tcppayload, option)) {http1_0count++; return true;} - - /* Otherwise it could be HTTP/1.0 without version: check if it's got an - * HTTP method (RFC2616 5.1.1) */ - 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; -} - -/*static bool http_sign_check(bool firstcheck, const unsigned int tcplen, unsigned char *tcppayload) { - if (!firstcheck) { - return false; - } else { - for (int i = 14; i < tcplen - 3; i++) { //最短的 http 动词是 GET - if (*(tcppayload + i) == '\r') { - if (*(tcppayload + i + 1) == '\n') { - return stringCmp(tcppayload + i - 8, "HTTP/1"); // 向前查找 http 版本 - } else { - return false; - } - } - } // 找不到 http 协议版本 - return false; - } -}*/ +// +//#define PROBE_HTTP_METHOD(option) if(probe_http_method(tcppayload, option)) {http1_0count++; return true;} +// +// /* Otherwise it could be HTTP/1.0 without version: check if it's got an +// * HTTP method (RFC2616 5.1.1) */ +// 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; +//} static void -nfq_send_verdict(int queue_num, uint32_t id, struct pkt_buff *pktb, uint32_t mark, bool nohttp, - char addcmd[50]) { // http mark = 24, ukn mark = 18-20, no http mark = 23 +nfq_send_verdict(int queue_num, uint32_t id, struct pkt_buff *pktb, uint32_t mark, bool noUA, + char addcmd[50]) { // http mark = 24, ukn mark = 16-20, no http mark = 23 char buf[0xffff + (MNL_SOCKET_BUFFER_SIZE / 2)]; struct nlmsghdr *nlh; struct nlattr *nest; @@ -179,7 +132,7 @@ nfq_send_verdict(int queue_num, uint32_t id, struct pkt_buff *pktb, uint32_t mar debugflag2++;//flag3 - if (nohttp) { + if (noUA) { if (mark == 1) { nest = mnl_attr_nest_start(nlh, NFQA_CT); mnl_attr_put_u32(nlh, CTA_MARK, htonl(16)); @@ -201,21 +154,20 @@ nfq_send_verdict(int queue_num, uint32_t id, struct pkt_buff *pktb, uint32_t mar ipset_parse_line(Pipset, addcmd); //加 ipset 标记 - nohttpmark++; + noUAmark++; } } else { if (mark != 24) { nest = mnl_attr_nest_start(nlh, NFQA_CT); mnl_attr_put_u32(nlh, CTA_MARK, htonl(24)); mnl_attr_nest_end(nlh, nest); - httpmark++; + UAmark++; } } if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { perror("mnl_socket_send"); - //exithandle(1); syslog(LOG_ERR, "Exit at breakpoint 1."); exit(EXIT_FAILURE); } @@ -223,9 +175,7 @@ nfq_send_verdict(int queue_num, uint32_t id, struct pkt_buff *pktb, uint32_t mar debugflag2++;//flag4 tcpcount++; - if (pktb) { - pktb_free(pktb); - } + pktb_free(pktb); debugflag2++;//flag5 } @@ -248,7 +198,7 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) { char *str = NULL; void *payload; uint32_t mark = 0; - bool nohttp = false; + bool noUA = false; char *ip; uint16_t port = 0; @@ -343,24 +293,21 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) { tcppklen = nfq_tcp_get_payload_len(tcppkhdl, pktb); //获取 tcp长度 if (tcppkpayload) { - if (http_judge(tcppkpayload, tcppklen)) { + char *uapointer = memmem(tcppkpayload, tcppklen, "\r\nUser-Agent: ", 14); + + if (uapointer) { debugflag++; //flag5 - char *uapointer = memmem(tcppkpayload, tcppklen, "User-Agent:", 11); + debugflag++; //flag6 - if (uapointer) { - uaoffset = uapointer - tcppkpayload + 12; - - for (int i = 0; i < tcppklen - uaoffset - 4; ++i) { - if (*(uapointer + 12 + i) == '\r') { - ualength = i; - break; - } + uaoffset = uapointer - tcppkpayload + 15; + for (int i = 0; i < tcppklen - uaoffset - 4; ++i) { + if (*(uapointer + 15 + i) == '\r') { + ualength = i; + break; } - } else { - httpnouacount++; } debugflag++; //flag7 @@ -382,9 +329,9 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) { exit(EXIT_FAILURE); } if (nfq_tcp_mangle_ipv4(pktb, uaoffset, ualength, str, ualength) == 1) { - httpcount++; //记录修改包的数量 + UAcount++; //记录修改包的数量 free(str);//用完就丢 - nohttp = false; + noUA = false; } else { free(str); pktb_free(pktb); @@ -394,22 +341,22 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data) { debugflag++; //flag8 } else { - nohttp = true; + noUA = true; } } debugflag++; //flag5 / 9 - nfq_send_verdict(ntohs(nfg->res_id), ntohl((uint32_t) ph->packet_id), pktb, mark, nohttp, addcmd); + nfq_send_verdict(ntohs(nfg->res_id), ntohl((uint32_t) ph->packet_id), pktb, mark, noUA, addcmd); debugflag++; //flag6 / 10 - if (httpcount / oldhttpcount == 2 || httpcount - oldhttpcount >= 8192) { - oldhttpcount = httpcount; + if (UAcount / oldhttpcount == 2 || UAcount - oldhttpcount >= 8192) { + oldhttpcount = UAcount; current_t = time(NULL); syslog(LOG_INFO, - "UA2F has handled %lld http, %lld http 1.0, %lld noua http, %lld tcp. Set %lld mark and %lld nohttp mark in %s", - httpcount, http1_0count, httpnouacount, tcpcount, httpmark, nohttpmark, + "UA2F has handled %lld ua http, %lld tcp. Set %lld mark and %lld noUA mark in %s", + UAcount, tcpcount, UAmark, noUAmark, time2str((int) difftime(current_t, start_t))); } @@ -429,7 +376,7 @@ int main(int argc, char *argv[]) { char *buf; size_t sizeof_buf = 0xffff + (MNL_SOCKET_BUFFER_SIZE / 2); struct nlmsghdr *nlh; - int ret; + ssize_t ret; unsigned int portid; int child_status;