diff --git a/nfq2/Makefile b/nfq2/Makefile index 4cc2c8c..3354f04 100644 --- a/nfq2/Makefile +++ b/nfq2/Makefile @@ -10,11 +10,11 @@ LIBS = LIBS_LINUX = -lz -lnetfilter_queue -lnfnetlink -lmnl -lm LIBS_SYSTEMD = -lsystemd LIBS_BSD = -lz -lm -LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 +LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 -liphlpapi -lntdll LIBS_CYGWIN32 = -lwindivert32 LIBS_CYGWIN64 = -lwindivert64 -RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o -RES_CYGWIN64 = windows/res/64/winmanifest.o windows/res/64/winicon.o +RES_CYGWIN32 = windows/res/winws_res32.o +RES_CYGWIN64 = windows/res/winws_res64.o SRC_FILES = *.c crypto/*.c LUA_JIT?=1 diff --git a/nfq2/checksum.c b/nfq2/checksum.c index 3775114..3d8c620 100644 --- a/nfq2/checksum.c +++ b/nfq2/checksum.c @@ -95,10 +95,7 @@ static uint16_t do_csum(const uint8_t *buff, size_t len) return u16; } -uint16_t csum_partial(const void *buff, size_t len) -{ - return do_csum(buff, len); -} +#define csum_partial(buff, len) do_csum((const uint8_t*)buff,len) uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum) { @@ -107,7 +104,7 @@ uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t p uint16_t ip4_compute_csum(const void *buff, size_t len) { - return ~from64to16(do_csum(buff, len)); + return ~csum_partial(buff, len); } void ip4_fix_checksum(struct ip *ip) { @@ -158,3 +155,21 @@ void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const else if (ip6hdr) udp6_fix_checksum(udp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst); } + +void icmp4_fix_checksum(struct icmp46 *icmp, size_t len) +{ + icmp->icmp_cksum = 0; + icmp->icmp_cksum = ~csum_partial(icmp, len); +} +void icmp6_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr) +{ + icmp->icmp_cksum = 0; + icmp->icmp_cksum = csum_ipv6_magic(&ip6hdr->ip6_src, &ip6hdr->ip6_dst, len, IPPROTO_ICMPV6, csum_partial(icmp, len)); +} +void icmp_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr) +{ + if (ip6hdr) + icmp6_fix_checksum(icmp, len, ip6hdr); + else + icmp4_fix_checksum(icmp, len); +} diff --git a/nfq2/checksum.h b/nfq2/checksum.h index c33831e..611927c 100644 --- a/nfq2/checksum.h +++ b/nfq2/checksum.h @@ -11,6 +11,20 @@ #include #include +// icmp 4 and 6 are basically compatible although checksums are calculated differently +// do not use version specific structs +struct icmp46 +{ + uint8_t icmp_type, icmp_code; + uint16_t icmp_cksum; + union + { + uint32_t icmp_data32; + uint16_t icmp_data16[2]; + uint8_t icmp_data8[4]; + }; +}; + uint16_t csum_partial(const void *buff, size_t len); uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum); uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum); @@ -25,3 +39,7 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr); void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr); void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr); + +void icmp4_fix_checksum(struct icmp46 *icmp, size_t len); +void icmp6_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr); +void icmp_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr); diff --git a/nfq2/conntrack.c b/nfq2/conntrack.c index 2ee4c54..88d35b9 100644 --- a/nfq2/conntrack.c +++ b/nfq2/conntrack.c @@ -70,7 +70,7 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s p->pool = NULL; } -void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis) +bool ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis) { memset(c, 0, sizeof(*c)); if (dis->ip) @@ -86,8 +86,9 @@ void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis) c->src.ip6 = bReverse ? dis->ip6->ip6_dst : dis->ip6->ip6_src; } else - c->l3proto = -1; + return false; extract_ports(dis->tcp, dis->udp, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport); + return c->l4proto!=IPPROTO_NONE; } @@ -225,7 +226,7 @@ static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct di t_conn conn, connswp; t_conntrack_pool *ctr; - ConntrackExtractConn(&conn, false, dis); + if (!ConntrackExtractConn(&conn, false, dis)) return false; if ((ctr = ConntrackPoolSearch(*pp, &conn))) { if (bReverse) *bReverse = false; @@ -256,7 +257,7 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct dissect *d bool b_rev; uint8_t proto = dis->tcp ? IPPROTO_TCP : dis->udp ? IPPROTO_UDP : IPPROTO_NONE; - ConntrackExtractConn(&conn, false, dis); + if (!ConntrackExtractConn(&conn, false, dis)) return false; if ((ctr = ConntrackPoolSearch(*pp, &conn))) { ConntrackFeedPacket(&ctr->track, (b_rev = false), dis); @@ -296,7 +297,7 @@ static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct dissect *d { t_conn conn, connswp; t_conntrack_pool *t; - ConntrackExtractConn(&conn, false, dis); + if (!ConntrackExtractConn(&conn, false, dis)) return false; if (!(t = ConntrackPoolSearch(*pp, &conn))) { connswap(&conn, &connswp); diff --git a/nfq2/conntrack.h b/nfq2/conntrack.h index 01f99af..62467b8 100644 --- a/nfq2/conntrack.h +++ b/nfq2/conntrack.h @@ -105,7 +105,7 @@ bool ConntrackPoolFeed(t_conntrack *p, const struct dissect *dis, t_ctrack **ctr // do not create, do not update. only find existing bool ConntrackPoolDoubleSearch(t_conntrack *p, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse); bool ConntrackPoolDrop(t_conntrack *p, const struct dissect *dis); -void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis); +bool ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis); void ConntrackPoolDump(const t_conntrack *p); void ConntrackPoolPurge(t_conntrack *p); void ConntrackClearHostname(t_ctrack *track); diff --git a/nfq2/crypto/hkdf.c b/nfq2/crypto/hkdf.c index 266cb37..5e16de1 100644 --- a/nfq2/crypto/hkdf.c +++ b/nfq2/crypto/hkdf.c @@ -103,9 +103,6 @@ int hkdfExtract(SHAversion whichSha, salt_len = USHAHashSize(whichSha); memset(nullSalt, '\0', salt_len); } - else if (salt_len < 0) { - return shaBadParam; - } return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk); } @@ -154,11 +151,7 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len, info = (const unsigned char *)""; info_len = 0; } - else if (info_len < 0) { - return shaBadParam; - } - if (okm_len <= 0) return shaBadParam; - if (!okm) return shaBadParam; + if (!okm || !okm_len) return shaBadParam; hash_len = USHAHashSize(whichSha); if (prk_len < hash_len) return shaBadParam; diff --git a/nfq2/darkmagic.c b/nfq2/darkmagic.c index fa3d56e..e27043a 100644 --- a/nfq2/darkmagic.c +++ b/nfq2/darkmagic.c @@ -33,6 +33,8 @@ #define ERROR_INVALID_IMAGE_HASH __MSABI_LONG(577) #endif +#include "nthacks.h" + #endif #ifdef __linux__ @@ -98,11 +100,11 @@ bool tcp_syn_segment(const struct tcphdr *tcphdr) } -void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport) +void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr,uint8_t *proto, uint16_t *sport, uint16_t *dport) { if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0); if (dport) *dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0); - if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : -1; + if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : IPPROTO_NONE; } bool extract_dst(const uint8_t *data, size_t len, struct sockaddr* dst) @@ -174,6 +176,11 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st si->sin6_scope_id = 0; } } + else + { + memset(src,0,sizeof(*src)); + memset(dst,0,sizeof(*dst)); + } } const char *proto_name(uint8_t proto) @@ -192,8 +199,6 @@ const char *proto_name(uint8_t proto) return "igmp"; case IPPROTO_ESP: return "esp"; - case IPPROTO_AH: - return "ah"; case IPPROTO_IPV6: return "6in4"; case IPPROTO_IPIP: @@ -210,7 +215,7 @@ const char *proto_name(uint8_t proto) return NULL; } } -static void str_proto_name(char *s, size_t s_len, uint8_t proto) +void str_proto_name(char *s, size_t s_len, uint8_t proto) { const char *name = proto_name(proto); if (name) @@ -228,6 +233,56 @@ uint16_t family_from_proto(uint8_t l3proto) } } +const char *icmp_type_name(bool v6, uint8_t type) +{ + if (v6) + { + switch(type) + { + case ICMP6_ECHO_REQUEST: return "echo_req6"; + case ICMP6_ECHO_REPLY: return "echo_reply6"; + case ICMP6_DST_UNREACH: return "dest_unreach6"; + case ICMP6_PACKET_TOO_BIG: return "packet_too_big"; + case ICMP6_TIME_EXCEEDED: return "time_exceeded6"; + case ICMP6_PARAM_PROB: return "param_problem6"; + case MLD_LISTENER_QUERY: return "mld_listener_query"; + case MLD_LISTENER_REPORT: return "mld_listener_report"; + case MLD_LISTENER_REDUCTION: return "mld_listener_reduction"; + case ND_ROUTER_SOLICIT: return "router_sol"; + case ND_ROUTER_ADVERT: return "router_adv"; + case ND_NEIGHBOR_SOLICIT: return "neigh_sol"; + case ND_NEIGHBOR_ADVERT: return "neigh_adv"; + case ND_REDIRECT: return "redirect6"; + } + } + else + { + switch(type) + { + case ICMP_ECHOREPLY: return "echo_reply"; + case ICMP_DEST_UNREACH: return "dest_unreach"; + case ICMP_REDIRECT: return "redirect"; + case ICMP_ECHO: return "echo_req"; + case ICMP_TIME_EXCEEDED: return "time_exceeded"; + case ICMP_PARAMETERPROB: return "param_problem"; + case ICMP_TIMESTAMP: return "ts"; + case ICMP_TIMESTAMPREPLY: return "ts_reply"; + case ICMP_INFO_REQUEST: return "info_req"; + case ICMP_INFO_REPLY: return "info_reply"; + } + } + return NULL; +} +void str_icmp_type_name(char *s, size_t s_len, bool v6, uint8_t type) +{ + const char *name = icmp_type_name(v6, type); + if (name) + snprintf(s,s_len,"%s",name); + else + snprintf(s,s_len,"%u",type); +} + + static void str_srcdst_ip(char *s, size_t s_len, const void *saddr,const void *daddr) { char s_ip[16],d_ip[16]; @@ -298,7 +353,21 @@ void print_udphdr(const struct udphdr *udphdr) str_udphdr(s,sizeof(s),udphdr); printf("%s",s); } - +void str_icmphdr(char *s, size_t s_len, bool v6, const struct icmp46 *icmp) +{ + char stype[32]; + str_icmp_type_name(stype,sizeof(stype),v6,icmp->icmp_type); + if (icmp->icmp_type==ICMP_ECHO || icmp->icmp_type==ICMP_ECHOREPLY || icmp->icmp_type==ICMP6_ECHO_REQUEST || icmp->icmp_type==ICMP6_ECHO_REPLY) + snprintf(s,s_len,"icmp_type=%s icmp_code=%u id=0x%04X seq=%u",stype,icmp->icmp_code,ntohs(icmp->icmp_data16[0]),ntohs(icmp->icmp_data16[1])); + else + snprintf(s,s_len,"icmp_type=%s icmp_code=%u data=0x%08X",stype,icmp->icmp_code,ntohl(icmp->icmp_data32)); +} +void print_icmphdr(const struct icmp46 *icmp, bool v6) +{ + char s[48]; + str_icmphdr(s,sizeof(s),v6,icmp); + printf("%s",s); +} @@ -340,7 +409,15 @@ void proto_skip_udp(const uint8_t **data, size_t *len) *data += sizeof(struct udphdr); *len -= sizeof(struct udphdr); } - +bool proto_check_icmp(const uint8_t *data, size_t len) +{ + return len >= sizeof(struct icmp46); +} +void proto_skip_icmp(const uint8_t **data, size_t *len) +{ + *data += sizeof(struct icmp46); + *len -= sizeof(struct icmp46); +} bool proto_check_ipv6(const uint8_t *data, size_t len) { return len >= sizeof(struct ip6_hdr) && (data[0] & 0xF0) == 0x60; @@ -449,7 +526,7 @@ uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto) return NULL; } -void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis) +void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis, bool no_payload_check) { const uint8_t *p; @@ -466,7 +543,7 @@ void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis) proto_skip_ipv4(&data, &len); dis->len_l3 = data-p; } - else if (proto_check_ipv6(data, len) && proto_check_ipv6_payload(data, len)) + else if (proto_check_ipv6(data, len) && (no_payload_check || proto_check_ipv6_payload(data, len))) { dis->ip6 = (const struct ip6_hdr *) data; p = data; @@ -478,31 +555,36 @@ void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis) return; } + dis->transport_len = len; + if (dis->proto==IPPROTO_TCP && proto_check_tcp(data, len)) { dis->tcp = (const struct tcphdr *) data; - dis->transport_len = len; - p = data; proto_skip_tcp(&data, &len); dis->len_l4 = data-p; - - dis->data_payload = data; - dis->len_payload = len; - } - else if (dis->proto==IPPROTO_UDP && proto_check_udp(data, len) && proto_check_udp_payload(data, len)) + else if (dis->proto==IPPROTO_UDP && proto_check_udp(data, len) && (no_payload_check || proto_check_udp_payload(data, len))) { dis->udp = (const struct udphdr *) data; - dis->transport_len = len; - p = data; proto_skip_udp(&data, &len); dis->len_l4 = data-p; - - dis->data_payload = data; - dis->len_payload = len; } + else if ((dis->proto==IPPROTO_ICMP || dis->proto==IPPROTO_ICMPV6) && proto_check_icmp(data, len)) + { + dis->icmp = (const struct icmp46 *) data; + p = data; + proto_skip_icmp(&data, &len); + dis->len_l4 = data-p; + } + else + { + dis->len_l4 = 0; + } + + dis->data_payload = data; + dis->len_payload = len; } void reverse_ip(struct ip *ip, struct ip6_hdr *ip6) @@ -539,12 +621,137 @@ uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6) } +bool get_source_ip4(const struct in_addr *target, struct in_addr *source) +{ + int sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) return false; + + struct sockaddr_in serv,name; + socklen_t namelen; + + memset(&serv,0,sizeof(serv)); // or valgrind complains about uninitialized + serv.sin_family = AF_INET; + serv.sin_addr = *target; + serv.sin_port = 0xFFFF; + + // Connect triggers the kernel's route lookup + if (!connect(sock, (const struct sockaddr*)&serv, sizeof(serv))) + { + namelen = sizeof(name); + if (!getsockname(sock, (struct sockaddr*)&name, &namelen)) + { + close(sock); + *source = name.sin_addr; + return true; + } + } + close(sock); + return false; +} +bool get_source_ip6(const struct in6_addr *target, struct in6_addr *source) +{ + int sock = socket(AF_INET6, SOCK_DGRAM, 0); + if (sock < 0) return false; + + struct sockaddr_in6 serv,name; + socklen_t namelen; + + memset(&serv,0,sizeof(serv)); // or valgrind complains about uninitialized + serv.sin6_family = AF_INET6; + serv.sin6_addr = *target; + serv.sin6_port = 0xFFFF; + + // Connect triggers the kernel's route lookup + if (!connect(sock, (const struct sockaddr*)&serv, sizeof(serv))) + { + namelen = sizeof(name); + if (!getsockname(sock, (struct sockaddr*)&name, &namelen)) + { + close(sock); + *source = name.sin6_addr; + return true; + } + } + + close(sock); + return false; +} #ifdef __CYGWIN__ uint32_t w_win32_error=0; +BOOL AdjustPrivileges(HANDLE hToken, const LPCTSTR *privs, BOOL bEnable) +{ + DWORD dwSize, k, n; + PTOKEN_PRIVILEGES TokenPrivsData; + LUID luid; + + dwSize = 0; + GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwSize ); // will fail + w_win32_error = GetLastError(); + if (w_win32_error == ERROR_INSUFFICIENT_BUFFER) + { + w_win32_error = 0; + if (TokenPrivsData = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_FIXED, dwSize)) + { + if (GetTokenInformation(hToken, TokenPrivileges, TokenPrivsData, dwSize, &dwSize)) + { + n = 0; + while (privs[n]) + { + if (LookupPrivilegeValue(NULL, privs[n], &luid)) + { + w_win32_error = ERROR_PRIVILEGE_NOT_HELD; + for (k = 0; k < TokenPrivsData->PrivilegeCount; k++) + if (!memcmp(&TokenPrivsData->Privileges[k].Luid, &luid, sizeof(LUID))) + { + if (bEnable) + TokenPrivsData->Privileges[k].Attributes |= SE_PRIVILEGE_ENABLED; + else + TokenPrivsData->Privileges[k].Attributes &= ~SE_PRIVILEGE_ENABLED; + w_win32_error = 0; + break; + } + } + else + w_win32_error = GetLastError(); + if (w_win32_error) break; + n++; + } + if (!w_win32_error) + { + if (!AdjustTokenPrivileges(hToken, FALSE, TokenPrivsData, 0, NULL, NULL)) + w_win32_error = GetLastError(); + } + } + else + w_win32_error = GetLastError(); + LocalFree(TokenPrivsData); + } + else + w_win32_error = GetLastError(); + } + return !w_win32_error; +} +BOOL AdjustPrivilegesForCurrentProcess(const LPCTSTR *privs, BOOL bEnable) +{ + HANDLE hTokenThisProcess; + + w_win32_error = 0; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hTokenThisProcess)) + { + if (!AdjustPrivileges(hTokenThisProcess, privs, bEnable)) + w_win32_error = GetLastError(); + CloseHandle(hTokenThisProcess); + } + else + w_win32_error = GetLastError(); + + return !w_win32_error; +} + static BOOL RemoveTokenPrivs(void) { BOOL bRes = FALSE; @@ -670,6 +877,26 @@ err: if (!bRes) w_win32_error = GetLastError(); return bRes; } +BOOL SetMandatoryLabelObject(HANDLE h, SE_OBJECT_TYPE ObjType, DWORD dwMandatoryLabelRID, DWORD dwAceRevision, DWORD dwAceFlags) +{ + BOOL bRes = FALSE; + DWORD dwErr; + char buf_label[16], buf_pacl[32]; + PSID label = (PSID)buf_label; + PACL pacl = (PACL)buf_pacl; + + InitializeSid(label, &label_authority, 1); + *GetSidSubAuthority(label, 0) = dwMandatoryLabelRID; + if (InitializeAcl(pacl, sizeof(buf_pacl), ACL_REVISION) && AddMandatoryAce(pacl, dwAceRevision, dwAceFlags, SYSTEM_MANDATORY_LABEL_NO_WRITE_UP, label)) + { + dwErr = SetSecurityInfo(h, ObjType, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pacl); + SetLastError(dwErr); + bRes = dwErr == ERROR_SUCCESS; + } + if (!bRes) w_win32_error = GetLastError(); + return bRes; +} + bool ensure_file_access(const char *filename) { @@ -703,6 +930,85 @@ bool prepare_low_appdata() return b; } +// cygwin uses nt directory to store it's state. low mandatory breaks write access there and cause some functions to fail +// it's not possible to reproduce exact directory names, have to iterate and set low integrity to all +BOOL RelaxCygwinNTDir() +{ + NTSTATUS status; + PROCESS_SESSION_INFORMATION psi; + WCHAR bno_name[32], cyg_name[256]; + CHAR scyg_name[256]; + UNICODE_STRING bno_us, cyg_us; + OBJECT_ATTRIBUTES attr; + HANDLE hDir, hDirCyg; + BYTE buf[4096]; + ULONG context, rsize; + BOOL b,ball,restart; + POBJECT_DIRECTORY_INFORMATION pdir; + + LPCTSTR Privs[] = { SE_TAKE_OWNERSHIP_NAME , NULL }; + + if (!AdjustPrivilegesForCurrentProcess(Privs, TRUE)) + return FALSE; + + status = NtQueryInformationProcess(GetCurrentProcess(), ProcessSessionInformation, &psi, sizeof psi, NULL); + if (NT_SUCCESS(status)) + swprintf(bno_name, sizeof(bno_name)/sizeof(*bno_name), L"\\Sessions\\BNOLINKS\\%u", psi.SessionId); + else + swprintf(bno_name, sizeof(bno_name)/sizeof(*bno_name), L"\\BaseNamedObjects"); + + RtlInitUnicodeString(&bno_us, bno_name); + InitializeObjectAttributes(&attr, &bno_us, 0, NULL, NULL); + + ball = TRUE; + w_win32_error = 0; + status = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY, &attr); + if (NT_SUCCESS(status)) + { + context = 0; + restart = TRUE; + while (NT_SUCCESS(status = NtQueryDirectoryObject(hDir, buf, sizeof(buf), restart, FALSE, &context, &rsize))) + { + + for (pdir = (POBJECT_DIRECTORY_INFORMATION)buf; pdir->Name.Length; pdir++) + if (pdir->TypeName.Length == 18 && !memcmp(pdir->TypeName.Buffer, L"Directory", 18) && + pdir->Name.Length >= 14 && !memcmp(pdir->Name.Buffer, L"cygwin1", 14)) + { + swprintf(cyg_name, sizeof(cyg_name)/sizeof(*cyg_name), L"%ls\\%ls", bno_name, pdir->Name.Buffer); + if (!WideCharToMultiByte(CP_ACP, 0, cyg_name, -1, scyg_name, sizeof(scyg_name), NULL, NULL)) + *scyg_name=0; + RtlInitUnicodeString(&cyg_us, cyg_name); + InitializeObjectAttributes(&attr, &cyg_us, 0, NULL, NULL); + status = NtOpenDirectoryObject(&hDirCyg, WRITE_OWNER, &attr); + if (NT_SUCCESS(status)) + { + b = SetMandatoryLabelObject(hDirCyg, SE_KERNEL_OBJECT, SECURITY_MANDATORY_LOW_RID, ACL_REVISION_DS, 0); + if (!b) + { + w_win32_error = GetLastError(); + DLOG_ERR("could not set integrity label on '%s' . error %u\n", scyg_name, w_win32_error); + } + else + DLOG("set low integrity label on '%s'\n", scyg_name); + ball = ball && b; + NtClose(hDirCyg); + } + } + restart = FALSE; + } + NtClose(hDir); + } + else + { + w_win32_error = RtlNtStatusToDosError(status); + return FALSE; + } + + return ball; +} + + + BOOL JobSandbox() { BOOL bRes = FALSE; @@ -734,6 +1040,9 @@ bool win_sandbox(void) // there's no way to return privs if (!b_sandbox_set) { + if (!RelaxCygwinNTDir()) + DLOG_ERR("could not set low mandatory label on cygwin NT directory. some functions may not work. error %u\n", w_win32_error); + if (!RemoveTokenPrivs()) return FALSE; @@ -1961,6 +2270,23 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo #endif } +void verdict_icmp_csum_fix(uint8_t verdict, struct icmp46 *icmphdr, size_t transport_len, const struct ip6_hdr *ip6hdr) +{ + // always fix csum for windivert. original can be partial or bad + // FreeBSD tend to pass ipv6 frames with wrong checksum (OBSERVED EARLIER, MAY BE FIXED NOW) + // Linux passes correct checksums +#ifndef __linux__ + if (!(verdict & VERDICT_NOCSUM) && (verdict & VERDICT_MASK)==VERDICT_PASS) + { + #ifdef __FreeBSD__ + if (ip6hdr) + #endif + DLOG("fixing icmp checksum\n"); + icmp_fix_checksum(icmphdr,transport_len,ip6hdr); + } +#endif +} + void dbgprint_socket_buffers(int fd) { if (params.debug) diff --git a/nfq2/darkmagic.h b/nfq2/darkmagic.h index 5a12b42..cba8604 100644 --- a/nfq2/darkmagic.h +++ b/nfq2/darkmagic.h @@ -25,6 +25,11 @@ #ifdef __CYGWIN__ #define INITGUID #include "windivert/windivert.h" +#include "netinet/icmp6.h" +#include "netinet/ip_icmp.h" +#else +#include +#include #endif #ifndef IPPROTO_DIVERT @@ -59,6 +64,31 @@ #define IPPROTO_SHIM6 140 #endif +#ifndef ICMP_DEST_UNREACH +#define ICMP_DEST_UNREACH 3 +#endif +#ifndef ICMP_TIME_EXCEEDED +#define ICMP_TIME_EXCEEDED 11 +#endif +#ifndef ICMP_PARAMETERPROB +#define ICMP_PARAMETERPROB 12 +#endif +#ifndef ICMP_TIMESTAMP +#define ICMP_TIMESTAMP 13 +#endif +#ifndef ICMP_TIMESTAMPREPLY +#define ICMP_TIMESTAMPREPLY 14 +#endif +#ifndef ICMP_INFO_REQUEST +#define ICMP_INFO_REQUEST 15 +#endif +#ifndef ICMP_INFO_REPLY +#define ICMP_INFO_REPLY 16 +#endif +#ifndef MLD_LISTENER_REDUCTION +#define MLD_LISTENER_REDUCTION 132 +#endif + // returns netorder value uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment); uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); @@ -85,6 +115,7 @@ uint16_t tcp_find_mss(const struct tcphdr *tcp); bool tcp_synack_segment(const struct tcphdr *tcphdr); bool tcp_syn_segment(const struct tcphdr *tcphdr); + bool make_writeable_dir(); bool ensure_file_access(const char *filename); #ifdef __CYGWIN__ @@ -121,16 +152,21 @@ int socket_divert(sa_family_t family); #endif const char *proto_name(uint8_t proto); +void str_proto_name(char *s, size_t s_len, uint8_t proto); +const char *icmp_type_name(bool v6, uint8_t type); +void str_icmp_type_name(char *s, size_t s_len, bool v6, uint8_t type); uint16_t family_from_proto(uint8_t l3proto); void print_ip(const struct ip *ip); void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto); void print_tcphdr(const struct tcphdr *tcphdr); void print_udphdr(const struct udphdr *udphdr); +void print_icmphdr(const struct icmp46 *icmp, bool v6); void str_ip(char *s, size_t s_len, const struct ip *ip); void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto); void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr); void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr); void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr); +void str_icmphdr(char *s, size_t s_len, bool v6, const struct icmp46 *icmp); bool proto_check_ipv4(const uint8_t *data, size_t len); void proto_skip_ipv4(const uint8_t **data, size_t *len); @@ -143,6 +179,9 @@ void proto_skip_tcp(const uint8_t **data, size_t *len); bool proto_check_udp(const uint8_t *data, size_t len); bool proto_check_udp_payload(const uint8_t *data, size_t len); void proto_skip_udp(const uint8_t **data, size_t *len); +bool proto_check_icmp(const uint8_t *data, size_t len); +void proto_skip_icmp(const uint8_t **data, size_t *len); + struct dissect { const uint8_t *data_pkt; @@ -153,19 +192,24 @@ struct dissect uint8_t proto; const struct tcphdr *tcp; const struct udphdr *udp; + const struct icmp46 *icmp; size_t len_l4; size_t transport_len; const uint8_t *data_payload; size_t len_payload; }; -void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis); +void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis, bool no_payload_check); void reverse_ip(struct ip *ip, struct ip6_hdr *ip6); void reverse_tcp(struct tcphdr *tcp); uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6); +bool get_source_ip4(const struct in_addr *target, struct in_addr *source); +bool get_source_ip6(const struct in6_addr *target, struct in6_addr *source); + void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, const struct ip *ip, const struct ip6_hdr *ip6hdr); void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, const struct ip *ip, const struct ip6_hdr *ip6hdr); +void verdict_icmp_csum_fix(uint8_t verdict, struct icmp46 *icmphdr, size_t transport_len, const struct ip6_hdr *ip6hdr); void dbgprint_socket_buffers(int fd); bool set_socket_buffers(int fd, int rcvbuf, int sndbuf); diff --git a/nfq2/desync.c b/nfq2/desync.c index 7914b0e..21c300c 100644 --- a/nfq2/desync.c +++ b/nfq2/desync.c @@ -132,11 +132,79 @@ static void TLSDebug(const uint8_t *tls, size_t sz) TLSDebugHandshake(tls + 5, sz - 5); } +static void packet_debug(bool replay, const struct dissect *dis) +{ + if (params.debug) + { + if (replay) DLOG("REPLAY "); + if (dis->ip) + { + char s[66]; + str_ip(s, sizeof(s), dis->ip); + DLOG("IP4: %s", s); + } + else if (dis->ip6) + { + char s[128]; + str_ip6hdr(s, sizeof(s), dis->ip6, dis->proto); + DLOG("IP6: %s", s); + } + if (dis->tcp) + { + char s[80]; + str_tcphdr(s, sizeof(s), dis->tcp); + DLOG(" %s\n", s); + if (dis->len_payload) + { + DLOG("TCP: len=%zu : ", dis->len_payload); + hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); + DLOG("\n"); + } + } + else if (dis->udp) + { + char s[30]; + str_udphdr(s, sizeof(s), dis->udp); + DLOG(" %s\n", s); + if (dis->len_payload) + { + DLOG("UDP: len=%zu : ", dis->len_payload); + hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); + DLOG("\n"); + } + } + else if (dis->icmp) + { + char s[72]; + str_icmphdr(s, sizeof(s), !!dis->ip6, dis->icmp); + DLOG(" %s\nICMP: len=%zu : ", s, dis->len_payload); + hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); + DLOG("\n"); + } + else + { + if (dis->len_payload) + { + char s_proto[16]; + str_proto_name(s_proto,sizeof(s_proto),dis->proto); + DLOG("\nIP PROTO %s: len=%zu : ", s_proto, dis->len_payload); + hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); + DLOG("\n"); + } + else + DLOG("\n"); + } + } +} + +// ipr,ipr6 - reverse ip - ip of the other side of communication static bool dp_match( struct desync_profile *dp, uint8_t l3proto, - const struct in_addr *ip, const struct in6_addr *ip6, uint16_t port, + const struct in_addr *ip, const struct in6_addr *ip6, + const struct in_addr *ipr, const struct in6_addr *ipr6, + uint16_t port, uint8_t icmp_type, uint8_t icmp_code, const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid, bool *bCheckDone, bool *bCheckResult, bool *bExcluded) { @@ -150,8 +218,23 @@ static bool dp_match( // L3 filter does not match return false; - if ((l3proto == IPPROTO_TCP && !port_filters_in_range(&dp->pf_tcp, port)) || (l3proto == IPPROTO_UDP && !port_filters_in_range(&dp->pf_udp, port))) - // L4 filter does not match + switch(l3proto) + { + case IPPROTO_TCP: + if (!port_filters_match(&dp->pf_tcp, port)) return false; + break; + case IPPROTO_UDP: + if (!port_filters_match(&dp->pf_udp, port)) return false; + break; + case IPPROTO_ICMP: + if (!icmp_filters_match(&dp->icf, icmp_type, icmp_code)) return false; + break; + default: + if (!ipp_filters_match(&dp->ipf, l3proto)) return false; + } + + if (l3proto == IPPROTO_ICMP && !icmp_filters_match(&dp->icf, icmp_type, icmp_code)) + // icmp filter does not match return false; if (!l7_proto_match(l7proto, dp->filter_l7)) @@ -166,7 +249,7 @@ static bool dp_match( if (!dp->hostlist_auto && !hostname && !bHostlistsEmpty) // avoid cpu consuming ipset check. profile cannot win if regular hostlists are present without auto hostlist and hostname is unknown. return false; - if (!IpsetCheck(dp, ip, ip6)) + if (!IpsetCheck(dp, ip, ip6, ipr, ipr6)) // target ip does not match return false; @@ -197,7 +280,9 @@ static bool dp_match( static struct desync_profile *dp_find( struct desync_profile_list_head *head, uint8_t l3proto, - const struct in_addr *ip, const struct in6_addr *ip6, uint16_t port, + const struct in_addr *ip, const struct in6_addr *ip6, + const struct in_addr *ipr, const struct in6_addr *ipr6, + uint16_t port, uint8_t icmp_type, uint8_t icmp_code, const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid, bool *bCheckDone, bool *bCheckResult, bool *bExcluded) { @@ -206,12 +291,21 @@ static struct desync_profile *dp_find( { char s[40]; ntopa46(ip, ip6, s, sizeof(s)); - DLOG("desync profile search for %s ip=%s port=%u l7proto=%s ssid='%s' hostname='%s'\n", proto_name(l3proto), s, port, l7proto_str(l7proto), ssid ? ssid : "", hostname ? hostname : ""); + if (ipr || ipr6) + { + char sr[40]; + ntopa46(ipr, ipr6, sr, sizeof(sr)); + DLOG("desync profile search for %s ip1=%s ip2=%s port=%u icmp=%u:%u l7proto=%s ssid='%s' hostname='%s'\n", + proto_name(l3proto), s, sr, port, icmp_type, icmp_code, l7proto_str(l7proto), ssid ? ssid : "", hostname ? hostname : ""); + } + else + DLOG("desync profile search for %s ip=%s port=%u icmp=%u:%u l7proto=%s ssid='%s' hostname='%s'\n", + proto_name(l3proto), s, port, icmp_type, icmp_code, l7proto_str(l7proto), ssid ? ssid : "", hostname ? hostname : ""); } if (bCheckDone) *bCheckDone = false; LIST_FOREACH(dpl, head, next) { - if (dp_match(&dpl->dp, l3proto, ip, ip6, port, hostname, bNoSubdom, l7proto, ssid, bCheckDone, bCheckResult, bExcluded)) + if (dp_match(&dpl->dp, l3proto, ip, ip6, ipr, ipr6, port, icmp_type, icmp_code, hostname, bNoSubdom, l7proto, ssid, bCheckDone, bCheckResult, bExcluded)) { DLOG("desync profile %u (%s) matches\n", dpl->dp.n, PROFILE_NAME(&dpl->dp)); return &dpl->dp; @@ -455,8 +549,8 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, ui static bool reasm_client_start(t_ctrack *ctrack, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload) { if (!ctrack) return false; - // if winsize_calc==0 it means we dont know server window size - no incoming packets redirected ? - if (proto==IPPROTO_TCP && ctrack->pos.server.winsize_calc && (ctrack->pos.server.winsize_calc < sz)) + // if pcounter==0 it means we dont know server window size - no incoming packets redirected ? + if (proto==IPPROTO_TCP && ctrack->pos.server.pcounter && (ctrack->pos.server.winsize_calc < sz)) { // this is rare but possible situation // server gave us too small tcp window @@ -640,6 +734,12 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *hostname = 0; return true; } + if (params.debug) + { + char s[40]; + ntopa46(a4, a6, s, sizeof(s)); + DLOG("ipcache hostname search for %s\n", s); + } ip_cache_item *ipc = ipcacheTouch(¶ms.ipcache, a4, a6, NULL); if (!ipc) { @@ -648,7 +748,12 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr } if (ipc->hostname) { - DLOG("got cached hostname (is_ip=%u): %s\n", ipc->hostname_is_ip, ipc->hostname); + if (params.debug) + { + char s[40]; + ntopa46(a4, a6, s, sizeof(s)); + DLOG("got cached hostname for %s : %s (is_ip=%u)\n", s, ipc->hostname, ipc->hostname_is_ip); + } snprintf(hostname, hostname_buf_len, "%s", ipc->hostname); if (hostname_is_ip) *hostname_is_ip = ipc->hostname_is_ip; } @@ -968,7 +1073,7 @@ static uint8_t desync( } else { - b = lua_reconstruct_dissect(params.L, -1, mod_pkt, len_mod_pkt, false, false); + b = lua_reconstruct_dissect(params.L, -1, mod_pkt, len_mod_pkt, false, false, false); lua_pop(params.L, 2); if (!b) { @@ -1116,7 +1221,7 @@ static bool play_prolog( DLOG("using cached desync profile %u (%s)\n", ps->dp->n, PROFILE_NAME(ps->dp)); else if (!ps->ctrack_replay->dp_search_complete) { - ps->dp = ps->ctrack_replay->dp = dp_find(¶ms.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, ps->sdport, ps->ctrack_replay->hostname, ps->ctrack_replay->hostname_is_ip, ps->l7proto, ps->ssid, NULL, NULL, NULL); + ps->dp = ps->ctrack_replay->dp = dp_find(¶ms.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF, ps->ctrack_replay->hostname, ps->ctrack_replay->hostname_is_ip, ps->l7proto, ps->ssid, NULL, NULL, NULL); ps->ctrack_replay->dp_search_complete = true; } if (!ps->dp) @@ -1164,7 +1269,7 @@ static bool play_prolog( DLOG_ERR("strdup(host): out of memory\n"); } } - ps->dp = dp_find(¶ms.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, ps->sdport, hostname, hostname_is_ip, ps->l7proto, ps->ssid, NULL, NULL, NULL); + ps->dp = dp_find(¶ms.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF, hostname, hostname_is_ip, ps->l7proto, ps->ssid, NULL, NULL, NULL); if (ps->ctrack) { ps->ctrack->dp = ps->dp; @@ -1249,7 +1354,7 @@ static bool dp_rediscovery(struct play_state *ps) { struct desync_profile *dp_prev = ps->dp; // search for desync profile again. it may have changed. - ps->dp = dp_find(¶ms.desync_profiles, ps->dis->proto, ps->sdip4, ps->sdip6, ps->sdport, + ps->dp = dp_find(¶ms.desync_profiles, ps->dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF, ps->ctrack_replay ? ps->ctrack_replay->hostname : ps->bHaveHost ? ps->host : NULL, ps->ctrack_replay ? ps->ctrack_replay->hostname_is_ip : bHostIsIp, ps->l7proto, ps->ssid, @@ -1782,41 +1887,200 @@ pass_reasm_cancel: goto pass; } - -static void packet_debug(bool replay, const struct dissect *dis) +// conntrack is supported only for RELATED icmp +// ip matched in both directions if conntrack is unavailable +static uint8_t dpi_desync_icmp_packet( + uint32_t fwmark, + const char *ifin, const char *ifout, + const struct dissect *dis, + uint8_t *mod_pkt, size_t *len_mod_pkt) { - if (params.debug) + uint8_t verdict = VERDICT_PASS; + + // additional safety check + if (!!dis->ip == !!dis->ip6) return verdict; + + const uint8_t *pkt_attached; + size_t len_attached; + const char *ifname; + struct sockaddr_storage src, dst; + const char *ssid = NULL; + struct desync_profile *dp = NULL; + t_l7payload l7payload = L7P_UNKNOWN; + t_ctrack *ctrack = NULL; + bool bReverse, bReverseFixed; + + extract_endpoints(dis->ip, dis->ip6, NULL, NULL, &src, &dst); + + switch(dis->icmp->icmp_type) { - if (replay) DLOG("REPLAY "); - if (dis->ip) - { - char s[66]; - str_ip(s, sizeof(s), dis->ip); - DLOG("IP4: %s", s); - } - else if (dis->ip6) - { - char s[128]; - str_ip6hdr(s, sizeof(s), dis->ip6, dis->proto); - DLOG("IP6: %s", s); - } - if (dis->tcp) - { - char s[80]; - str_tcphdr(s, sizeof(s), dis->tcp); - DLOG(" %s\n", s); - if (dis->len_payload) { DLOG("TCP: len=%zu : ", dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); DLOG("\n"); } - } - else if (dis->udp) - { - char s[30]; - str_udphdr(s, sizeof(s), dis->udp); - DLOG(" %s\n", s); - if (dis->len_payload) { DLOG("UDP: len=%zu : ", dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); DLOG("\n"); } - } - else - DLOG("\n"); + case ICMP_DEST_UNREACH: + case ICMP_TIME_EXCEEDED: + case ICMP_PARAMETERPROB: + case ICMP_REDIRECT: + case ICMP6_DST_UNREACH: + //case ICMP6_TIME_EXCEEDED: // same as ICMP_TIME_EXCEEDED = 3 + case ICMP6_PACKET_TOO_BIG: + case ICMP6_PARAM_PROB: + pkt_attached = dis->data_payload; + break; + default: + pkt_attached = NULL; } + if (pkt_attached) + { + struct dissect adis; + + len_attached = pkt_attached - dis->data_payload + dis->len_payload; + proto_dissect_l3l4(pkt_attached, len_attached, &adis, true); // dissect without payload length checks - can be partial + if (!dis->ip && !dis->ip6) + DLOG("attached packet is invalid\n"); + else + { + l7payload = dis->ip ? L7P_IPV4 : L7P_IPV6; + DLOG("attached packet\n"); + packet_debug(false, &adis); + if (ConntrackPoolDoubleSearch(¶ms.conntrack, &adis, &ctrack, &bReverse)) + { + // invert direction. they are answering to this packet + bReverse = !bReverse; + DLOG("found conntrack entry. inverted reverse=%u\n",bReverse); + if (ctrack->dp_search_complete) + { + // RELATED icmp processed within base connection profile + dp = ctrack->dp; + DLOG("using desync profile %u (%s) from conntrack entry\n", dp->n, PROFILE_NAME(dp)); + } + } + else + DLOG("conntrack entry not found\n"); + } + } + + bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && *ifin && (!ifout || !*ifout)); + +#ifdef HAS_FILTER_SSID + ifname = bReverse ? ifin : ifout; + if ((ssid = wlan_ssid_search_ifname(ifname))) + DLOG("found ssid for %s : %s\n", ifname, ssid); + else if (!ctrack) + { + // we dont know direction for sure + // search opposite interface + ifname = bReverse ? ifout : ifin; + if ((ssid = wlan_ssid_search_ifname(ifname))) + DLOG("found ssid for %s : %s\n", ifname, ssid); + } +#endif + if (!dp) + { + bool hostname_is_ip = false; + char host[256]; + const char *hostname = NULL; + if (ctrack && ctrack->hostname) + { +printf("ZZZZZz4 %p\n",ctrack->hostname); + hostname = ctrack->hostname; + hostname_is_ip = ctrack->hostname_is_ip; + } + else if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, host, sizeof(host), &hostname_is_ip) && *host || + ipcache_get_hostname(dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, host, sizeof(host), &hostname_is_ip) && *host) + { + hostname = host; + } + + dp = dp_find( + ¶ms.desync_profiles, + dis->proto, + dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, + dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, + 0, dis->icmp->icmp_type, dis->icmp->icmp_code, + hostname, hostname_is_ip, + L7_UNKNOWN, ssid, NULL, NULL, NULL); + if (!dp) + { + DLOG("matching desync profile not found\n"); + return verdict; + } + } + + const struct in_addr *sdip4; + const struct in6_addr *sdip6; + sdip6 = dis->ip6 ? bReverseFixed ? &dis->ip6->ip6_src : &dis->ip6->ip6_dst : NULL; + sdip4 = dis->ip ? bReverseFixed ? &dis->ip->ip_src : &dis->ip->ip_dst : NULL; + + verdict = desync( + dp, fwmark, ifin, ifout, bReverseFixed, ctrack, NULL, l7payload, L7_UNKNOWN, + dis, sdip4, sdip6, 0, mod_pkt, len_mod_pkt, 0, 0, 0, NULL, 0, NULL, 0); + + return verdict; +} + +// undissected l4+ +// conntrack is unsupported +// ip matched in both directions +static uint8_t dpi_desync_ip_packet( + uint32_t fwmark, + const char *ifin, const char *ifout, + const struct dissect *dis, + uint8_t *mod_pkt, size_t *len_mod_pkt) +{ + uint8_t verdict = VERDICT_PASS; + + // additional safety check + if (!!dis->ip == !!dis->ip6) return verdict; + + struct sockaddr_storage src, dst; + const char *ssid; + struct desync_profile *dp; + + extract_endpoints(dis->ip, dis->ip6, NULL, NULL, &src, &dst); +#ifdef HAS_FILTER_SSID + if ((ssid = wlan_ssid_search_ifname(ifin))) + DLOG("found ssid for %s : %s\n", ifin, ssid); + else + { + // we dont know direction for sure + // search opposite interface + if ((ssid = wlan_ssid_search_ifname(ifout))) + DLOG("found ssid for %s : %s\n", ifout, ssid); + } +#endif + + bool hostname_is_ip = false; + const char *hostname = NULL; + char host[256]; + if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, host, sizeof(host), &hostname_is_ip) && *host || + ipcache_get_hostname(dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, host, sizeof(host), &hostname_is_ip) && *host) + { + hostname = host; + } + dp = dp_find( + ¶ms.desync_profiles, + dis->proto, + dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, + dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, + 0, 0xFF, 0xFF, + hostname, hostname_is_ip, + L7_UNKNOWN, ssid, NULL, NULL, NULL); + if (!dp) + { + DLOG("matching desync profile not found\n"); + return verdict; + } + + bool bReverse = ifin && *ifin && (!ifout || !*ifout); + + const struct in_addr *sdip4; + const struct in6_addr *sdip6; + sdip6 = dis->ip6 ? bReverse ? &dis->ip6->ip6_src : &dis->ip6->ip6_dst : NULL; + sdip4 = dis->ip ? bReverse ? &dis->ip->ip_src : &dis->ip->ip_dst : NULL; + + verdict = desync( + dp, fwmark, ifin, ifout, bReverse, NULL, NULL, L7P_UNKNOWN, L7_UNKNOWN, + dis, sdip4, sdip6, 0, mod_pkt, len_mod_pkt, 0, 0, 0, NULL, 0, NULL, 0); + + return verdict; } @@ -1831,19 +2095,19 @@ static uint8_t dpi_desync_packet_play( // NOTE ! OS can pass wrong checksum to queue. cannot rely on it ! - proto_dissect_l3l4(data_pkt, len_pkt, &dis); + proto_dissect_l3l4(data_pkt, len_pkt, &dis, false); if (!!dis.ip != !!dis.ip6) { packet_debug(!!replay_piece_count, &dis); + // fix csum if unmodified and if OS can pass wrong csum to queue (depends on OS) + // modified means we have already fixed the checksum or made it invalid intentionally + // this is the only point we VIOLATE const to fix the checksum in the original buffer to avoid copying to mod_pkt switch (dis.proto) { case IPPROTO_TCP: if (dis.tcp) { verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt); - // fix csum if unmodified and if OS can pass wrong csum to queue (depends on OS) - // modified means we have already fixed the checksum or made it invalid intentionally - // this is the only point we VIOLATE const to fix the checksum in the original buffer to avoid copying to mod_pkt verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6); } break; @@ -1851,12 +2115,19 @@ static uint8_t dpi_desync_packet_play( if (dis.udp) { verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt); - // fix csum if unmodified and if OS can pass wrong csum to queue (depends on OS) - // modified means we have already fixed the checksum or made it invalid intentionally - // this is the only point we VIOLATE const to fix the checksum in the original buffer to avoid copying to mod_pkt verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6); } break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + if (dis.icmp) + { + verdict = dpi_desync_icmp_packet(fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt); + verdict_icmp_csum_fix(verdict, (struct icmp46 *)dis.icmp, dis.transport_len, dis.ip6); + } + break; + default: + verdict = dpi_desync_ip_packet(fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt); } } return verdict; diff --git a/nfq2/filter.c b/nfq2/filter.c new file mode 100644 index 0000000..8a08d3d --- /dev/null +++ b/nfq2/filter.c @@ -0,0 +1,236 @@ +#include "filter.h" +#include +#include +#include +#include +#include + +bool pf_match(uint16_t port, const port_filter *pf) +{ + return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg); +} +bool pf_parse(const char *s, port_filter *pf) +{ + unsigned int v1,v2; + char c; + + if (!s) return false; + if (*s=='*' && s[1]==0) + { + pf->from=1; pf->to=0xFFFF; + return true; + } + if (*s=='~') + { + pf->neg=true; + s++; + } + else + pf->neg=false; + if (sscanf(s,"%u-%u%c",&v1,&v2,&c)==2) + { + if (v1>65535 || v2>65535 || v1>v2) return false; + pf->from=(uint16_t)v1; + pf->to=(uint16_t)v2; + } + else if (sscanf(s,"%u%c",&v1,&c)==1) + { + if (v1>65535) return false; + pf->to=pf->from=(uint16_t)v1; + } + else + return false; + // deny all case + if (!pf->from && !pf->to) pf->neg=true; + return true; +} + +static bool fltmode_parse(const char *s, uint8_t *mode) +{ + if (*s=='*' && !s[1]) + { + *mode = FLTMODE_ANY; + return true; + } + else if (*s=='-' && !s[1]) + { + *mode = FLTMODE_SKIP; + return true; + } + *mode = FLTMODE_SKIP; + return false; +} + +bool icf_match(uint8_t type, uint8_t code, const icmp_filter *icf) +{ + return icf->mode==FLTMODE_ANY || icf->mode==FLTMODE_FILTER && icf->type==type && (!icf->code_valid || icf->code==code); +} +bool icf_parse(const char *s, icmp_filter *icf) +{ + unsigned int u1,u2; + char c1,c2; + + icf->type = icf->code = 0; + icf->code_valid = false; + if (fltmode_parse(s, &icf->mode)) return true; + switch(sscanf(s,"%u%c%u%c",&u1,&c1,&u2,&c2)) + { + case 1: + if (u1>0xFF) return false; + icf->type = (uint8_t)u1; + icf->mode = FLTMODE_FILTER; + break; + case 3: + if (c1!=':' || (u1>0xFF) || (u2>0xFF)) return false; + icf->type = (uint8_t)u1; + icf->code = (uint8_t)u2; + icf->code_valid = true; + icf->mode = FLTMODE_FILTER; + break; + default: + icf->mode = FLTMODE_SKIP; + return false; + } + return true; +} + +bool ipp_match(uint8_t proto, const ipp_filter *ipp) +{ + return ipp->mode==FLTMODE_ANY || ipp->mode==FLTMODE_FILTER && ipp->proto==proto; +} +bool ipp_parse(const char *s, ipp_filter *ipp) +{ + unsigned int u1; + char c; + + ipp->proto = 0xFF; + if (fltmode_parse(s, &ipp->mode)) return true; + if (sscanf(s,"%u%c",&u1,&c)!=1 || u1>0xFF) return false; + ipp->proto = (uint8_t)u1; + ipp->mode = FLTMODE_FILTER; + return true; +} + +bool packet_pos_parse(const char *s, struct packet_pos *pos) +{ + if (*s!='n' && *s!='d' && *s!='s' && *s!='p' && *s!='b' && *s!='x' && *s!='a') return false; + pos->mode=*s; + if (pos->mode=='x' || pos->mode=='a') + { + pos->pos=0; + return true; + } + return sscanf(s+1,"%u",&pos->pos)==1; +} +bool packet_range_parse(const char *s, struct packet_range *range) +{ + const char *p; + + range->upper_cutoff = false; + if (*s=='-' || *s=='<') + { + range->from = PACKET_POS_ALWAYS; + range->upper_cutoff = *s=='<'; + } + else + { + if (!packet_pos_parse(s,&range->from)) return false; + if (range->from.mode=='x') + { + range->to = range->from; + return true; + } + if (!(p = strchr(s,'-'))) + p = strchr(s,'<'); + if (p) + { + s = p; + range->upper_cutoff = *s=='<'; + } + else + { + if (range->from.mode=='a') + { + range->to = range->from; + return true; + } + return false; + } + } + s++; + if (*s) + { + return packet_pos_parse(s,&range->to); + } + else + { + range->to = PACKET_POS_ALWAYS; + return true; + } +} + + +void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr) +{ + char s_ip[16]; + *s_ip=0; + inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip)); + snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen); +} +void print_cidr4(const struct cidr4 *cidr) +{ + char s[19]; + str_cidr4(s,sizeof(s),cidr); + printf("%s",s); +} +void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr) +{ + char s_ip[40]; + *s_ip=0; + inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip)); + snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen); +} +void print_cidr6(const struct cidr6 *cidr) +{ + char s[44]; + str_cidr6(s,sizeof(s),cidr); + printf("%s",s); +} +bool parse_cidr4(char *s, struct cidr4 *cidr) +{ + char *p,d; + bool b; + unsigned int plen; + + if ((p = strchr(s, '/'))) + { + if (sscanf(p + 1, "%u", &plen)!=1 || plen>32) + return false; + cidr->preflen = (uint8_t)plen; + d=*p; *p=0; // backup char + } + else + cidr->preflen = 32; + b = (inet_pton(AF_INET, s, &cidr->addr)==1); + if (p) *p=d; // restore char + return b; +} +bool parse_cidr6(char *s, struct cidr6 *cidr) +{ + char *p,d; + bool b; + unsigned int plen; + + if ((p = strchr(s, '/'))) + { + if (sscanf(p + 1, "%u", &plen)!=1 || plen>128) + return false; + cidr->preflen = (uint8_t)plen; + d=*p; *p=0; // backup char + } + else + cidr->preflen = 128; + b = (inet_pton(AF_INET6, s, &cidr->addr)==1); + if (p) *p=d; // restore char + return b; +} diff --git a/nfq2/filter.h b/nfq2/filter.h new file mode 100644 index 0000000..2a9f9ed --- /dev/null +++ b/nfq2/filter.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include + +typedef struct +{ + uint16_t from,to; + bool neg; +} port_filter; +bool pf_match(uint16_t port, const port_filter *pf); +bool pf_parse(const char *s, port_filter *pf); + +#define FLTMODE_SKIP 0 +#define FLTMODE_ANY 1 +#define FLTMODE_FILTER 2 +typedef struct +{ + uint8_t mode, type, code; + bool code_valid; +} icmp_filter; +bool icf_match(uint8_t type, uint8_t code, const icmp_filter *icf); +bool icf_parse(const char *s, icmp_filter *icf); + +typedef struct +{ + uint8_t mode, proto; +} ipp_filter; +bool ipp_match(uint8_t proto, const ipp_filter *ipp); +bool ipp_parse(const char *s, ipp_filter *ipp); + +struct packet_pos +{ + char mode; // n - packets, d - data packets, s - relative sequence + unsigned int pos; +}; +struct packet_range +{ + struct packet_pos from, to; + bool upper_cutoff; // true - do not include upper limit, false - include upper limit +}; +#define PACKET_POS_NEVER (struct packet_pos){'x',0} +#define PACKET_POS_ALWAYS (struct packet_pos){'a',0} +#define PACKET_RANGE_NEVER (struct packet_range){PACKET_POS_NEVER,PACKET_POS_NEVER} +#define PACKET_RANGE_ALWAYS (struct packet_range){PACKET_POS_ALWAYS,PACKET_POS_ALWAYS} +bool packet_range_parse(const char *s, struct packet_range *range); + +struct cidr4 +{ + struct in_addr addr; + uint8_t preflen; +}; +struct cidr6 +{ + struct in6_addr addr; + uint8_t preflen; +}; +void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr); +void print_cidr4(const struct cidr4 *cidr); +void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr); +void print_cidr6(const struct cidr6 *cidr); +bool parse_cidr4(char *s, struct cidr4 *cidr); +bool parse_cidr6(char *s, struct cidr6 *cidr); diff --git a/nfq2/helpers.c b/nfq2/helpers.c index 67ccc1f..58dc86a 100644 --- a/nfq2/helpers.c +++ b/nfq2/helpers.c @@ -448,107 +448,6 @@ bool file_open_test(const char *filename, int flags) return false; } -bool pf_in_range(uint16_t port, const port_filter *pf) -{ - return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg); -} -bool pf_parse(const char *s, port_filter *pf) -{ - unsigned int v1,v2; - char c; - - if (!s) return false; - if (*s=='*' && s[1]==0) - { - pf->from=1; pf->to=0xFFFF; - return true; - } - if (*s=='~') - { - pf->neg=true; - s++; - } - else - pf->neg=false; - if (sscanf(s,"%u-%u%c",&v1,&v2,&c)==2) - { - if (v1>65535 || v2>65535 || v1>v2) return false; - pf->from=(uint16_t)v1; - pf->to=(uint16_t)v2; - } - else if (sscanf(s,"%u%c",&v1,&c)==1) - { - if (v1>65535) return false; - pf->to=pf->from=(uint16_t)v1; - } - else - return false; - // deny all case - if (!pf->from && !pf->to) pf->neg=true; - return true; -} -bool pf_is_empty(const port_filter *pf) -{ - return !pf->neg && !pf->from && !pf->to; -} - -bool packet_pos_parse(const char *s, struct packet_pos *pos) -{ - if (*s!='n' && *s!='d' && *s!='s' && *s!='p' && *s!='b' && *s!='x' && *s!='a') return false; - pos->mode=*s; - if (pos->mode=='x' || pos->mode=='a') - { - pos->pos=0; - return true; - } - return sscanf(s+1,"%u",&pos->pos)==1; -} -bool packet_range_parse(const char *s, struct packet_range *range) -{ - const char *p; - - range->upper_cutoff = false; - if (*s=='-' || *s=='<') - { - range->from = PACKET_POS_ALWAYS; - range->upper_cutoff = *s=='<'; - } - else - { - if (!packet_pos_parse(s,&range->from)) return false; - if (range->from.mode=='x') - { - range->to = range->from; - return true; - } - if (!(p = strchr(s,'-'))) - p = strchr(s,'<'); - if (p) - { - s = p; - range->upper_cutoff = *s=='<'; - } - else - { - if (range->from.mode=='a') - { - range->to = range->from; - return true; - } - return false; - } - } - s++; - if (*s) - { - return packet_pos_parse(s,&range->to); - } - else - { - range->to = PACKET_POS_ALWAYS; - return true; - } -} void fill_random_bytes(uint8_t *p,size_t sz) { @@ -581,12 +480,55 @@ bool fill_crypto_random_bytes(uint8_t *p,size_t sz) return b; } +#if defined(__GNUC__) && !defined(__llvm__) +__attribute__((optimize ("no-strict-aliasing"))) +#endif +void bxor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz) +{ + for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8) + *(uint64_t*)result = *(uint64_t*)x1 ^ *(uint64_t*)x2; + for (; sz ; x1++, x2++, result++, sz--) + *result = *x1 ^ *x2; +} +#if defined(__GNUC__) && !defined(__llvm__) +__attribute__((optimize ("no-strict-aliasing"))) +#endif +void bor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz) +{ + for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8) + *(uint64_t*)result = *(uint64_t*)x1 | *(uint64_t*)x2; + for (; sz ; x1++, x2++, result++, sz--) + *result = *x1 | *x2; +} +#if defined(__GNUC__) && !defined(__llvm__) +__attribute__((optimize ("no-strict-aliasing"))) +#endif +void band(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz) +{ + for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8) + *(uint64_t*)result = *(uint64_t*)x1 & *(uint64_t*)x2; + for (; sz ; x1++, x2++, result++, sz--) + *result = *x1 & *x2; +} + + void set_console_io_buffering(void) { setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); } +void close_std(void) +{ + // free memory allocated by setvbuf + fclose(stdout); + fclose(stderr); +} +void close_std_and_exit(int code) +{ + close_std(); + exit(code); +} bool set_env_exedir(const char *argv0) { @@ -601,73 +543,6 @@ bool set_env_exedir(const char *argv0) return bOK; } - - -void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr) -{ - char s_ip[16]; - *s_ip=0; - inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip)); - snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen); -} -void print_cidr4(const struct cidr4 *cidr) -{ - char s[19]; - str_cidr4(s,sizeof(s),cidr); - printf("%s",s); -} -void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr) -{ - char s_ip[40]; - *s_ip=0; - inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip)); - snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen); -} -void print_cidr6(const struct cidr6 *cidr) -{ - char s[44]; - str_cidr6(s,sizeof(s),cidr); - printf("%s",s); -} -bool parse_cidr4(char *s, struct cidr4 *cidr) -{ - char *p,d; - bool b; - unsigned int plen; - - if ((p = strchr(s, '/'))) - { - if (sscanf(p + 1, "%u", &plen)!=1 || plen>32) - return false; - cidr->preflen = (uint8_t)plen; - d=*p; *p=0; // backup char - } - else - cidr->preflen = 32; - b = (inet_pton(AF_INET, s, &cidr->addr)==1); - if (p) *p=d; // restore char - return b; -} -bool parse_cidr6(char *s, struct cidr6 *cidr) -{ - char *p,d; - bool b; - unsigned int plen; - - if ((p = strchr(s, '/'))) - { - if (sscanf(p + 1, "%u", &plen)!=1 || plen>128) - return false; - cidr->preflen = (uint8_t)plen; - d=*p; *p=0; // backup char - } - else - cidr->preflen = 128; - b = (inet_pton(AF_INET6, s, &cidr->addr)==1); - if (p) *p=d; // restore char - return b; -} - bool parse_int16(const char *p, int16_t *v) { if (*p == '+' || *p == '-' || *p >= '0' && *p <= '9') @@ -678,3 +553,29 @@ bool parse_int16(const char *p, int16_t *v) } return false; } + +uint32_t mask_from_bitcount(uint32_t zct) +{ + return zct<32 ? ~((1u << zct) - 1) : 0; +} +static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a) +{ + if (zct >= 128) + memset(a->s6_addr,0x00,16); + else + { + int32_t n = (127 - zct) >> 3; + memset(a->s6_addr,0xFF,n); + memset(a->s6_addr+n,0x00,16-n); + a->s6_addr[n] = ~((1u << (zct & 7)) - 1); + } +} +static struct in6_addr ip6_mask[129]; +void mask_from_bitcount6_prepare(void) +{ + for (int zct=0;zct<=128;zct++) mask_from_bitcount6_make(zct, ip6_mask+zct); +} +const struct in6_addr *mask_from_bitcount6(uint32_t zct) +{ + return ip6_mask+zct; +} diff --git a/nfq2/helpers.h b/nfq2/helpers.h index ff922bc..ad0841d 100644 --- a/nfq2/helpers.h +++ b/nfq2/helpers.h @@ -85,55 +85,22 @@ time_t file_mod_time(const char *filename); bool file_size(const char *filename, off_t *size); bool file_open_test(const char *filename, int flags); -typedef struct -{ - uint16_t from,to; - bool neg; -} port_filter; -bool pf_in_range(uint16_t port, const port_filter *pf); -bool pf_parse(const char *s, port_filter *pf); -bool pf_is_empty(const port_filter *pf); - -struct packet_pos -{ - char mode; // n - packets, d - data packets, s - relative sequence - unsigned int pos; -}; -struct packet_range -{ - struct packet_pos from, to; - bool upper_cutoff; // true - do not include upper limit, false - include upper limit -}; -#define PACKET_POS_NEVER (struct packet_pos){'x',0} -#define PACKET_POS_ALWAYS (struct packet_pos){'a',0} -#define PACKET_RANGE_NEVER (struct packet_range){PACKET_POS_NEVER,PACKET_POS_NEVER} -#define PACKET_RANGE_ALWAYS (struct packet_range){PACKET_POS_ALWAYS,PACKET_POS_ALWAYS} -bool packet_range_parse(const char *s, struct packet_range *range); - void fill_random_bytes(uint8_t *p,size_t sz); void fill_random_az(uint8_t *p,size_t sz); void fill_random_az09(uint8_t *p,size_t sz); bool fill_crypto_random_bytes(uint8_t *p,size_t sz); +void bxor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz); +void band(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz); +void bor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz); + void set_console_io_buffering(void); +void close_std(void); +void close_std_and_exit(int code); bool set_env_exedir(const char *argv0); - -struct cidr4 -{ - struct in_addr addr; - uint8_t preflen; -}; -struct cidr6 -{ - struct in6_addr addr; - uint8_t preflen; -}; -void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr); -void print_cidr4(const struct cidr4 *cidr); -void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr); -void print_cidr6(const struct cidr6 *cidr); -bool parse_cidr4(char *s, struct cidr4 *cidr); -bool parse_cidr6(char *s, struct cidr6 *cidr); - bool parse_int16(const char *p, int16_t *v); + +uint32_t mask_from_bitcount(uint32_t zct); +void mask_from_bitcount6_prepare(void); +const struct in6_addr *mask_from_bitcount6(uint32_t zct); diff --git a/nfq2/hostlist.c b/nfq2/hostlist.c index ec31b60..fcc71da 100644 --- a/nfq2/hostlist.c +++ b/nfq2/hostlist.c @@ -42,7 +42,7 @@ bool AppendHostlistItem(hostlist_pool **hostlist, char *s) bool AppendHostList(hostlist_pool **hostlist, const char *filename) { - char *p, *e, s[256], *zbuf; + char *p, *e, s[4096], *zbuf; size_t zsize; int ct = 0; FILE *F; diff --git a/nfq2/ipset.c b/nfq2/ipset.c index 115f00d..55add05 100644 --- a/nfq2/ipset.c +++ b/nfq2/ipset.c @@ -59,7 +59,7 @@ bool AppendIpsetItem(ipset *ips, char *ip) static bool AppendIpset(ipset *ips, const char *filename) { - char *p, *e, s[256], *zbuf; + char *p, *e, s[4096], *zbuf; size_t zsize; int ct = 0; FILE *F; @@ -215,7 +215,11 @@ bool IpsetsReloadCheckForProfile(const struct desync_profile *dp) return IpsetsReloadCheck(&dp->ips_collection) && IpsetsReloadCheck(&dp->ips_collection_exclude); } -static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ipset_collection_head *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6) +static bool IpsetCheck_( + const struct ipset_collection_head *ips, const struct ipset_collection_head *ips_exclude, + const struct in_addr *ipv4, const struct in6_addr *ipv6, + const struct in_addr *ipv4r, const struct in6_addr *ipv6r +) { struct ipset_item *item; @@ -227,6 +231,12 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed"); if (SearchIpset(&item->hfile->ipset, ipv4, ipv6)) return false; + if (ipv4r || ipv6r) + { + DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed"); + if (SearchIpset(&item->hfile->ipset, ipv4r, ipv6r)) + return false; + } } // old behavior compat: all include lists are empty means check passes if (!ipset_collection_is_empty(ips)) @@ -236,17 +246,26 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed"); if (SearchIpset(&item->hfile->ipset, ipv4, ipv6)) return true; + if (ipv4r || ipv6r) + { + DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed"); + if (SearchIpset(&item->hfile->ipset, ipv4r, ipv6r)) + return true; + } } return false; } return true; } -bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6) +bool IpsetCheck( + const struct desync_profile *dp, + const struct in_addr *ipv4, const struct in6_addr *ipv6, + const struct in_addr *ipv4r, const struct in6_addr *ipv6r) { if (PROFILE_IPSETS_ABSENT(dp)) return true; DLOG("* ipset check for profile %u (%s)\n",dp->n,PROFILE_NAME(dp)); - return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6); + return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6,ipv4r,ipv6r); } diff --git a/nfq2/ipset.h b/nfq2/ipset.h index b711ac5..36bd7dd 100644 --- a/nfq2/ipset.h +++ b/nfq2/ipset.h @@ -6,7 +6,10 @@ #include "pools.h" bool LoadAllIpsets(); -bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6); +bool IpsetCheck( + const struct desync_profile *dp, + const struct in_addr *ipv4, const struct in6_addr *ipv6, + const struct in_addr *ipv4r, const struct in6_addr *ipv6r); struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename); void IpsetsDebug(); bool AppendIpsetItem(ipset *ips, char *ip); diff --git a/nfq2/lua.c b/nfq2/lua.c index c623f91..4509d33 100644 --- a/nfq2/lua.c +++ b/nfq2/lua.c @@ -1,15 +1,37 @@ #include #include #include +#include #include -#ifdef __FreeBSD__ -#include -#elif defined(__linux__) -#include -#elif defined(__CYGWIN__) -#include -#endif +#include #include +#include +#include + +#ifdef __FreeBSD__ + +#include + +#elif defined(__linux__) + +#include + +#elif defined(__CYGWIN__) + +#include + +// header hell conflicts between unix and win32 +typedef struct in6_addr IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR; +typedef struct sockaddr *LPSOCKADDR; +typedef struct _SOCKET_ADDRESS { + LPSOCKADDR lpSockaddr; + int iSockaddrLength; +} SOCKET_ADDRESS,*PSOCKET_ADDRESS,*LPSOCKET_ADDRESS; +#define _WINSOCK2API_ +#define _NETIOAPI_H_ +#include + +#endif #include "lua.h" #include "params.h" @@ -67,6 +89,18 @@ static int luacall_DLOG_CONDUP(lua_State *L) return 0; } +const char *lua_reqlstring(lua_State *L,int idx,size_t *len) +{ + luaL_checktype(L,idx,LUA_TSTRING); + return lua_tolstring(L,idx,len); +} +const char *lua_reqstring(lua_State *L,int idx) +{ + luaL_checktype(L,idx,LUA_TSTRING); + return lua_tostring(L,idx); +} + + static int luacall_bitlshift(lua_State *L) { lua_check_argc(L,"bitlshift",2); @@ -213,7 +247,7 @@ static int luacall_u8(lua_State *L) int argc=lua_gettop(L); size_t l; lua_Integer offset; - const uint8_t *p = (uint8_t*)luaL_checklstring(L,1,&l); + const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+1)>l) luaL_error(L, "out of range"); @@ -227,7 +261,7 @@ static int luacall_u16(lua_State *L) int argc=lua_gettop(L); size_t l; lua_Integer offset; - const uint8_t *p = (uint8_t*)luaL_checklstring(L,1,&l); + const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+2)>l) luaL_error(L, "out of range"); @@ -241,7 +275,7 @@ static int luacall_u24(lua_State *L) int argc=lua_gettop(L); size_t l; lua_Integer offset; - const uint8_t *p = (uint8_t*)luaL_checklstring(L,1,&l); + const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+3)>l) luaL_error(L, "out of range"); @@ -255,7 +289,7 @@ static int luacall_u32(lua_State *L) int argc=lua_gettop(L); size_t l; lua_Integer offset; - const uint8_t *p = (uint8_t*)luaL_checklstring(L,1,&l); + const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+4)>l) luaL_error(L, "out of range"); @@ -269,7 +303,7 @@ static int luacall_u48(lua_State *L) int argc=lua_gettop(L); size_t l; lua_Integer offset; - const uint8_t *p = (uint8_t*)luaL_checklstring(L,1,&l); + const uint8_t *p = (uint8_t*)lua_reqlstring(L,1,&l); offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0; if (offset<0 || (offset+6)>l) luaL_error(L, "out of range"); @@ -495,7 +529,7 @@ static int luacall_parse_hex(lua_State *L) LUA_STACK_GUARD_ENTER(L) size_t l; - const char *hex = luaL_checklstring(L,1,&l); + const char *hex = lua_reqlstring(L,1,&l); if ((l&1)) goto err; l>>=1; uint8_t *p = malloc(l); @@ -553,6 +587,40 @@ static int luacall_bcryptorandom(lua_State *L) LUA_STACK_GUARD_RETURN(L,1) } + +static int luac_bop(lua_State *L, const char *name, void (*op)(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)) +{ + lua_check_argc(L,name,2); + + LUA_STACK_GUARD_ENTER(L) + + size_t sz1,sz2; + const uint8_t *d1 = (const uint8_t*)lua_reqlstring(L,1,&sz1); + const uint8_t *d2 = (const uint8_t*)lua_reqlstring(L,2,&sz2); + if (sz1!=sz2) luaL_error(L, "string lengths must be the same\n"); + uint8_t *d3 = malloc(sz1); + if (!d3) luaL_error(L, "out of memory"); + + op(d1,d2,d3,sz1); + + lua_pushlstring(L,(char*)d3,sz1); + free(d3); + + LUA_STACK_GUARD_RETURN(L,1) +} +static int luacall_bxor(lua_State *L) +{ + return luac_bop(L,"bxor",bxor); +} +static int luacall_bor(lua_State *L) +{ + return luac_bop(L,"bor",bor); +} +static int luacall_band(lua_State *L) +{ + return luac_bop(L,"band",band); +} + static int luacall_hash(lua_State *L) { // hash(hash_type, data) returns hash @@ -564,7 +632,7 @@ static int luacall_hash(lua_State *L) SHAversion sha_ver = lua_hash_type(L, s_hash_type); size_t data_len; - const uint8_t *data = (uint8_t*)luaL_checklstring(L,2,&data_len); + const uint8_t *data = (uint8_t*)lua_reqlstring(L,2,&data_len); unsigned char hash[USHAMaxHashSize]; USHAContext tcontext; @@ -585,11 +653,11 @@ static int luacall_aes(lua_State *L) bool bEncrypt = lua_toboolean(L,1); size_t key_len; - const uint8_t *key = (uint8_t*)luaL_checklstring(L,2,&key_len); + const uint8_t *key = (uint8_t*)lua_reqlstring(L,2,&key_len); if (key_len!=16 && key_len!=24 && key_len!=32) luaL_error(L, "aes: wrong key length %u. should be 16,24,32.", (unsigned)key_len); size_t input_len; - const uint8_t *input = (uint8_t*)luaL_checklstring(L,3,&input_len); + const uint8_t *input = (uint8_t*)lua_reqlstring(L,3,&input_len); if (input_len!=16) luaL_error(L, "aes: wrong data length %u. should be 16.", (unsigned)input_len); @@ -613,17 +681,17 @@ static int luacall_aes_gcm(lua_State *L) int argc = lua_gettop(L); bool bEncrypt = lua_toboolean(L,1); size_t key_len; - const uint8_t *key = (uint8_t*)luaL_checklstring(L,2,&key_len); + const uint8_t *key = (uint8_t*)lua_reqlstring(L,2,&key_len); if (key_len!=16 && key_len!=24 && key_len!=32) luaL_error(L, "aes_gcm: wrong key length %u. should be 16,24,32.", (unsigned)key_len); size_t iv_len; - const uint8_t *iv = (uint8_t*)luaL_checklstring(L,3,&iv_len); + const uint8_t *iv = (uint8_t*)lua_reqlstring(L,3,&iv_len); if (iv_len!=12) luaL_error(L, "aes_gcm: wrong iv length %u. should be 12.", (unsigned)iv_len); size_t input_len; - const uint8_t *input = (uint8_t*)luaL_checklstring(L,4,&input_len); + const uint8_t *input = (uint8_t*)lua_reqlstring(L,4,&input_len); size_t add_len=0; - const uint8_t *add = lua_isnoneornil(L,5) ? NULL : (uint8_t*)luaL_checklstring(L,5,&add_len); + const uint8_t *add = lua_isnoneornil(L,5) ? NULL : (uint8_t*)lua_reqlstring(L,5,&add_len); uint8_t atag[16]; uint8_t *output = malloc(input_len); @@ -652,12 +720,12 @@ static int luacall_aes_ctr(lua_State *L) LUA_STACK_GUARD_ENTER(L) size_t key_len; - const uint8_t *key = (uint8_t*)luaL_checklstring(L,1,&key_len); + const uint8_t *key = (uint8_t*)lua_reqlstring(L,1,&key_len); if (key_len!=16 && key_len!=24 && key_len!=32) luaL_error(L, "aes_ctr: wrong key length %u. should be 16,24,32.", (unsigned)key_len); size_t iv_len; - const uint8_t *iv = (uint8_t*)luaL_checklstring(L,2,&iv_len); + const uint8_t *iv = (uint8_t*)lua_reqlstring(L,2,&iv_len); if (iv_len!=16) luaL_error(L, "aes_ctr: wrong iv length %u. should be 16.", (unsigned)iv_len); @@ -1175,6 +1243,32 @@ void lua_pushf_blob(lua_State *L, int idx_desync, const char *field, const char lua_rawset(L,-3); } +void lua_push_ipaddr(lua_State *L, const struct sockaddr *sa) +{ + switch(sa ? sa->sa_family : 0) + { + case AF_INET: + lua_pushlstring(L, (const char*)&((struct sockaddr_in*)sa)->sin_addr, sizeof(struct in_addr)); + break; + case AF_INET6: + lua_pushlstring(L, (const char*)&((struct sockaddr_in6*)sa)->sin6_addr, sizeof(struct in6_addr)); + break; + default: + lua_pushnil(L); + } +} +void lua_pushf_ipaddr(lua_State *L, const char *field, const struct sockaddr *sa) +{ + lua_pushstring(L, field); + lua_push_ipaddr(L,sa); + lua_rawset(L,-3); +} +void lua_pushi_ipaddr(lua_State *L, lua_Integer idx, const struct sockaddr *sa) +{ + lua_pushinteger(L, idx); + lua_push_ipaddr(L,sa); + lua_rawset(L,-3); +} void lua_pushf_tcphdr_options(lua_State *L, const struct tcphdr *tcp, size_t len) { @@ -1217,11 +1311,10 @@ void lua_pushf_tcphdr_options(lua_State *L, const struct tcphdr *tcp, size_t len LUA_STACK_GUARD_LEAVE(L, 0) } -void lua_pushf_tcphdr(lua_State *L, const struct tcphdr *tcp, size_t len) +void lua_push_tcphdr(lua_State *L, const struct tcphdr *tcp, size_t len) { LUA_STACK_GUARD_ENTER(L) - lua_pushliteral(L, "tcp"); if (tcp && len>=sizeof(struct tcphdr)) { lua_createtable(L, 0, 11); @@ -1239,15 +1332,37 @@ void lua_pushf_tcphdr(lua_State *L, const struct tcphdr *tcp, size_t len) } else lua_pushnil(L); + + LUA_STACK_GUARD_LEAVE(L, 1) +} +void lua_pushf_tcphdr(lua_State *L, const struct tcphdr *tcp, size_t len) +{ + LUA_STACK_GUARD_ENTER(L) + + lua_pushliteral(L, "tcp"); + lua_push_tcphdr(L,tcp,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } -void lua_pushf_udphdr(lua_State *L, const struct udphdr *udp, size_t len) +static int luacall_dissect_tcphdr(lua_State *L) +{ + // dissect_tcphdr(tcphdr_data) + lua_check_argc(L,"dissect_tcphdr",1); + + LUA_STACK_GUARD_ENTER(L) + + size_t len; + const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); + + lua_push_tcphdr(L, (struct tcphdr*)data, len); + + LUA_STACK_GUARD_RETURN(L,1) +} +void lua_push_udphdr(lua_State *L, const struct udphdr *udp, size_t len) { LUA_STACK_GUARD_ENTER(L) - lua_pushliteral(L, "udp"); if (udp && len>=sizeof(struct udphdr)) { lua_createtable(L, 0, 4); @@ -1258,15 +1373,77 @@ void lua_pushf_udphdr(lua_State *L, const struct udphdr *udp, size_t len) } else lua_pushnil(L); + + LUA_STACK_GUARD_LEAVE(L, 1) +} +void lua_pushf_udphdr(lua_State *L, const struct udphdr *udp, size_t len) +{ + LUA_STACK_GUARD_ENTER(L) + + lua_pushliteral(L, "udp"); + lua_push_udphdr(L,udp,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } -void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len) +static int luacall_dissect_udphdr(lua_State *L) +{ + // dissect_udphdr(udphdr_data) + lua_check_argc(L,"dissect_udphdr",1); + + LUA_STACK_GUARD_ENTER(L) + + size_t len; + const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); + + lua_push_udphdr(L, (struct udphdr*)data, len); + + LUA_STACK_GUARD_RETURN(L,1) +} +void lua_push_icmphdr(lua_State *L, const struct icmp46 *icmp, size_t len) { LUA_STACK_GUARD_ENTER(L) - lua_pushliteral(L, "ip"); + if (icmp && len>=sizeof(struct icmp46)) + { + lua_createtable(L, 0, 4); + lua_pushf_int(L,"icmp_type",icmp->icmp_type); + lua_pushf_int(L,"icmp_code",icmp->icmp_code); + lua_pushf_int(L,"icmp_cksum",ntohs(icmp->icmp_cksum)); + lua_pushf_int(L,"icmp_data",ntohl(icmp->icmp_data32)); + } + else + lua_pushnil(L); + + LUA_STACK_GUARD_LEAVE(L, 1) +} +void lua_pushf_icmphdr(lua_State *L, const struct icmp46 *icmp, size_t len) +{ + LUA_STACK_GUARD_ENTER(L) + + lua_pushliteral(L, "icmp"); + lua_push_icmphdr(L,icmp,len); + lua_rawset(L,-3); + + LUA_STACK_GUARD_LEAVE(L, 0) +} +static int luacall_dissect_icmphdr(lua_State *L) +{ + // dissect_icmphdr(icmphdr_data) + lua_check_argc(L,"dissect_icmphdr",1); + + LUA_STACK_GUARD_ENTER(L) + + size_t len; + const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); + + lua_push_icmphdr(L, (struct icmp46*)data, len); + + LUA_STACK_GUARD_RETURN(L,1) +} +void lua_push_iphdr(lua_State *L, const struct ip *ip, size_t len) +{ + LUA_STACK_GUARD_ENTER(L) if (ip && len>=sizeof(struct ip)) { uint16_t hl = ip->ip_hl<<2; @@ -1288,10 +1465,31 @@ void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len) } else lua_pushnil(L); - lua_rawset(L,-3); + LUA_STACK_GUARD_LEAVE(L, 1) +} +void lua_pushf_iphdr(lua_State *L, const struct ip *ip, size_t len) +{ + LUA_STACK_GUARD_ENTER(L) + lua_pushliteral(L, "ip"); + lua_push_iphdr(L,ip,len); + lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } +static int luacall_dissect_iphdr(lua_State *L) +{ + // dissect_iphdr(iphdr_data) + lua_check_argc(L,"dissect_iphdr",1); + + LUA_STACK_GUARD_ENTER(L) + + size_t len; + const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); + + lua_push_iphdr(L, (struct ip*)data, len); + + LUA_STACK_GUARD_RETURN(L,1) +} void lua_pushf_ip6exthdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) { LUA_STACK_GUARD_ENTER(L); @@ -1358,11 +1556,10 @@ end: LUA_STACK_GUARD_LEAVE(L, 0) } -void lua_pushf_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) +void lua_push_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) { LUA_STACK_GUARD_ENTER(L) - lua_pushliteral(L, "ip6"); if (ip6) { lua_createtable(L, 0, 7); @@ -1376,21 +1573,45 @@ void lua_pushf_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) } else lua_pushnil(L); + + LUA_STACK_GUARD_LEAVE(L, 1) +} +void lua_pushf_ip6hdr(lua_State *L, const struct ip6_hdr *ip6, size_t len) +{ + LUA_STACK_GUARD_ENTER(L) + + lua_pushliteral(L, "ip6"); + lua_push_ip6hdr(L,ip6,len); lua_rawset(L,-3); LUA_STACK_GUARD_LEAVE(L, 0) } +static int luacall_dissect_ip6hdr(lua_State *L) +{ + // dissect_iphdr(ip6hdr_data) + lua_check_argc(L,"dissect_ip6hdr",1); + + LUA_STACK_GUARD_ENTER(L) + + size_t len; + const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); + + lua_push_ip6hdr(L, (struct ip6_hdr*)data, len); + + LUA_STACK_GUARD_RETURN(L,1) +} void lua_push_dissect(lua_State *L, const struct dissect *dis) { LUA_STACK_GUARD_ENTER(L) if (dis) { - lua_createtable(L, 0, 9); + lua_createtable(L, 0, 10); lua_pushf_iphdr(L,dis->ip, dis->len_l3); lua_pushf_ip6hdr(L,dis->ip6, dis->len_l3); lua_pushf_tcphdr(L,dis->tcp, dis->len_l4); lua_pushf_udphdr(L,dis->udp, dis->len_l4); + lua_pushf_icmphdr(L,dis->icmp, dis->len_l4); lua_pushf_int(L,"l4proto",dis->proto); lua_pushf_int(L,"transport_len",dis->transport_len); lua_pushf_int(L,"l3_len",dis->len_l3); @@ -1455,7 +1676,7 @@ void lua_pushf_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_posit lua_pushf_nil(L, "incoming_ttl"); lua_pushf_str(L, "l7proto", l7proto_str(ctrack->l7proto)); lua_pushf_str(L, "hostname", ctrack->hostname); - lua_pushf_bool(L, "hostname_is_ip", ctrack->hostname_is_ip); + if (ctrack->hostname) lua_pushf_bool(L, "hostname_is_ip", ctrack->hostname_is_ip); lua_pushf_reg(L, "lua_state", ctrack->lua_state); lua_pushf_bool(L, "lua_in_cutoff", ctrack->b_lua_in_cutoff); lua_pushf_bool(L, "lua_out_cutoff", ctrack->b_lua_out_cutoff); @@ -1573,10 +1794,11 @@ void lua_pushf_range(lua_State *L, const char *name, const struct packet_range * } -static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *badsum, bool *ip6_preserve_next, uint8_t *ip6_last_proto) +static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *keepsum, bool *badsum, bool *ip6_preserve_next, uint8_t *ip6_last_proto) { if (lua_isnoneornil(L,idx)) { + if (keepsum) *keepsum = false; if (badsum) *badsum = false; if (ip6_preserve_next) *ip6_preserve_next = false; if (ip6_last_proto) *ip6_last_proto = IPPROTO_NONE; @@ -1584,6 +1806,12 @@ static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *badsum, else { luaL_checktype(L, idx, LUA_TTABLE); + if (keepsum) + { + lua_getfield(L, idx,"keepsum"); + *keepsum = lua_type(L,-1)!=LUA_TNIL && (lua_type(L,-1)!=LUA_TBOOLEAN || lua_toboolean(L,-1)); + lua_pop(L,1); + } if (badsum) { lua_getfield(L, idx,"badsum"); @@ -1659,6 +1887,7 @@ static bool lua_reconstruct_ip6exthdr(lua_State *L, int idx, struct ip6_hdr *ip6 } } } + // set last header proto if (!preserve_next) *last_proto = proto; @@ -1684,11 +1913,6 @@ bool lua_reconstruct_ip6hdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t * ip6->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(lua_type(L,-1)==LUA_TNUMBER ? (uint32_t)lua_tolint(L,-1) : 0x60000000); lua_pop(L, 1); - lua_getfield(L,idx,"ip6_plen"); - ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons((uint16_t)lua_tointeger(L,-1)); - - lua_pop(L, 1); - lua_getfield(L,idx,"ip6_nxt"); ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = (uint8_t)lua_tointeger(L,-1); lua_pop(L, 1); @@ -1711,12 +1935,28 @@ bool lua_reconstruct_ip6hdr(lua_State *L, int idx, struct ip6_hdr *ip6, size_t * ip6->ip6_dst = *(struct in6_addr*)p; lua_pop(L, 1); + bool have_plen = false; + lua_getfield(L,idx,"ip6_plen"); + switch (lua_type(L,-1)) + { + case LUA_TNIL: + break; + case LUA_TNUMBER: + ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons((uint16_t)luaL_checkinteger(L,-1)); + have_plen = true; + break; + default: + luaL_error(L,"reconstruct_ip6hdr: ip6_plen wrong type"); + } + lua_pop(L, 1); + bool b = lua_reconstruct_ip6exthdr(L, idx, ip6, len, last_proto, preserve_next); + if (b && !have_plen) ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = htons((uint16_t)(*len-sizeof(struct ip6_hdr))); + LUA_STACK_GUARD_LEAVE(L, 0) return b; err: lua_pop(L, 1); - LUA_STACK_GUARD_LEAVE(L, 0) return false; } @@ -1732,7 +1972,7 @@ static int luacall_reconstruct_ip6hdr(lua_State *L) uint8_t last_proto; bool preserve_next; - lua_reconstruct_extract_options(L, 2, NULL, &preserve_next, &last_proto); + lua_reconstruct_extract_options(L, 2, NULL, NULL, &preserve_next, &last_proto); if (!lua_reconstruct_ip6hdr(L, 1,(struct ip6_hdr*)data, &len, last_proto, preserve_next)) luaL_error(L, "invalid data for ip6hdr"); @@ -2035,6 +2275,51 @@ static int luacall_reconstruct_udphdr(lua_State *L) LUA_STACK_GUARD_RETURN(L,1) } +bool lua_reconstruct_icmphdr(lua_State *L, int idx, struct icmp46 *icmp) +{ + if (lua_type(L,-1)!=LUA_TTABLE) return false; + + LUA_STACK_GUARD_ENTER(L) + + lua_getfield(L,idx,"icmp_type"); + if (lua_type(L,-1)!=LUA_TNUMBER) goto err; + icmp->icmp_type = (uint8_t)lua_tointeger(L,-1); + lua_pop(L, 1); + + lua_getfield(L,idx,"icmp_code"); + if (lua_type(L,-1)!=LUA_TNUMBER) goto err; + icmp->icmp_code = (uint8_t)lua_tointeger(L,-1); + lua_pop(L, 1); + + lua_getfield(L,idx,"icmp_data"); + if (lua_type(L,-1)!=LUA_TNUMBER) goto err; + icmp->icmp_data32 = htonl((uint32_t)lua_tointeger(L,-1)); + lua_pop(L, 1); + + lua_getfield(L,idx,"icmp_cksum"); + icmp->icmp_cksum = htons((uint16_t)lua_tointeger(L,-1)); + lua_pop(L, 1); + + LUA_STACK_GUARD_LEAVE(L, 0) + return true; +err: + lua_pop(L, 1); + LUA_STACK_GUARD_LEAVE(L, 0) + return false; +} +static int luacall_reconstruct_icmphdr(lua_State *L) +{ + LUA_STACK_GUARD_ENTER(L) + + lua_check_argc(L,"reconstruct_icmphdr",1); + struct icmp46 icmp; + if (!lua_reconstruct_icmphdr(L,1,&icmp)) + luaL_error(L, "invalid data for icmphdr"); + lua_pushlstring(L,(char*)&icmp,sizeof(icmp)); + + LUA_STACK_GUARD_RETURN(L,1) +} + uint8_t lua_ip6_l4proto_from_dissect(lua_State *L, int idx) { int type; @@ -2047,10 +2332,28 @@ uint8_t lua_ip6_l4proto_from_dissect(lua_State *L, int idx) lua_getfield(L,idx,"udp"); type=lua_type(L,-1); lua_pop(L,1); - return type==LUA_TTABLE ? IPPROTO_UDP : IPPROTO_NONE; + if (type==LUA_TTABLE) return IPPROTO_UDP; + + lua_getfield(L,idx,"icmp"); + type=lua_type(L,-1); + lua_pop(L,1); + if (type==LUA_TTABLE) + { + lua_getfield(L,idx,"ip"); + type=lua_type(L,-1); + lua_pop(L,1); + if (type==LUA_TTABLE) return IPPROTO_ICMP; + + lua_getfield(L,idx,"ip6"); + type=lua_type(L,-1); + lua_pop(L,1); + if (type==LUA_TTABLE) return IPPROTO_ICMPV6; + } + + return IPPROTO_NONE; } -bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next) +bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, bool keepsum, bool badsum, bool ip6_preserve_next) { uint8_t *data = buf; size_t sz,l,lpayload,l3,left = *len; @@ -2058,6 +2361,7 @@ bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, b struct ip6_hdr *ip6=NULL; struct tcphdr *tcp=NULL; struct udphdr *udp=NULL; + struct icmp46 *icmp=NULL; const char *p; LUA_STACK_GUARD_ENTER(L) @@ -2093,9 +2397,10 @@ bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, b lua_pop(L, 1); lua_getfield(L,idx,"tcp"); - l = left; + l=0; if (lua_type(L,-1)==LUA_TTABLE) { + l = left; tcp = (struct tcphdr*)data; if (!lua_reconstruct_tcphdr(L, -1, tcp, &l)) { @@ -2107,13 +2412,30 @@ bool lua_reconstruct_dissect(lua_State *L, int idx, uint8_t *buf, size_t *len, b { lua_pop(L, 1); lua_getfield(L,idx,"udp"); - l = sizeof(struct udphdr); - if (lua_type(L,-1)!=LUA_TTABLE || left0xFFFF) + if (tcp) { - DLOG_ERR("reconstruct_dissect: invalid payload length\n"); - goto err; + tcp_fix_checksum(tcp,l-l3,ip,ip6); + if (badsum) tcp->th_sum ^= 1 + (random() % 0xFFFF); + } + else if (udp) + { + sz = (uint16_t)(lpayload+sizeof(struct udphdr)); + if (sz>0xFFFF) + { + DLOG_ERR("reconstruct_dissect: invalid payload length\n"); + goto err; + } + udp->uh_ulen = htons((uint16_t)sz); + udp_fix_checksum(udp,l-l3,ip,ip6); + if (badsum) udp->uh_sum ^= 1 + (random() % 0xFFFF); + } + else if (icmp) + { + icmp_fix_checksum(icmp,l-l3,ip6); + if (badsum) icmp->icmp_cksum ^= 1 + (random() % 0xFFFF); } - udp->uh_ulen = htons((uint16_t)sz); - udp_fix_checksum(udp,l-l3,ip,ip6); - if (badsum) udp->uh_sum ^= 1 + (random() % 0xFFFF); - } - if (tcp) - { - tcp_fix_checksum(tcp,l-l3,ip,ip6); - if (badsum) tcp->th_sum ^= 1 + (random() % 0xFFFF); } if (ip) @@ -2227,10 +2558,10 @@ static int luacall_reconstruct_dissect(lua_State *L) uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16))); l = sizeof(buf); - bool ip6_preserve_next, badsum; - lua_reconstruct_extract_options(L, 2, &badsum, &ip6_preserve_next, NULL); + bool ip6_preserve_next, badsum, keepsum; + lua_reconstruct_extract_options(L, 2, &keepsum, &badsum, &ip6_preserve_next, NULL); - if (!lua_reconstruct_dissect(L, 1, buf, &l, badsum, ip6_preserve_next)) + if (!lua_reconstruct_dissect(L, 1, buf, &l, keepsum, badsum, ip6_preserve_next)) luaL_error(L, "invalid dissect data"); lua_pushlstring(L,(char*)buf,l); @@ -2245,10 +2576,10 @@ static int luacall_dissect(lua_State *L) LUA_STACK_GUARD_ENTER(L) size_t len; - const uint8_t *data = (const uint8_t*)luaL_checklstring(L, 1, &len); + const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &len); struct dissect dis; - proto_dissect_l3l4(data, len, &dis); + proto_dissect_l3l4(data, len, &dis, false); lua_push_dissect(L, &dis); @@ -2263,7 +2594,7 @@ static int luacall_csum_ip4_fix(lua_State *L) LUA_STACK_GUARD_ENTER(L) size_t l; - const uint8_t *data = (const uint8_t*)luaL_checklstring(L, 1, &l); + const uint8_t *data = (const uint8_t*)lua_reqlstring(L, 1, &l); if (l>60 || !proto_check_ipv4(data, l)) luaL_error(L, "invalid ip header"); @@ -2283,7 +2614,7 @@ static int luacall_csum_tcp_fix(lua_State *L) LUA_STACK_GUARD_ENTER(L) size_t l_ip; - const uint8_t *b_ip = (const uint8_t*)luaL_checklstring(L, 1, &l_ip); + const uint8_t *b_ip = (const uint8_t*)lua_reqlstring(L, 1, &l_ip); const struct ip *ip=NULL; const struct ip6_hdr *ip6=NULL; @@ -2295,12 +2626,12 @@ static int luacall_csum_tcp_fix(lua_State *L) luaL_error(L, "invalid ip header"); size_t l_tcp; - const uint8_t *b_tcp = (const uint8_t*)luaL_checklstring(L, 2, &l_tcp); + const uint8_t *b_tcp = (const uint8_t*)lua_reqlstring(L, 2, &l_tcp); if (!proto_check_tcp(b_tcp, l_tcp)) luaL_error(L, "invalid tcp header"); size_t l_pl; - const uint8_t *b_pl = (const uint8_t*)luaL_checklstring(L, 3, &l_pl); + const uint8_t *b_pl = (const uint8_t*)lua_reqlstring(L, 3, &l_pl); if (l_pl>0xFFFF) luaL_error(L, "invalid payload length"); @@ -2326,7 +2657,7 @@ static int luacall_csum_udp_fix(lua_State *L) LUA_STACK_GUARD_ENTER(L) size_t l_ip; - const uint8_t *b_ip = (const uint8_t*)luaL_checklstring(L, 1, &l_ip); + const uint8_t *b_ip = (const uint8_t*)lua_reqlstring(L, 1, &l_ip); const struct ip *ip=NULL; const struct ip6_hdr *ip6=NULL; @@ -2338,12 +2669,12 @@ static int luacall_csum_udp_fix(lua_State *L) luaL_error(L, "invalid ip header"); size_t l_udp; - const uint8_t *b_udp = (const uint8_t*)luaL_checklstring(L, 2, &l_udp); + const uint8_t *b_udp = (const uint8_t*)lua_reqlstring(L, 2, &l_udp); if (!proto_check_udp(b_udp, l_udp)) luaL_error(L, "invalid udp header"); size_t l_pl; - const uint8_t *b_pl = (const uint8_t*)luaL_checklstring(L, 3, &l_pl); + const uint8_t *b_pl = (const uint8_t*)lua_reqlstring(L, 3, &l_pl); if (l_pl>0xFFFF) luaL_error(L, "invalid payload length"); @@ -2361,6 +2692,49 @@ static int luacall_csum_udp_fix(lua_State *L) LUA_STACK_GUARD_RETURN(L,1) } +static int luacall_csum_icmp_fix(lua_State *L) +{ + // csum_icmp_fix(ip_header, icmp_header, payload) returns icmp_header + lua_check_argc(L,"csum_icmp_fix",3); + + LUA_STACK_GUARD_ENTER(L) + + size_t l_ip; + const uint8_t *b_ip = (const uint8_t*)lua_reqlstring(L, 1, &l_ip); + const struct ip *ip=NULL; + const struct ip6_hdr *ip6=NULL; + + if (proto_check_ipv4(b_ip, l_ip)) + ip = (struct ip*)b_ip; + else if (proto_check_ipv6(b_ip, l_ip)) + ip6 = (struct ip6_hdr*)b_ip; + else + luaL_error(L, "invalid ip header"); + + size_t l_icmp; + const uint8_t *b_icmp = (const uint8_t*)lua_reqlstring(L, 2, &l_icmp); + if (!proto_check_icmp(b_icmp, l_icmp)) + luaL_error(L, "invalid icmp header"); + + size_t l_pl; + const uint8_t *b_pl = (const uint8_t*)lua_reqlstring(L, 3, &l_pl); + if (l_pl>0xFFFF) + luaL_error(L, "invalid payload length"); + + size_t l_tpl = l_icmp + l_pl; + uint8_t *tpl = malloc(l_tpl); + if (!tpl) luaL_error(L, "out of memory"); + + memcpy(tpl, b_icmp, l_icmp); + memcpy(tpl+l_icmp, b_pl, l_pl); + struct icmp46 *icmp = (struct icmp46*)tpl; + icmp_fix_checksum(icmp, l_tpl, ip6); + + lua_pushlstring(L,(char*)tpl,l_icmp); + free(tpl); + + LUA_STACK_GUARD_RETURN(L,1) +} static int luacall_ntop(lua_State *L) { @@ -2373,7 +2747,7 @@ static int luacall_ntop(lua_State *L) LUA_STACK_GUARD_ENTER(L) - p=luaL_checklstring(L,1,&l); + p=lua_reqlstring(L,1,&l); switch(l) { case sizeof(struct in_addr): @@ -2401,7 +2775,7 @@ static int luacall_pton(lua_State *L) LUA_STACK_GUARD_ENTER(L) - p=luaL_checkstring(L,1); + p=lua_reqstring(L,1); if (inet_pton(AF_INET,p,s)) lua_pushlstring(L,s,sizeof(struct in_addr)); else if (inet_pton(AF_INET6,p,s)) @@ -2462,7 +2836,7 @@ static int luacall_rawsend(lua_State *L) sockaddr_in46 sa; bool b; - data=(uint8_t*)luaL_checklstring(L,1,&len); + data=(uint8_t*)lua_reqlstring(L,1,&len); lua_rawsend_extract_options(L,2,&repeats,&fwmark,&ifout); if (!extract_dst(data, len, (struct sockaddr*)&sa)) @@ -2487,15 +2861,15 @@ static int luacall_rawsend_dissect(lua_State *L) int repeats; uint32_t fwmark; sockaddr_in46 sa; - bool b, badsum, ip6_preserve_next; + bool b, badsum, keepsum, ip6_preserve_next; uint8_t buf[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16))); len = sizeof(buf); luaL_checktype(L,1,LUA_TTABLE); lua_rawsend_extract_options(L,2, &repeats, &fwmark, &ifout); - lua_reconstruct_extract_options(L, 3, &badsum, &ip6_preserve_next, NULL); + lua_reconstruct_extract_options(L, 3, &keepsum, &badsum, &ip6_preserve_next, NULL); - if (!lua_reconstruct_dissect(L, 1, buf, &len, badsum, ip6_preserve_next)) + if (!lua_reconstruct_dissect(L, 1, buf, &len, keepsum, badsum, ip6_preserve_next)) luaL_error(L, "invalid dissect data"); if (!extract_dst(buf, len, (struct sockaddr*)&sa)) @@ -2507,6 +2881,211 @@ static int luacall_rawsend_dissect(lua_State *L) LUA_STACK_GUARD_RETURN(L,1) } +static int luacall_get_source_ip(lua_State *L) +{ + // get_source_ip(target_ip) + lua_check_argc(L,"get_source_ip",1); + + LUA_STACK_GUARD_ENTER(L) + + union + { + struct in_addr a4; + struct in6_addr a6; + } a; + size_t len; + const uint8_t *data = (uint8_t*)lua_reqlstring(L,1,&len); + + switch(len) + { + case sizeof(struct in_addr) : + if (get_source_ip4((struct in_addr*)data, &a.a4)) + lua_pushlstring(L,(char*)&a.a4,sizeof(a.a4)); + else + lua_pushnil(L); + break; + case sizeof(struct in6_addr) : + if (get_source_ip6((struct in6_addr*)data, &a.a6)) + lua_pushlstring(L,(char*)&a.a6,sizeof(a.a6)); + else + lua_pushnil(L); + break; + default: + luaL_error(L, "invalid IP length %u", (unsigned int)len); + } + + LUA_STACK_GUARD_RETURN(L,1) +} + +#ifdef __CYGWIN__ +#define GAA_FLAGS (GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST) +static int lua_get_ifaddrs(lua_State *L) +{ + LUA_STACK_GUARD_ENTER(L) + + ULONG Size=0; + if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAGS, NULL, NULL, &Size)==ERROR_BUFFER_OVERFLOW) + { + PIP_ADAPTER_ADDRESSES pip, pips = (PIP_ADAPTER_ADDRESSES)malloc(Size); + if (pips) + { + if (GetAdaptersAddresses(AF_UNSPEC, GAA_FLAGS, NULL, pips, &Size)==ERROR_SUCCESS) + { + lua_newtable(L); + for(pip=pips; pip ; pip=pip->Next) + { + if (!pip->FirstUnicastAddress || pip->OperStatus!=IfOperStatusUp) continue; // disconnected ? + + char ifname[16]; + snprintf(ifname,sizeof(ifname),"%u.0",pip->IfIndex); + lua_pushf_table(L,ifname); + lua_getfield(L,-1,ifname); + + lua_pushf_str(L, "guid", pip->AdapterName); + if (pip->PhysicalAddressLength) lua_pushf_lstr(L, "phys", pip->PhysicalAddress, pip->PhysicalAddressLength); + lua_pushf_int(L, "index", pip->IfIndex); + lua_pushf_int(L, "index6", pip->Ipv6IfIndex); + lua_pushf_int(L, "flags", pip->Flags); + lua_pushf_lint(L, "mtu", pip->Mtu); + lua_pushf_int(L, "iftype", pip->IfType); + lua_pushf_lint(L, "speed_xmit", pip->TransmitLinkSpeed); + lua_pushf_lint(L, "speed_recv", pip->ReceiveLinkSpeed); + lua_pushf_lint(L, "metric4", pip->Ipv4Metric); + lua_pushf_lint(L, "metric6", pip->Ipv6Metric); + lua_pushf_lint(L, "conntype", pip->ConnectionType); + lua_pushf_lint(L, "tunneltype", pip->TunnelType); + lua_pushf_table(L,"addr"); + lua_getfield(L,-1,"addr"); + + int n; + uint32_t a4,a44; + PIP_ADAPTER_UNICAST_ADDRESS_LH pa; + for(pa=pip->FirstUnicastAddress, n=1; pa ; pa=pa->Next, n++) + { + lua_pushi_table(L, n); + lua_rawgeti(L, -1, n); + lua_pushf_ipaddr(L, "addr", pa->Address.lpSockaddr); + switch(pa->Address.lpSockaddr->sa_family) + { + case AF_INET: + if (pa->OnLinkPrefixLength<=32) + { + a44 = mask_from_bitcount(pa->OnLinkPrefixLength); + a4 = ~a44; + lua_pushf_lstr(L, "netmask", (const char*)&a4, 4); + a4 &= ((struct sockaddr_in*)pa->Address.lpSockaddr)->sin_addr.s_addr; + a4 |= a44; + lua_pushf_lstr(L, "broadcast", (const char*)&a4, 4); + } + break; + case AF_INET6: + if (pa->OnLinkPrefixLength<=128) + { + lua_pushf_lstr(L, "netmask", (const char*)mask_from_bitcount6(128 - pa->OnLinkPrefixLength), 16); + } + break; + } + lua_pushf_ipaddr(L, "addr", pa->Address.lpSockaddr); + lua_pop(L,1); + } + lua_pop(L,2); + } + } + free (pips); + goto ok; + } + } + + lua_pushnil(L); + +ok: + LUA_STACK_GUARD_RETURN(L,1) +} +#else +// in cygwin this does not work with low intergity level because of cygwin objects in NT directory tree +static int lua_get_ifaddrs(lua_State *L) +{ + LUA_STACK_GUARD_ENTER(L) + + struct ifaddrs *addrs,*a; + unsigned int index; + lua_Integer li; + struct ifreq ifr; + const char *ifname; +#ifdef __CYGWIN__ + char ifname_buf[16]; +#endif + memset(&ifr,0,sizeof(ifr)); + + if (getifaddrs(&addrs)<0) + lua_pushnil(L); + else + { + int sock = socket(AF_INET,SOCK_DGRAM,0); + lua_newtable(L); + a = addrs; + for(a=addrs ; a ; a=a->ifa_next) + { + if (a->ifa_addr && (a->ifa_addr->sa_family==AF_INET || a->ifa_addr->sa_family==AF_INET6) && a->ifa_name && *a->ifa_name) + { +#ifdef __CYGWIN__ + // cygwin returns GUID interface names. windivert needs ifindex.subindex + if (index = if_nametoindex(a->ifa_name)) + { + snprintf(ifname_buf,sizeof(ifname_buf),"%u.0",index); + ifname = ifname_buf; + } +#else + ifname = a->ifa_name; +#endif + lua_getfield(L,-1,ifname); + if (lua_isnil(L,-1)) + { + lua_pop(L,1); + lua_pushf_table(L,ifname); + lua_getfield(L,-1,ifname); +#ifdef __CYGWIN__ + lua_pushf_str(L, "guid", a->ifa_name); +#else + index = if_nametoindex(ifname); +#endif + if (index) lua_pushf_int(L, "index", index); + lua_pushf_int(L, "flags", a->ifa_flags); +#ifdef HAS_FILTER_SSID + lua_pushf_str(L, "ssid", wlan_ssid_search_ifname(ifname)); +#endif + strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); + if (sock>=0 && !ioctl(sock, SIOCGIFMTU, &ifr)) + lua_pushf_int(L, "mtu", ifr.ifr_mtu); + + lua_pushf_table(L,"addr"); + } + lua_getfield(L,-1,"addr"); + li = lua_rawlen(L,-1)+1; + lua_pushi_table(L, li); + lua_rawgeti(L,-1,li); + lua_pushf_ipaddr(L, "addr", a->ifa_addr); + lua_pushf_ipaddr(L, "netmask", a->ifa_netmask); + lua_pushf_ipaddr(L, "broadcast", a->ifa_broadaddr); + lua_pushf_ipaddr(L, "dst", a->ifa_dstaddr); + lua_pop(L,3); + } + } + freeifaddrs(addrs); + if (sock>=0) close(sock); + } + + LUA_STACK_GUARD_RETURN(L,1) +} +#endif // CYGWIN + +static int luacall_get_ifaddrs(lua_State *L) +{ + lua_check_argc(L,"get_ifaddrs",0); + lua_get_ifaddrs(L); + return 1; +} + static int luacall_resolve_pos(lua_State *L) { // resolve_pos(blob,l7payload_type,marker[,zero_based_pos]) @@ -2516,9 +3095,9 @@ static int luacall_resolve_pos(lua_State *L) int argc=lua_gettop(L); size_t len; - const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); - const char *sl7payload = luaL_checkstring(L,2); - const char *smarker = luaL_checkstring(L,3); + const uint8_t *data = (uint8_t*)lua_reqlstring(L,1,&len); + const char *sl7payload = lua_reqstring(L,2); + const char *smarker = lua_reqstring(L,3); bool bZeroBased = argc>=4 && lua_toboolean(L,4); t_l7payload l7payload = l7payload_from_name(sl7payload); @@ -2546,9 +3125,9 @@ static int luacall_resolve_multi_pos(lua_State *L) int argc=lua_gettop(L); size_t len; - const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); - const char *sl7payload = luaL_checkstring(L,2); - const char *smarkers = luaL_checkstring(L,3); + const uint8_t *data = (uint8_t*)lua_reqlstring(L,1,&len); + const char *sl7payload = lua_reqstring(L,2); + const char *smarkers = lua_reqstring(L,3); bool bZeroBased = argc>=4 && lua_toboolean(L,4); t_l7payload l7payload = l7payload_from_name(sl7payload); @@ -2577,9 +3156,9 @@ static int luacall_resolve_range(lua_State *L) int argc=lua_gettop(L); size_t i,len; - const uint8_t *data = (uint8_t*)luaL_checklstring(L,1,&len); - const char *sl7payload = luaL_checkstring(L,2); - const char *smarkers = luaL_checkstring(L,3); + const uint8_t *data = (uint8_t*)lua_reqlstring(L,1,&len); + const char *sl7payload = lua_reqstring(L,2); + const char *smarkers = lua_reqstring(L,3); bool bStrict = argc>=4 && lua_toboolean(L,4); bool bZeroBased = argc>=5 && lua_toboolean(L,5); @@ -2627,13 +3206,13 @@ static int luacall_tls_mod(lua_State *L) size_t fake_tls_len; bool bRes; - const uint8_t *fake_tls = (uint8_t*)luaL_checklstring(L,1,&fake_tls_len); - const char *modlist = luaL_checkstring(L,2); + const uint8_t *fake_tls = (uint8_t*)lua_reqlstring(L,1,&fake_tls_len); + const char *modlist = lua_reqstring(L,2); size_t payload_len = 0; const uint8_t *payload = NULL; if (argc>=3 && lua_type(L,3)!=LUA_TNIL) - payload = (uint8_t*)luaL_checklstring(L,3,&payload_len); + payload = (uint8_t*)lua_reqlstring(L,3,&payload_len); struct fake_tls_mod mod; if (!TLSMod_parse_list(modlist, &mod)) @@ -3248,6 +3827,7 @@ static void lua_init_const(void) {"IP6_BASE_LEN",sizeof(struct ip6_hdr)}, {"TCP_BASE_LEN",sizeof(struct tcphdr)}, {"UDP_BASE_LEN",sizeof(struct udphdr)}, + {"ICMP_BASE_LEN",sizeof(struct icmp46)}, {"TCP_KIND_END",TCP_KIND_END}, {"TCP_KIND_NOOP",TCP_KIND_NOOP}, @@ -3300,7 +3880,62 @@ static void lua_init_const(void) {"IPPROTO_MH",IPPROTO_MH}, {"IPPROTO_HIP",IPPROTO_HIP}, {"IPPROTO_SHIM6",IPPROTO_SHIM6}, - {"IPPROTO_NONE",IPPROTO_NONE} + {"IPPROTO_NONE",IPPROTO_NONE}, + + // icmp types + {"ICMP_ECHOREPLY",ICMP_ECHOREPLY}, + {"ICMP_DEST_UNREACH",ICMP_DEST_UNREACH}, + {"ICMP_REDIRECT",ICMP_REDIRECT}, + {"ICMP_ECHO",ICMP_ECHO}, + {"ICMP_TIME_EXCEEDED",ICMP_TIME_EXCEEDED}, + {"ICMP_PARAMETERPROB",ICMP_PARAMETERPROB}, + {"ICMP_TIMESTAMP",ICMP_TIMESTAMP}, + {"ICMP_TIMESTAMPREPLY",ICMP_TIMESTAMPREPLY}, + {"ICMP_INFO_REQUEST",ICMP_INFO_REQUEST}, + {"ICMP_INFO_REPLY",ICMP_INFO_REPLY}, + + // icmp codes for UNREACH + {"ICMP_UNREACH_NET",ICMP_UNREACH_NET}, + {"ICMP_UNREACH_HOST",ICMP_UNREACH_HOST}, + {"ICMP_UNREACH_PROTOCOL",ICMP_UNREACH_PROTOCOL}, + {"ICMP_UNREACH_PORT",ICMP_UNREACH_PORT}, + {"ICMP_UNREACH_NEEDFRAG",ICMP_UNREACH_NEEDFRAG}, + {"ICMP_UNREACH_SRCFAIL",ICMP_UNREACH_SRCFAIL}, + {"ICMP_UNREACH_NET_UNKNOWN",ICMP_UNREACH_NET_UNKNOWN}, + {"ICMP_UNREACH_HOST_UNKNOWN",ICMP_UNREACH_HOST_UNKNOWN}, + {"ICMP_UNREACH_NET_PROHIB",ICMP_UNREACH_NET_PROHIB}, + {"ICMP_UNREACH_HOST_PROHIB",ICMP_UNREACH_HOST_PROHIB}, + {"ICMP_UNREACH_TOSNET",ICMP_UNREACH_TOSNET}, + {"ICMP_UNREACH_TOSHOST",ICMP_UNREACH_TOSHOST}, + {"ICMP_UNREACH_FILTER_PROHIB",ICMP_UNREACH_FILTER_PROHIB}, + {"ICMP_UNREACH_HOST_PRECEDENCE",ICMP_UNREACH_HOST_PRECEDENCE}, + {"ICMP_UNREACH_PRECEDENCE_CUTOFF",ICMP_UNREACH_PRECEDENCE_CUTOFF}, + + // icmp codes for REDIRECT + {"ICMP_REDIRECT_NET",ICMP_REDIRECT_NET}, + {"ICMP_REDIRECT_HOST",ICMP_REDIRECT_HOST}, + {"ICMP_REDIRECT_TOSNET",ICMP_REDIRECT_TOSNET}, + {"ICMP_REDIRECT_TOSHOST",ICMP_REDIRECT_TOSHOST}, + + // icmp codes for TIME_EXCEEDED + {"ICMP_TIMXCEED_INTRANS",ICMP_TIMXCEED_INTRANS}, + {"ICMP_TIMXCEED_REASS",ICMP_TIMXCEED_REASS}, + + // icmp6 types + {"ICMP6_ECHO_REQUEST",ICMP6_ECHO_REQUEST}, + {"ICMP6_ECHO_REPLY",ICMP6_ECHO_REPLY}, + {"ICMP6_DST_UNREACH",ICMP6_DST_UNREACH}, + {"ICMP6_PACKET_TOO_BIG",ICMP6_PACKET_TOO_BIG}, + {"ICMP6_TIME_EXCEEDED",ICMP6_TIME_EXCEEDED}, + {"ICMP6_PARAM_PROB",ICMP6_PARAM_PROB}, + {"MLD_LISTENER_QUERY",MLD_LISTENER_QUERY}, + {"MLD_LISTENER_REPORT",MLD_LISTENER_REPORT}, + {"MLD_LISTENER_REDUCTION",MLD_LISTENER_REDUCTION}, + {"ND_ROUTER_SOLICIT",ND_ROUTER_SOLICIT}, + {"ND_ROUTER_ADVERT",ND_ROUTER_ADVERT}, + {"ND_NEIGHBOR_SOLICIT",ND_NEIGHBOR_SOLICIT}, + {"ND_NEIGHBOR_ADVERT",ND_NEIGHBOR_ADVERT}, + {"ND_REDIRECT",ND_REDIRECT} }; DLOG("\nLUA NUMERIC:"); for (int i=0;i fd[1] ? fd[0] : fd[1]) + 1; + fdmax = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1; + } DLOG_CONDUP("initializing raw sockets\n"); if (!rawsend_preinit(false, false)) goto exiterr; - if (params.droproot && !droproot(params.uid, params.user, params.gid, params.gid_count)) goto exiterr; print_id(); @@ -503,23 +528,25 @@ static int dvt_main(void) if (!lua_test_init_script_files()) goto exiterr; + catch_signals(); + + if (!params.intercept) + { + if (params.daemon) daemonize(); + if (!write_pidfile(&Fpid)) goto exiterr; + } + if (!lua_init()) goto exiterr; - if (params.daemon) daemonize(); - - if (Fpid) + if (!params.intercept) { - if (fprintf(Fpid, "%d", getpid()) <= 0) - { - DLOG_PERROR("write pidfile"); - goto exiterr; - } - fclose(Fpid); - Fpid = NULL; + DLOG("no intercept quit\n"); + goto exitok; } - pre_desync(); + if (params.daemon) daemonize(); + if (!write_pidfile(&Fpid)) goto exiterr; for (;;) { @@ -637,6 +664,7 @@ static int win_main() int res=0; uint8_t packet[RECONSTRUCT_MAX_SIZE] __attribute__((aligned(16))); + // windows emulated fork logic does not cover objects outside of cygwin world. have to daemonize before inits if (params.daemon) daemonize(); if (*params.pidfile && !writepid(params.pidfile)) @@ -651,7 +679,7 @@ static int win_main() res=w_win32_error; goto ex; } - pre_desync(); + catch_signals(); for (;;) { @@ -675,6 +703,8 @@ static int win_main() res=w_win32_error; goto ex; } + DLOG_CONDUP(params.intercept ? "windivert initialized. capture is started.\n" : "windivert initialized\n"); + if (!win_sandbox()) { res=w_win32_error; @@ -688,7 +718,11 @@ static int win_main() res=ERROR_INVALID_PARAMETER; goto ex; } - DLOG_CONDUP("windivert initialized. capture is started.\n"); + if (!params.intercept) + { + DLOG("no intercept quit\n"); + goto ex; + } for (id = 0;; id++) { @@ -765,8 +799,7 @@ ex: static void exit_clean(int code) { cleanup_params(¶ms); - - exit(code); + close_std_and_exit(code); } @@ -1042,6 +1075,52 @@ static bool parse_pf_list(char *opt, struct port_filters_head *pfl) return true; } +static bool parse_icf_list(char *opt, struct icmp_filters_head *icfl) +{ + char *e, *p, c; + icmp_filter icf; + bool b; + + for (p = opt; p; ) + { + if ((e = strchr(p, ','))) + { + c = *e; + *e = 0; + } + + b = icf_parse(p, &icf) && icmp_filter_add(icfl, &icf); + if (e) *e++ = c; + if (!b) return false; + + p = e; + } + return true; +} + +static bool parse_ipp_list(char *opt, struct ipp_filters_head *ippl) +{ + char *e, *p, c; + ipp_filter ipp; + bool b; + + for (p = opt; p; ) + { + if ((e = strchr(p, ','))) + { + c = *e; + *e = 0; + } + + b = ipp_parse(p, &ipp) && ipp_filter_add(ippl, &ipp); + if (e) *e++ = c; + if (!b) return false; + + p = e; + } + return true; +} + bool lua_call_param_add(char *opt, struct str2_list_head *args) { char c,*p; @@ -1260,6 +1339,82 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu strncat(buf, ")", len - strlen(buf) - 1); return true; } +static bool wf_make_icf(char *opt, char *buf, size_t len) +{ + char *e, *p, c, s1[80]; + icmp_filter icf; + + if (len < 3) return false; + + for (p = opt, *buf = '(', buf[1] = 0; p;) + { + if ((e = strchr(p, ','))) + { + c = *e; + *e = 0; + } + if (!icf_parse(p, &icf)) return false; + switch(icf.mode) + { + case FLTMODE_FILTER: + if (icf.code_valid) + snprintf(s1, sizeof(s1), "icmp.Type==%u and icmp.Code==%u or icmpv6.Type==%u and icmpv6.Code==%u", icf.type, icf.code, icf.type, icf.code); + else + snprintf(s1, sizeof(s1), "icmp.Type==%u or icmpv6.Type==%u", icf.type, icf.type); + break; + case FLTMODE_ANY: + snprintf(s1, sizeof(s1), "icmp or icmpv6"); + break; + default: + goto dont_add; + } + if (buf[1]) strncat(buf, " or ", len - strlen(buf) - 1); + strncat(buf, s1, len - strlen(buf) - 1); +dont_add: + if (e) *e++ = c; + p = e; + } + if (!buf[1]) return false; // nothing added + strncat(buf, ")", len - strlen(buf) - 1); + return true; +} +static bool wf_make_ipf(char *opt, char *buf, size_t len) +{ + char *e, *p, c, s1[40]; + ipp_filter ipf; + + if (len < 3) return false; + + for (p = opt, *buf = '(', buf[1] = 0; p;) + { + if ((e = strchr(p, ','))) + { + c = *e; + *e = 0; + } + if (!ipp_parse(p, &ipf)) return false; + switch(ipf.mode) + { + case FLTMODE_FILTER: + // NOTE: windivert can't walk ipv6 extension headers. instead of real protocol first ext header type will be matched + snprintf(s1, sizeof(s1), "ip.Protocol==%u or ipv6.NextHdr==%u", ipf.proto, ipf.proto); + break; + case FLTMODE_ANY: + snprintf(s1, sizeof(s1), "ip or ipv6"); + break; + default: + goto dont_add; + } + if (buf[1]) strncat(buf, " or ", len - strlen(buf) - 1); + strncat(buf, s1, len - strlen(buf) - 1); +dont_add: + if (e) *e++ = c; + p = e; + } + if (!buf[1]) return false; // nothing added + strncat(buf, ")", len - strlen(buf) - 1); + return true; +} #define DIVERT_NO_LOCALNETSv4_DST "(" \ "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ @@ -1306,6 +1461,8 @@ static bool wf_make_filter( const char *pf_tcp_src_out, const char *pf_tcp_dst_out, const char *pf_tcp_src_in, const char *pf_tcp_dst_in, const char *pf_udp_src_in, const char *pf_udp_dst_out, + const char *icf_out, const char *icf_in, + const char *ipf_out, const char *ipf_in, const struct str_list_head *wf_raw_part, bool bFilterOutLAN, bool bFilterOutLoopback) { @@ -1354,6 +1511,11 @@ static bool wf_make_filter( if (*pf_udp_dst_out) snprintf(wf + strlen(wf), len - strlen(wf), " or\n outbound and %s", pf_udp_dst_out); if (*pf_udp_src_in) snprintf(wf + strlen(wf), len - strlen(wf), " or\n inbound and %s", pf_udp_src_in); + if (*icf_in) snprintf(wf + strlen(wf), len - strlen(wf), " or\n inbound and %s", icf_in); + if (*icf_out) snprintf(wf + strlen(wf), len - strlen(wf), " or\n outbound and %s", icf_out); + if (*ipf_in) snprintf(wf + strlen(wf), len - strlen(wf), " or\n inbound and %s", ipf_in); + if (*ipf_out) snprintf(wf + strlen(wf), len - strlen(wf), " or\n outbound and %s", ipf_out); + snprintf(wf + strlen(wf), len - strlen(wf), "\n)"); if (bFilterOutLAN) @@ -1403,6 +1565,7 @@ static void exithelp(void) " --version\t\t\t\t\t\t; print version and exit\n" " --dry-run\t\t\t\t\t\t; verify parameters and exit with code 0 if successful\n" " --comment=any_text\n" + " --intercept=0|1\t\t\t\t\t; enable interception. if disabled - run lua-init and exit\n" #ifdef __linux__ " --qnum=\n" #elif defined(BSD) @@ -1433,10 +1596,14 @@ static void exithelp(void) " --wf-iface=[.]\t\t\t\t; numeric network interface and subinterface indexes\n" " --wf-l3=ipv4|ipv6\t\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" " --wf-tcp-in=[~]port1[-port2]\t\t\t\t; TCP in port filter. ~ means negation. multiple comma separated values allowed.\n" - " --wf-udp-in=[~]port1[-port2]\t\t\t\t; UDP in port filter. ~ means negation. multiple comma separated values allowed.\n" " --wf-tcp-out=[~]port1[-port2]\t\t\t\t; TCP out port filter. ~ means negation. multiple comma separated values allowed.\n" + " --wf-udp-in=[~]port1[-port2]\t\t\t\t; UDP in port filter. ~ means negation. multiple comma separated values allowed.\n" " --wf-udp-out=[~]port1[-port2]\t\t\t\t; UDP out port filter. ~ means negation. multiple comma separated values allowed.\n" " --wf-tcp-empty=[0|1]\t\t\t\t\t; enable processing of empty tcp packets without flags SYN,RST,FIN (default : 0)\n" + " --wf-icmp-in=type[:code]\t\t\t\t; ICMP out filter. multiple comma separated values allowed.\n" + " --wf-icmp-out=type[:code]\t\t\t\t; ICMP in filter. multiple comma separated values allowed.\n" + " --wf-ipp-in=proto\t\t\t\t\t; IP protocol in filter. multiple comma separated values allowed.\n" + " --wf-ipp-out=proto\t\t\t\t\t; IP protocol out filter. multiple comma separated values allowed.\n" " --wf-raw-part=|@\t\t\t; partial raw windivert filter string or filename\n" " --wf-filter-lan=0|1\t\t\t\t\t; add excluding filter for non-global IP (default : 1)\n" " --wf-filter-loopback=0|1\t\t\t\t; add excluding filter for loopback (default : 1)\n" @@ -1461,8 +1628,10 @@ static void exithelp(void) " --cookie[=]\t\t\t\t\t; pass this profile-bound string to LUA\n" " --import=\t\t\t\t\t; populate current profile with template data\n" " --filter-l3=ipv4|ipv6\t\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n" - " --filter-tcp=[~]port1[-port2]|*\t\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list allowed.\n" - " --filter-udp=[~]port1[-port2]|*\t\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n" + " --filter-tcp=[~]port1[-port2]|*\t\t\t; TCP port filter. ~ means negation. setting tcp filter and not setting others denies others. comma separated list allowed.\n" + " --filter-udp=[~]port1[-port2]|*\t\t\t; UDP port filter. ~ means negation. setting udp filter and not setting others denies others. comma separated list allowed.\n" + " --filter-icmp=type[:code]|*\t\t\t\t; ICMP type+code filter. setting icmp filter and not setting others denies others. comma separated list allowed.\n" + " --filter-ipp=proto\t\t\t\t\t; IP protocol filter. setting up ipp filter and not setting others denies others. comma separated list allowed.\n" " --filter-l7=proto[,proto]\t\t\t\t; L6-L7 protocol filter : %s\n" #ifdef HAS_FILTER_SSID " --filter-ssid=ssid1[,ssid2,ssid3,...]\t\t\t; per profile wifi SSID filter\n" @@ -1504,7 +1673,7 @@ static void exithelp(void) HOSTLIST_AUTO_UDP_OUT, HOSTLIST_AUTO_UDP_IN, all_payloads ); - exit(1); + close_std_and_exit(1); } static void exithelp_clean(void) { @@ -1553,6 +1722,7 @@ static void ApplyDefaultBlobs(struct blob_collection_head *blobs) enum opt_indices { IDX_DEBUG, IDX_DRY_RUN, + IDX_INTERCEPT, IDX_VERSION, IDX_COMMENT, #ifdef __linux__ @@ -1610,6 +1780,8 @@ enum opt_indices { IDX_FILTER_L3, IDX_FILTER_TCP, IDX_FILTER_UDP, + IDX_FILTER_ICMP, + IDX_FILTER_IPP, IDX_FILTER_L7, #ifdef HAS_FILTER_SSID IDX_FILTER_SSID, @@ -1632,6 +1804,10 @@ enum opt_indices { IDX_WF_UDP_IN, IDX_WF_UDP_OUT, IDX_WF_TCP_EMPTY, + IDX_WF_ICMP_IN, + IDX_WF_ICMP_OUT, + IDX_WF_IPP_IN, + IDX_WF_IPP_OUT, IDX_WF_RAW, IDX_WF_RAW_PART, IDX_WF_FILTER_LAN, @@ -1648,6 +1824,7 @@ enum opt_indices { static const struct option long_options[] = { [IDX_DEBUG] = {"debug", optional_argument, 0, 0}, [IDX_DRY_RUN] = {"dry-run", no_argument, 0, 0}, + [IDX_INTERCEPT] = {"intercept", optional_argument, 0, 0}, [IDX_VERSION] = {"version", no_argument, 0, 0}, [IDX_COMMENT] = {"comment", optional_argument, 0, 0}, #ifdef __linux__ @@ -1702,6 +1879,8 @@ static const struct option long_options[] = { [IDX_FILTER_L3] = {"filter-l3", required_argument, 0, 0}, [IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0}, [IDX_FILTER_UDP] = {"filter-udp", required_argument, 0, 0}, + [IDX_FILTER_ICMP] = {"filter-icmp", required_argument, 0, 0}, + [IDX_FILTER_IPP] = {"filter-ipp", required_argument, 0, 0}, [IDX_FILTER_L7] = {"filter-l7", required_argument, 0, 0}, #ifdef HAS_FILTER_SSID [IDX_FILTER_SSID] = {"filter-ssid", required_argument, 0, 0}, @@ -1724,6 +1903,10 @@ static const struct option long_options[] = { [IDX_WF_UDP_IN] = {"wf-udp-in", required_argument, 0, 0}, [IDX_WF_UDP_OUT] = {"wf-udp-out", required_argument, 0, 0}, [IDX_WF_TCP_EMPTY] = {"wf-tcp-empty", optional_argument, 0, 0}, + [IDX_WF_ICMP_IN] = {"wf-icmp-in", required_argument, 0, 0}, + [IDX_WF_ICMP_OUT] = {"wf-icmp-out", required_argument, 0, 0}, + [IDX_WF_IPP_IN] = {"wf-ipp-in", required_argument, 0, 0}, + [IDX_WF_IPP_OUT] = {"wf-ipp-out", required_argument, 0, 0}, [IDX_WF_RAW] = {"wf-raw", required_argument, 0, 0}, [IDX_WF_RAW_PART] = {"wf-raw-part", required_argument, 0, 0}, [IDX_WF_FILTER_LAN] = {"wf-filter-lan", required_argument, 0, 0}, @@ -1738,6 +1921,29 @@ static const struct option long_options[] = { }; +#ifdef __CYGWIN__ +#define TITLE_ICON MAKEINTRESOURCE(1) +static void WinSetIcon(void) +{ + HWND hConsole = GetConsoleWindow(); + HICON hIcon,hIconOld; + if (hConsole) + { + if ((hIcon = LoadImage(GetModuleHandle(NULL),TITLE_ICON,IMAGE_ICON,32,32,LR_DEFAULTCOLOR|LR_SHARED))) + { + hIconOld = (HICON)SendMessage(hConsole, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); + if (hIconOld) DestroyIcon(hIconOld); + } + if ((hIcon = LoadImage(GetModuleHandle(NULL),TITLE_ICON,IMAGE_ICON,0,0,LR_DEFAULTCOLOR|LR_SHARED))) + { + hIconOld = (HICON)SendMessage(hConsole, WM_SETICON, ICON_BIG, (LPARAM)hIcon); + if (hIconOld) DestroyIcon(hIconOld); + } + } +} +#endif + + #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH) @@ -1754,6 +1960,7 @@ static const struct option long_options[] = { #endif #endif +enum {WF_TCP_IN, WF_UDP_IN, WF_TCP_OUT, WF_UDP_OUT, WF_ICMP_IN, WF_ICMP_OUT, WF_IPP_IN, WF_IPP_OUT, WF_RAW, WF_RAWF_PART, GLOBAL_SSID_FILTER, GLOBAL_NLM_FILTER, WF_RAWF, WF_COUNT} t_wf_index; int main(int argc, char **argv) { #ifdef __CYGWIN__ @@ -1762,6 +1969,9 @@ int main(int argc, char **argv) // we were running as service. now exit. return 0; } + WinSetIcon(); + MAKE_VER(params.verstr, sizeof(params.verstr)); + printf("%s\n\n",params.verstr); #endif int result, v; int option_index = 0; @@ -1774,24 +1984,23 @@ int main(int argc, char **argv) char wf_save_file[256]=""; bool wf_ipv4 = true, wf_ipv6 = true, wf_filter_lan = true, wf_filter_loopback = true, wf_tcp_empty = false; unsigned int IfIdx = 0, SubIfIdx = 0; - unsigned int hash_wf_tcp_in = 0, hash_wf_udp_in = 0, hash_wf_tcp_out = 0, hash_wf_udp_out = 0, hash_wf_raw = 0, hash_wf_raw_part = 0, hash_ssid_filter = 0, hash_nlm_filter = 0; + unsigned int hash_wf[WF_COUNT]; #endif if (argc < 2) exithelp(); srandom(time(NULL)); aes_init_keygen_tables(); // required for aes + mask_from_bitcount6_prepare(); set_env_exedir(argv[0]); set_console_io_buffering(); #ifdef __CYGWIN__ + memset(hash_wf,0,sizeof(hash_wf)); prepare_low_appdata(); #endif init_params(¶ms); - MAKE_VER(params.verstr, sizeof(params.verstr)); - printf("%s\n\n",params.verstr); - ApplyDefaultBlobs(¶ms.blobs); struct desync_profile_list *dpl; @@ -1818,23 +2027,11 @@ int main(int argc, char **argv) #ifdef __CYGWIN__ params.windivert_filter = malloc(WINDIVERT_MAX); - if (!params.windivert_filter) + if (!params.windivert_filter || !alloc_windivert_portfilters(¶ms)) { DLOG_ERR("out of memory\n"); exit_clean(1); } - char **wdbufs[] = - {¶ms.wf_pf_tcp_src_in, ¶ms.wf_pf_tcp_dst_in, ¶ms.wf_pf_udp_src_in, ¶ms.wf_pf_udp_dst_in, - ¶ms.wf_pf_tcp_src_out, ¶ms.wf_pf_tcp_dst_out, ¶ms.wf_pf_udp_src_out, ¶ms.wf_pf_udp_dst_out}; - for (v=0 ; v<(sizeof(wdbufs)/sizeof(*wdbufs)) ; v++) - { - if (!(*wdbufs[v] = malloc(WINDIVERT_PORTFILTER_MAX))) - { - DLOG_ERR("out of memory\n"); - exit_clean(1); - } - **wdbufs[v] = 0; - } #endif while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) @@ -1898,6 +2095,9 @@ int main(int argc, char **argv) case IDX_DRY_RUN: bDry = true; break; + case IDX_INTERCEPT: + params.intercept = !optarg || atoi(optarg); + break; case IDX_VERSION: exit_clean(0); break; @@ -2289,8 +2489,10 @@ int main(int argc, char **argv) DLOG_ERR("Invalid port filter : %s\n", optarg); exit_clean(1); } - // deny udp if not set - if (!port_filters_deny_if_empty(&dp->pf_udp)) + // deny others if not set + if (!port_filters_deny_if_empty(&dp->pf_udp) || + !icmp_filters_deny_if_empty(&dp->icf) || + !ipp_filters_deny_if_empty(&dp->ipf)) exit_clean(1); break; case IDX_FILTER_UDP: @@ -2299,8 +2501,34 @@ int main(int argc, char **argv) DLOG_ERR("Invalid port filter : %s\n", optarg); exit_clean(1); } - // deny tcp if not set - if (!port_filters_deny_if_empty(&dp->pf_tcp)) + // deny others if not set + if (!port_filters_deny_if_empty(&dp->pf_tcp) || + !icmp_filters_deny_if_empty(&dp->icf) || + !ipp_filters_deny_if_empty(&dp->ipf)) + exit_clean(1); + break; + case IDX_FILTER_ICMP: + if (!parse_icf_list(optarg, &dp->icf)) + { + DLOG_ERR("Invalid icmp filter : %s\n", optarg); + exit_clean(1); + } + // deny others if not set + if (!port_filters_deny_if_empty(&dp->pf_tcp) || + !port_filters_deny_if_empty(&dp->pf_udp) || + !ipp_filters_deny_if_empty(&dp->ipf)) + exit_clean(1); + break; + case IDX_FILTER_IPP: + if (!parse_ipp_list(optarg, &dp->ipf)) + { + DLOG_ERR("Invalid ip protocol filter : %s\n", optarg); + exit_clean(1); + } + // deny others if not set + if (!port_filters_deny_if_empty(&dp->pf_tcp) || + !port_filters_deny_if_empty(&dp->pf_udp) || + !icmp_filters_deny_if_empty(&dp->icf)) exit_clean(1); break; case IDX_FILTER_L7: @@ -2415,7 +2643,7 @@ int main(int argc, char **argv) } break; case IDX_WF_TCP_IN: - hash_wf_tcp_in = hash_jen(optarg, strlen(optarg)); + hash_wf[WF_TCP_IN] = hash_jen(optarg, strlen(optarg)); if (!wf_make_pf(optarg, "tcp", "SrcPort", params.wf_pf_tcp_src_in, WINDIVERT_PORTFILTER_MAX) || !wf_make_pf(optarg, "tcp", "DstPort", params.wf_pf_tcp_dst_in, WINDIVERT_PORTFILTER_MAX)) { @@ -2424,7 +2652,7 @@ int main(int argc, char **argv) } break; case IDX_WF_TCP_OUT: - hash_wf_tcp_out = hash_jen(optarg, strlen(optarg)); + hash_wf[WF_TCP_OUT] = hash_jen(optarg, strlen(optarg)); if (!wf_make_pf(optarg, "tcp", "SrcPort", params.wf_pf_tcp_src_out, WINDIVERT_PORTFILTER_MAX) || !wf_make_pf(optarg, "tcp", "DstPort", params.wf_pf_tcp_dst_out, WINDIVERT_PORTFILTER_MAX)) { @@ -2433,7 +2661,7 @@ int main(int argc, char **argv) } break; case IDX_WF_UDP_IN: - hash_wf_udp_in = hash_jen(optarg, strlen(optarg)); + hash_wf[WF_UDP_IN] = hash_jen(optarg, strlen(optarg)); if (!wf_make_pf(optarg, "udp", "SrcPort", params.wf_pf_udp_src_in, WINDIVERT_PORTFILTER_MAX) || !wf_make_pf(optarg, "udp", "DstPort", params.wf_pf_udp_dst_in, WINDIVERT_PORTFILTER_MAX)) { @@ -2442,7 +2670,7 @@ int main(int argc, char **argv) } break; case IDX_WF_UDP_OUT: - hash_wf_udp_out = hash_jen(optarg, strlen(optarg)); + hash_wf[WF_UDP_OUT] = hash_jen(optarg, strlen(optarg)); if (!wf_make_pf(optarg, "udp", "SrcPort", params.wf_pf_udp_src_out, WINDIVERT_PORTFILTER_MAX) || !wf_make_pf(optarg, "udp", "DstPort", params.wf_pf_udp_dst_out, WINDIVERT_PORTFILTER_MAX)) { @@ -2450,8 +2678,40 @@ int main(int argc, char **argv) exit_clean(1); } break; + case IDX_WF_ICMP_IN: + hash_wf[WF_ICMP_IN] = hash_jen(optarg, strlen(optarg)); + if (!wf_make_icf(optarg, params.wf_icf_in, WINDIVERT_PORTFILTER_MAX)) + { + DLOG_ERR("bad value for --wf-icmp-in\n"); + exit_clean(1); + } + break; + case IDX_WF_ICMP_OUT: + hash_wf[WF_ICMP_OUT] = hash_jen(optarg, strlen(optarg)); + if (!wf_make_icf(optarg, params.wf_icf_out, WINDIVERT_PORTFILTER_MAX)) + { + DLOG_ERR("bad value for --wf-icmp-out\n"); + exit_clean(1); + } + break; + case IDX_WF_IPP_IN: + hash_wf[WF_IPP_IN] = hash_jen(optarg, strlen(optarg)); + if (!wf_make_ipf(optarg, params.wf_ipf_in, WINDIVERT_PORTFILTER_MAX)) + { + DLOG_ERR("bad value for --wf-ipp-in\n"); + exit_clean(1); + } + break; + case IDX_WF_IPP_OUT: + hash_wf[WF_IPP_OUT] = hash_jen(optarg, strlen(optarg)); + if (!wf_make_ipf(optarg, params.wf_ipf_out, WINDIVERT_PORTFILTER_MAX)) + { + DLOG_ERR("bad value for --wf-ipp-out\n"); + exit_clean(1); + } + break; case IDX_WF_RAW: - hash_wf_raw = hash_jen(optarg, strlen(optarg)); + hash_wf[WF_RAWF] = hash_jen(optarg, strlen(optarg)); if (optarg[0] == '@') { size_t sz = WINDIVERT_MAX-1; @@ -2460,7 +2720,7 @@ int main(int argc, char **argv) } else { - strncpy(params.windivert_filter, optarg, WINDIVERT_MAX); + snprintf(params.windivert_filter, WINDIVERT_MAX, "%s", optarg); params.windivert_filter[WINDIVERT_MAX - 1] = '\0'; } break; @@ -2468,7 +2728,7 @@ int main(int argc, char **argv) wf_tcp_empty = !optarg || atoi(optarg); break; case IDX_WF_RAW_PART: - hash_wf_raw_part ^= hash_jen(optarg, strlen(optarg)); + hash_wf[WF_RAWF_PART] ^= hash_jen(optarg, strlen(optarg)); { char *wfpart = malloc(WINDIVERT_MAX); if (!wfpart) @@ -2484,7 +2744,7 @@ int main(int argc, char **argv) } else { - strncpy(wfpart, optarg, WINDIVERT_MAX); + snprintf(wfpart, WINDIVERT_MAX, "%s", optarg); wfpart[WINDIVERT_MAX - 1] = '\0'; } if (!strlist_add(¶ms.wf_raw_part, wfpart)) @@ -2510,7 +2770,7 @@ int main(int argc, char **argv) bDupCheck = !optarg || !!atoi(optarg); break; case IDX_SSID_FILTER: - hash_ssid_filter = hash_jen(optarg, strlen(optarg)); + hash_wf[GLOBAL_SSID_FILTER] = hash_jen(optarg, strlen(optarg)); if (!parse_strlist(optarg, ¶ms.ssid_filter)) { DLOG_ERR("strlist_add failed\n"); @@ -2518,7 +2778,7 @@ int main(int argc, char **argv) } break; case IDX_NLM_FILTER: - hash_nlm_filter = hash_jen(optarg, strlen(optarg)); + hash_wf[GLOBAL_NLM_FILTER] = hash_jen(optarg, strlen(optarg)); if (!parse_strlist(optarg, ¶ms.nlm_filter)) { DLOG_ERR("strlist_add failed\n"); @@ -2563,19 +2823,22 @@ int main(int argc, char **argv) #endif argv = NULL; argc = 0; + if (params.intercept) + { #ifdef __linux__ - if (params.qnum < 0) - { - DLOG_ERR("Need queue number (--qnum)\n"); - exit_clean(1); - } + if (params.qnum < 0) + { + DLOG_ERR("Need queue number (--qnum)\n"); + exit_clean(1); + } #elif defined(BSD) - if (!params.port) - { - DLOG_ERR("Need divert port (--port)\n"); - exit_clean(1); - } + if (!params.port) + { + DLOG_ERR("Need divert port (--port)\n"); + exit_clean(1); + } #endif + } DLOG("adding low-priority default empty desync profile\n"); // add default empty profile @@ -2659,37 +2922,50 @@ int main(int argc, char **argv) dp_list_destroy(¶ms.desync_templates); #ifdef __CYGWIN__ - if (!*params.windivert_filter) + if (params.intercept) { - if (!*params.wf_pf_tcp_src_in && !*params.wf_pf_udp_src_in && !*params.wf_pf_tcp_src_out && !*params.wf_pf_udp_src_out && LIST_EMPTY(¶ms.wf_raw_part)) + if (!*params.windivert_filter) { - DLOG_ERR("windivert filter : must specify port or/and partial raw filter\n"); - exit_clean(1); + if (!*params.wf_pf_tcp_src_in && !*params.wf_pf_udp_src_in && !*params.wf_pf_tcp_src_out && !*params.wf_pf_udp_src_out && !*params.wf_icf_in && !*params.wf_icf_out && !*params.wf_ipf_in && !*params.wf_ipf_out && LIST_EMPTY(¶ms.wf_raw_part)) + { + DLOG_ERR("windivert filter : must specify port or/and partial raw filter\n"); + exit_clean(1); + } + // exchange src/dst ports in server mode + bool b = params.server ? + wf_make_filter(params.windivert_filter, WINDIVERT_MAX, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, + wf_tcp_empty, + params.wf_pf_tcp_dst_out, params.wf_pf_tcp_src_out, + params.wf_pf_tcp_dst_in, params.wf_pf_tcp_src_in, + params.wf_pf_udp_dst_in, params.wf_pf_udp_src_out, + params.wf_icf_out, params.wf_icf_in, + params.wf_ipf_out, params.wf_ipf_in, + ¶ms.wf_raw_part, wf_filter_lan, wf_filter_loopback) : + wf_make_filter(params.windivert_filter, WINDIVERT_MAX, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, + wf_tcp_empty, + params.wf_pf_tcp_src_out, params.wf_pf_tcp_dst_out, + params.wf_pf_tcp_src_in, params.wf_pf_tcp_dst_in, + params.wf_pf_udp_src_in, params.wf_pf_udp_dst_out, + params.wf_icf_out, params.wf_icf_in, + params.wf_ipf_out, params.wf_ipf_in, + ¶ms.wf_raw_part, wf_filter_lan, wf_filter_loopback); + cleanup_windivert_portfilters(¶ms); + if (!b) + { + DLOG_ERR("windivert filter : could not make filter\n"); + exit_clean(1); + } + // free unneeded extra memory + char *p = realloc(params.windivert_filter, strlen(params.windivert_filter)+1); + if (p) params.windivert_filter=p; } - // exchange src/dst ports in server mode - bool b = params.server ? - wf_make_filter(params.windivert_filter, WINDIVERT_MAX, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, - wf_tcp_empty, - params.wf_pf_tcp_dst_out, params.wf_pf_tcp_src_out, - params.wf_pf_tcp_dst_in, params.wf_pf_tcp_src_in, - params.wf_pf_udp_dst_in, params.wf_pf_udp_src_out, - ¶ms.wf_raw_part, wf_filter_lan, wf_filter_loopback) : - wf_make_filter(params.windivert_filter, WINDIVERT_MAX, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6, - wf_tcp_empty, - params.wf_pf_tcp_src_out, params.wf_pf_tcp_dst_out, - params.wf_pf_tcp_src_in, params.wf_pf_tcp_dst_in, - params.wf_pf_udp_src_in, params.wf_pf_udp_dst_out, - ¶ms.wf_raw_part, wf_filter_lan, wf_filter_loopback); - cleanup_windivert_portfilters(¶ms); - if (!b) - { - DLOG_ERR("windivert filter : could not make filter\n"); - exit_clean(1); - } - // free unneeded extra memory - char *p = realloc(params.windivert_filter, strlen(params.windivert_filter)+1); - if (p) params.windivert_filter=p; } + else + { + // do not intercept anything. only required for rawsend + snprintf(params.windivert_filter,WINDIVERT_MAX,"false"); + } + DLOG("windivert filter size: %zu\nwindivert filter:\n%s\n", strlen(params.windivert_filter), params.windivert_filter); if (*wf_save_file) { @@ -2705,11 +2981,10 @@ int main(int argc, char **argv) } } HANDLE hMutexArg = NULL; - if (bDupCheck) + if (bDupCheck && params.intercept) { - char mutex_name[128]; - snprintf(mutex_name, sizeof(mutex_name), "Global\\winws2_arg_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u_%u", - hash_wf_tcp_in, hash_wf_udp_in, hash_wf_tcp_out, hash_wf_udp_out, hash_wf_raw, hash_wf_raw_part, hash_ssid_filter, hash_nlm_filter, IfIdx, SubIfIdx, wf_ipv4, wf_ipv6); + char mutex_name[32]; + snprintf(mutex_name, sizeof(mutex_name), "Global\\winws2_arg_%u", hash_jen(hash_wf, sizeof(hash_wf))); hMutexArg = CreateMutexA(NULL, TRUE, mutex_name); if (hMutexArg && GetLastError() == ERROR_ALREADY_EXISTS) @@ -2768,6 +3043,7 @@ ex: CloseHandle(hMutexArg); } #endif + close_std(); return result; exiterr: result = 1; diff --git a/nfq2/nfqws.h b/nfq2/nfqws.h index bcb0d65..29f435c 100644 --- a/nfq2/nfqws.h +++ b/nfq2/nfqws.h @@ -1,15 +1,15 @@ #pragma once -#include +#include #ifdef __linux__ #define HAS_FILTER_SSID 1 #endif #ifdef __CYGWIN__ -extern bool bQuit; +extern volatile sig_atomic_t bQuit; #endif int main(int argc, char *argv[]); // when something changes that can break LUA compatibility this version should be increased -#define LUA_COMPAT_VER 4 +#define LUA_COMPAT_VER 5 diff --git a/nfq2/params.c b/nfq2/params.c index 5f4f384..698efa0 100644 --- a/nfq2/params.c +++ b/nfq2/params.c @@ -337,6 +337,8 @@ void dp_init_dynamic(struct desync_profile *dp) LIST_INIT(&dp->ips_collection_exclude); LIST_INIT(&dp->pf_tcp); LIST_INIT(&dp->pf_udp); + LIST_INIT(&dp->icf); + LIST_INIT(&dp->ipf); LIST_INIT(&dp->lua_desync); #ifdef HAS_FILTER_SSID LIST_INIT(&dp->filter_ssid); @@ -368,6 +370,8 @@ static void dp_clear_dynamic(struct desync_profile *dp) ipset_collection_destroy(&dp->ips_collection_exclude); port_filters_destroy(&dp->pf_tcp); port_filters_destroy(&dp->pf_udp); + icmp_filters_destroy(&dp->icf); + ipp_filters_destroy(&dp->ipf); funclist_destroy(&dp->lua_desync); #ifdef HAS_FILTER_SSID strlist_destroy(&dp->filter_ssid); @@ -475,11 +479,30 @@ void cleanup_windivert_portfilters(struct params_s *params) { char **wdbufs[] = {¶ms->wf_pf_tcp_src_in, ¶ms->wf_pf_tcp_dst_in, ¶ms->wf_pf_udp_src_in, ¶ms->wf_pf_udp_dst_in, - ¶ms->wf_pf_tcp_src_out, ¶ms->wf_pf_tcp_dst_out, ¶ms->wf_pf_udp_src_out, ¶ms->wf_pf_udp_dst_out}; + ¶ms->wf_pf_tcp_src_out, ¶ms->wf_pf_tcp_dst_out, ¶ms->wf_pf_udp_src_out, ¶ms->wf_pf_udp_dst_out, + ¶ms->wf_icf_in, ¶ms->wf_icf_out, + ¶ms->wf_ipf_in, ¶ms->wf_ipf_out}; for (int i=0 ; i<(sizeof(wdbufs)/sizeof(*wdbufs)) ; i++) { - free(*wdbufs[i]); *wdbufs[i] = NULL; + free(*wdbufs[i]); + *wdbufs[i] = NULL; } + strlist_destroy(¶ms->wf_raw_part); +} +bool alloc_windivert_portfilters(struct params_s *params) +{ + char **wdbufs[] = + {¶ms->wf_pf_tcp_src_in, ¶ms->wf_pf_tcp_dst_in, ¶ms->wf_pf_udp_src_in, ¶ms->wf_pf_udp_dst_in, + ¶ms->wf_pf_tcp_src_out, ¶ms->wf_pf_tcp_dst_out, ¶ms->wf_pf_udp_src_out, ¶ms->wf_pf_udp_dst_out, + ¶ms->wf_icf_in, ¶ms->wf_icf_out, + ¶ms->wf_ipf_in, ¶ms->wf_ipf_out}; + for (int i=0 ; i<(sizeof(wdbufs)/sizeof(*wdbufs)) ; i++) + { + if (!(*wdbufs[i] = malloc(WINDIVERT_PORTFILTER_MAX))) + return false; + **wdbufs[i] = 0; + } + return true; } #endif void cleanup_params(struct params_s *params) @@ -514,6 +537,7 @@ void init_params(struct params_s *params) { memset(params, 0, sizeof(*params)); + params->intercept = true; #ifdef __linux__ params->qnum = -1; #elif defined(BSD) diff --git a/nfq2/params.h b/nfq2/params.h index 195cb12..579dd5b 100644 --- a/nfq2/params.h +++ b/nfq2/params.h @@ -63,6 +63,8 @@ struct desync_profile bool filter_ipv4,filter_ipv6; struct port_filters_head pf_tcp,pf_udp; + struct icmp_filters_head icf; + struct ipp_filters_head ipf; uint64_t filter_l7; // L7_PROTO_* bits #ifdef HAS_FILTER_SSID @@ -125,7 +127,7 @@ struct params_s char debug_logfile[PATH_MAX]; bool debug; - bool daemon; + bool daemon, intercept; #ifdef __linux__ int qnum; @@ -144,6 +146,7 @@ struct params_s char *windivert_filter; char *wf_pf_tcp_src_in, *wf_pf_tcp_dst_in, *wf_pf_udp_src_in, *wf_pf_udp_dst_in; char *wf_pf_tcp_src_out, *wf_pf_tcp_dst_out, *wf_pf_udp_src_out, *wf_pf_udp_dst_out; + char *wf_icf_in, *wf_icf_out, *wf_ipf_in, *wf_ipf_out; #else bool droproot; char *user; @@ -194,6 +197,7 @@ void init_params(struct params_s *params); void cleanup_args(struct params_s *params); #endif #ifdef __CYGWIN__ +bool alloc_windivert_portfilters(struct params_s *params); void cleanup_windivert_portfilters(struct params_s *params); #endif void cleanup_params(struct params_s *params); diff --git a/nfq2/pools.c b/nfq2/pools.c index d206cbf..4f9dac3 100644 --- a/nfq2/pools.c +++ b/nfq2/pools.c @@ -742,14 +742,14 @@ void port_filters_destroy(struct port_filters_head *head) free(entry); } } -bool port_filters_in_range(const struct port_filters_head *head, uint16_t port) +bool port_filters_match(const struct port_filters_head *head, uint16_t port) { const struct port_filter_item *item; if (LIST_EMPTY(head)) return true; LIST_FOREACH(item, head, next) { - if (pf_in_range(port, &item->pf)) + if (pf_match(port, &item->pf)) return true; } return false; @@ -762,6 +762,83 @@ bool port_filters_deny_if_empty(struct port_filters_head *head) } +bool icmp_filter_add(struct icmp_filters_head *head, const icmp_filter *icf) +{ + struct icmp_filter_item *entry = malloc(sizeof(struct icmp_filter_item)); + if (entry) + { + entry->icf = *icf; + LIST_INSERT_HEAD(head, entry, next); + } + return entry; +} +void icmp_filters_destroy(struct icmp_filters_head *head) +{ + struct icmp_filter_item *entry; + while ((entry = LIST_FIRST(head))) + { + LIST_REMOVE(entry, next); + free(entry); + } +} +bool icmp_filters_match(const struct icmp_filters_head *head, uint8_t type, uint8_t code) +{ + const struct icmp_filter_item *item; + + if (LIST_EMPTY(head)) return true; + LIST_FOREACH(item, head, next) + { + if (icf_match(type, code, &item->icf)) + return true; + } + return false; +} +bool icmp_filters_deny_if_empty(struct icmp_filters_head *head) +{ + icmp_filter icf; + if (!LIST_EMPTY(head)) return true; + return icf_parse("-",&icf) && icmp_filter_add(head,&icf); +} + + +bool ipp_filter_add(struct ipp_filters_head *head, const ipp_filter *ipp) +{ + struct ipp_filter_item *entry = malloc(sizeof(struct ipp_filter_item)); + if (entry) + { + entry->ipp = *ipp; + LIST_INSERT_HEAD(head, entry, next); + } + return entry; +} +void ipp_filters_destroy(struct ipp_filters_head *head) +{ + struct ipp_filter_item *entry; + while ((entry = LIST_FIRST(head))) + { + LIST_REMOVE(entry, next); + free(entry); + } +} +bool ipp_filters_match(const struct ipp_filters_head *head, uint8_t proto) +{ + const struct ipp_filter_item *item; + + if (LIST_EMPTY(head)) return true; + LIST_FOREACH(item, head, next) + { + if (ipp_match(proto, &item->ipp)) + return true; + } + return false; +} +bool ipp_filters_deny_if_empty(struct ipp_filters_head *head) +{ + ipp_filter ipp; + if (!LIST_EMPTY(head)) return true; + return ipp_parse("-",&ipp) && ipp_filter_add(head,&ipp); +} + struct blob_item *blob_collection_add(struct blob_collection_head *head) { diff --git a/nfq2/pools.h b/nfq2/pools.h index e3ecdd3..b91d36e 100644 --- a/nfq2/pools.h +++ b/nfq2/pools.h @@ -7,6 +7,7 @@ #include #include "helpers.h" +#include "filter.h" //#define HASH_BLOOM 20 #define HASH_NONFATAL_OOM 1 @@ -186,9 +187,28 @@ struct port_filter_item { LIST_HEAD(port_filters_head, port_filter_item); bool port_filter_add(struct port_filters_head *head, const port_filter *pf); void port_filters_destroy(struct port_filters_head *head); -bool port_filters_in_range(const struct port_filters_head *head, uint16_t port); +bool port_filters_match(const struct port_filters_head *head, uint16_t port); bool port_filters_deny_if_empty(struct port_filters_head *head); +struct icmp_filter_item { + icmp_filter icf; + LIST_ENTRY(icmp_filter_item) next; +}; +LIST_HEAD(icmp_filters_head, icmp_filter_item); +bool icmp_filter_add(struct icmp_filters_head *head, const icmp_filter *icf); +void icmp_filters_destroy(struct icmp_filters_head *head); +bool icmp_filters_match(const struct icmp_filters_head *head, uint8_t type, uint8_t code); +bool icmp_filters_deny_if_empty(struct icmp_filters_head *head); + +struct ipp_filter_item { + ipp_filter ipp; + LIST_ENTRY(ipp_filter_item) next; +}; +LIST_HEAD(ipp_filters_head, ipp_filter_item); +bool ipp_filter_add(struct ipp_filters_head *head, const ipp_filter *ipp); +void ipp_filters_destroy(struct ipp_filters_head *head); +bool ipp_filters_match(const struct ipp_filters_head *head, uint8_t proto); +bool ipp_filters_deny_if_empty(struct ipp_filters_head *head); struct blob_item { uint8_t *data; // main data blob diff --git a/nfq2/protocol.c b/nfq2/protocol.c index 40be021..6adc599 100644 --- a/nfq2/protocol.c +++ b/nfq2/protocol.c @@ -49,6 +49,7 @@ bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7) static const char *l7payload_name[] = { "all","unknown","empty","known", + "ipv4","ipv6", "http_req","http_reply", "tls_client_hello","tls_server_hello", "dtls_client_hello","dtls_server_hello", diff --git a/nfq2/protocol.h b/nfq2/protocol.h index cdcc655..fe10016 100644 --- a/nfq2/protocol.h +++ b/nfq2/protocol.h @@ -31,6 +31,8 @@ typedef enum { L7P_UNKNOWN, L7P_EMPTY, L7P_KNOWN, + L7P_IPV4, + L7P_IPV6, L7P_HTTP_REQ, L7P_HTTP_REPLY, L7P_TLS_CLIENT_HELLO, diff --git a/nfq2/windows/netinet/icmp6.h b/nfq2/windows/netinet/icmp6.h new file mode 100644 index 0000000..54ee8a7 --- /dev/null +++ b/nfq2/windows/netinet/icmp6.h @@ -0,0 +1,347 @@ +/* Copyright (C) 1991-2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _NETINET_ICMP6_H +#define _NETINET_ICMP6_H 1 + +#include +#include +#include +#include + +#define ICMP6_FILTER 1 + +#define ICMP6_FILTER_BLOCK 1 +#define ICMP6_FILTER_PASS 2 +#define ICMP6_FILTER_BLOCKOTHERS 3 +#define ICMP6_FILTER_PASSONLY 4 + +struct icmp6_filter + { + uint32_t icmp6_filt[8]; + }; + +struct icmp6_hdr + { + uint8_t icmp6_type; /* type field */ + uint8_t icmp6_code; /* code field */ + uint16_t icmp6_cksum; /* checksum field */ + union + { + uint32_t icmp6_un_data32[1]; /* type-specific field */ + uint16_t icmp6_un_data16[2]; /* type-specific field */ + uint8_t icmp6_un_data8[4]; /* type-specific field */ + } icmp6_dataun; + }; + +#define icmp6_data32 icmp6_dataun.icmp6_un_data32 +#define icmp6_data16 icmp6_dataun.icmp6_un_data16 +#define icmp6_data8 icmp6_dataun.icmp6_un_data8 +#define icmp6_pptr icmp6_data32[0] /* parameter prob */ +#define icmp6_mtu icmp6_data32[0] /* packet too big */ +#define icmp6_id icmp6_data16[0] /* echo request/reply */ +#define icmp6_seq icmp6_data16[1] /* echo request/reply */ +#define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */ + +#define ICMP6_DST_UNREACH 1 +#define ICMP6_PACKET_TOO_BIG 2 +#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_PARAM_PROB 4 + +#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */ + +#define ICMP6_ECHO_REQUEST 128 +#define ICMP6_ECHO_REPLY 129 +#define MLD_LISTENER_QUERY 130 +#define MLD_LISTENER_REPORT 131 +#define MLD_LISTENER_REDUCTION 132 +#define ICMPV6_EXT_ECHO_REQUEST 160 +#define ICMPV6_EXT_ECHO_REPLY 161 + +#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ +#define ICMP6_DST_UNREACH_ADMIN 1 /* communication with destination */ + /* administratively prohibited */ +#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */ +#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */ +#define ICMP6_DST_UNREACH_NOPORT 4 /* bad port */ + +#define ICMP6_TIME_EXCEED_TRANSIT 0 /* Hop Limit == 0 in transit */ +#define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* Reassembly time out */ + +#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */ +#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */ +#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized IPv6 option */ + +#define ICMP6_FILTER_WILLPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) == 0) + +#define ICMP6_FILTER_WILLBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) & (1U << ((type) & 31))) != 0) + +#define ICMP6_FILTER_SETPASS(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETBLOCK(type, filterp) \ + ((((filterp)->icmp6_filt[(type) >> 5]) |= (1U << ((type) & 31)))) + +#define ICMP6_FILTER_SETPASSALL(filterp) \ + memset (filterp, 0, sizeof (struct icmp6_filter)); + +#define ICMP6_FILTER_SETBLOCKALL(filterp) \ + memset (filterp, 0xFF, sizeof (struct icmp6_filter)); + +#define ND_ROUTER_SOLICIT 133 +#define ND_ROUTER_ADVERT 134 +#define ND_NEIGHBOR_SOLICIT 135 +#define ND_NEIGHBOR_ADVERT 136 +#define ND_REDIRECT 137 + +struct nd_router_solicit /* router solicitation */ + { + struct icmp6_hdr nd_rs_hdr; + /* could be followed by options */ + }; + +#define nd_rs_type nd_rs_hdr.icmp6_type +#define nd_rs_code nd_rs_hdr.icmp6_code +#define nd_rs_cksum nd_rs_hdr.icmp6_cksum +#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0] + +struct nd_router_advert /* router advertisement */ + { + struct icmp6_hdr nd_ra_hdr; + uint32_t nd_ra_reachable; /* reachable time */ + uint32_t nd_ra_retransmit; /* retransmit timer */ + /* could be followed by options */ + }; + +#define nd_ra_type nd_ra_hdr.icmp6_type +#define nd_ra_code nd_ra_hdr.icmp6_code +#define nd_ra_cksum nd_ra_hdr.icmp6_cksum +#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0] +#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] +#define ND_RA_FLAG_MANAGED 0x80 +#define ND_RA_FLAG_OTHER 0x40 +#define ND_RA_FLAG_HOME_AGENT 0x20 +#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] + +struct nd_neighbor_solicit /* neighbor solicitation */ + { + struct icmp6_hdr nd_ns_hdr; + struct in6_addr nd_ns_target; /* target address */ + /* could be followed by options */ + }; + +#define nd_ns_type nd_ns_hdr.icmp6_type +#define nd_ns_code nd_ns_hdr.icmp6_code +#define nd_ns_cksum nd_ns_hdr.icmp6_cksum +#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0] + +struct nd_neighbor_advert /* neighbor advertisement */ + { + struct icmp6_hdr nd_na_hdr; + struct in6_addr nd_na_target; /* target address */ + /* could be followed by options */ + }; + +#define nd_na_type nd_na_hdr.icmp6_type +#define nd_na_code nd_na_hdr.icmp6_code +#define nd_na_cksum nd_na_hdr.icmp6_cksum +#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0] +#if __BYTE_ORDER == __BIG_ENDIAN +#define ND_NA_FLAG_ROUTER 0x80000000 +#define ND_NA_FLAG_SOLICITED 0x40000000 +#define ND_NA_FLAG_OVERRIDE 0x20000000 +#else /* __BYTE_ORDER == __LITTLE_ENDIAN */ +#define ND_NA_FLAG_ROUTER 0x00000080 +#define ND_NA_FLAG_SOLICITED 0x00000040 +#define ND_NA_FLAG_OVERRIDE 0x00000020 +#endif + +struct nd_redirect /* redirect */ + { + struct icmp6_hdr nd_rd_hdr; + struct in6_addr nd_rd_target; /* target address */ + struct in6_addr nd_rd_dst; /* destination address */ + /* could be followed by options */ + }; + +#define nd_rd_type nd_rd_hdr.icmp6_type +#define nd_rd_code nd_rd_hdr.icmp6_code +#define nd_rd_cksum nd_rd_hdr.icmp6_cksum +#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0] + +struct nd_opt_hdr /* Neighbor discovery option header */ + { + uint8_t nd_opt_type; + uint8_t nd_opt_len; /* in units of 8 octets */ + /* followed by option specific data */ + }; + +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define ND_OPT_PREFIX_INFORMATION 3 +#define ND_OPT_REDIRECTED_HEADER 4 +#define ND_OPT_MTU 5 +#define ND_OPT_RTR_ADV_INTERVAL 7 +#define ND_OPT_HOME_AGENT_INFO 8 + +struct nd_opt_prefix_info /* prefix information */ + { + uint8_t nd_opt_pi_type; + uint8_t nd_opt_pi_len; + uint8_t nd_opt_pi_prefix_len; + uint8_t nd_opt_pi_flags_reserved; + uint32_t nd_opt_pi_valid_time; + uint32_t nd_opt_pi_preferred_time; + uint32_t nd_opt_pi_reserved2; + struct in6_addr nd_opt_pi_prefix; + }; + +#define ND_OPT_PI_FLAG_ONLINK 0x80 +#define ND_OPT_PI_FLAG_AUTO 0x40 +#define ND_OPT_PI_FLAG_RADDR 0x20 + +struct nd_opt_rd_hdr /* redirected header */ + { + uint8_t nd_opt_rh_type; + uint8_t nd_opt_rh_len; + uint16_t nd_opt_rh_reserved1; + uint32_t nd_opt_rh_reserved2; + /* followed by IP header and data */ + }; + +struct nd_opt_mtu /* MTU option */ + { + uint8_t nd_opt_mtu_type; + uint8_t nd_opt_mtu_len; + uint16_t nd_opt_mtu_reserved; + uint32_t nd_opt_mtu_mtu; + }; + +struct mld_hdr + { + struct icmp6_hdr mld_icmp6_hdr; + struct in6_addr mld_addr; /* multicast address */ + }; + +#define mld_type mld_icmp6_hdr.icmp6_type +#define mld_code mld_icmp6_hdr.icmp6_code +#define mld_cksum mld_icmp6_hdr.icmp6_cksum +#define mld_maxdelay mld_icmp6_hdr.icmp6_data16[0] +#define mld_reserved mld_icmp6_hdr.icmp6_data16[1] + +#define ICMP6_ROUTER_RENUMBERING 138 + +struct icmp6_router_renum /* router renumbering header */ + { + struct icmp6_hdr rr_hdr; + uint8_t rr_segnum; + uint8_t rr_flags; + uint16_t rr_maxdelay; + uint32_t rr_reserved; + }; + +#define rr_type rr_hdr.icmp6_type +#define rr_code rr_hdr.icmp6_code +#define rr_cksum rr_hdr.icmp6_cksum +#define rr_seqnum rr_hdr.icmp6_data32[0] + +/* Router renumbering flags */ +#define ICMP6_RR_FLAGS_TEST 0x80 +#define ICMP6_RR_FLAGS_REQRESULT 0x40 +#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20 +#define ICMP6_RR_FLAGS_SPECSITE 0x10 +#define ICMP6_RR_FLAGS_PREVDONE 0x08 + +struct rr_pco_match /* match prefix part */ + { + uint8_t rpm_code; + uint8_t rpm_len; + uint8_t rpm_ordinal; + uint8_t rpm_matchlen; + uint8_t rpm_minlen; + uint8_t rpm_maxlen; + uint16_t rpm_reserved; + struct in6_addr rpm_prefix; + }; + +/* PCO code values */ +#define RPM_PCO_ADD 1 +#define RPM_PCO_CHANGE 2 +#define RPM_PCO_SETGLOBAL 3 + +struct rr_pco_use /* use prefix part */ + { + uint8_t rpu_uselen; + uint8_t rpu_keeplen; + uint8_t rpu_ramask; + uint8_t rpu_raflags; + uint32_t rpu_vltime; + uint32_t rpu_pltime; + uint32_t rpu_flags; + struct in6_addr rpu_prefix; + }; + +#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x20 +#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x10 + +#if __BYTE_ORDER == __BIG_ENDIAN +# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000 +# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80 +# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40 +#endif + +struct rr_result /* router renumbering result message */ + { + uint16_t rrr_flags; + uint8_t rrr_ordinal; + uint8_t rrr_matchedlen; + uint32_t rrr_ifid; + struct in6_addr rrr_prefix; + }; + +#if __BYTE_ORDER == __BIG_ENDIAN +# define ICMP6_RR_RESULT_FLAGS_OOB 0x0002 +# define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define ICMP6_RR_RESULT_FLAGS_OOB 0x0200 +# define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 +#endif + +/* Mobile IPv6 extension: Advertisement Interval. */ +struct nd_opt_adv_interval + { + uint8_t nd_opt_adv_interval_type; + uint8_t nd_opt_adv_interval_len; + uint16_t nd_opt_adv_interval_reserved; + uint32_t nd_opt_adv_interval_ival; + }; + +/* Mobile IPv6 extension: Home Agent Info. */ +struct nd_opt_home_agent_info + { + uint8_t nd_opt_home_agent_info_type; + uint8_t nd_opt_home_agent_info_len; + uint16_t nd_opt_home_agent_info_reserved; + uint16_t nd_opt_home_agent_info_preference; + uint16_t nd_opt_home_agent_info_lifetime; + }; + +#endif /* netinet/icmpv6.h */ diff --git a/nfq2/windows/netinet/ip_icmp.h b/nfq2/windows/netinet/ip_icmp.h new file mode 100644 index 0000000..d509714 --- /dev/null +++ b/nfq2/windows/netinet/ip_icmp.h @@ -0,0 +1,298 @@ +/* Copyright (C) 1991-2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef __NETINET_IP_ICMP_H +#define __NETINET_IP_ICMP_H 1 + +#include +#include + +__BEGIN_DECLS + +struct icmphdr +{ + uint8_t type; /* message type */ + uint8_t code; /* type sub-code */ + uint16_t checksum; + union + { + struct + { + uint16_t id; + uint16_t sequence; + } echo; /* echo datagram */ + uint32_t gateway; /* gateway address */ + struct + { + uint16_t __glibc_reserved; + uint16_t mtu; + } frag; /* path mtu discovery */ + } un; +}; + +#define ICMP_ECHOREPLY 0 /* Echo Reply */ +#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ +#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ +#define ICMP_REDIRECT 5 /* Redirect (change route) */ +#define ICMP_ECHO 8 /* Echo Request */ +#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ +#define ICMP_TIMESTAMP 13 /* Timestamp Request */ +#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ +#define ICMP_INFO_REQUEST 15 /* Information Request */ +#define ICMP_INFO_REPLY 16 /* Information Reply */ +#define ICMP_ADDRESS 17 /* Address Mask Request */ +#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ +#define NR_ICMP_TYPES 18 + + +/* Codes for UNREACH. */ +#define ICMP_NET_UNREACH 0 /* Network Unreachable */ +#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ +#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ +#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ +#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ +#define ICMP_SR_FAILED 5 /* Source Route failed */ +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 +#define ICMP_PKT_FILTERED 13 /* Packet filtered */ +#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ +#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ +#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ + +/* Codes for REDIRECT. */ +#define ICMP_REDIR_NET 0 /* Redirect Net */ +#define ICMP_REDIR_HOST 1 /* Redirect Host */ +#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ +#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ + +/* Codes for TIME_EXCEEDED. */ +#define ICMP_EXC_TTL 0 /* TTL count exceeded */ +#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ + +/* Codes for ICMP_EXT_ECHO (PROBE) */ +#define ICMP_EXT_ECHO 42 +#define ICMP_EXT_ECHOREPLY 43 +#define ICMP_EXT_CODE_MAL_QUERY 1 /* Malformed Query */ +#define ICMP_EXT_CODE_NO_IF 2 /* No such Interface */ +#define ICMP_EXT_CODE_NO_TABLE_ENT 3 /* No table entry */ +#define ICMP_EXT_CODE_MULT_IFS 4 /* Multiple Interfaces Satisfy Query */ + +/* Constants for EXT_ECHO (PROBE) */ +#define ICMP_EXT_ECHOREPLY_ACTIVE (1 << 2)/* active bit in reply */ +#define ICMP_EXT_ECHOREPLY_IPV4 (1 << 1)/* ipv4 bit in reply */ +#define ICMP_EXT_ECHOREPLY_IPV6 1 /* ipv6 bit in reply */ +#define ICMP_EXT_ECHO_CTYPE_NAME 1 +#define ICMP_EXT_ECHO_CTYPE_INDEX 2 +#define ICMP_EXT_ECHO_CTYPE_ADDR 3 +#define ICMP_AFI_IP 1 /* Address Family Identifier for IPV4 */ +#define ICMP_AFI_IP6 2 /* Address Family Identifier for IPV6 */ + + +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + */ + +#include +#include + +/* + * Internal of an ICMP Router Advertisement + */ +struct icmp_ra_addr +{ + uint32_t ira_addr; + uint32_t ira_preference; +}; + +struct icmp +{ + uint8_t icmp_type; /* type of message, see below */ + uint8_t icmp_code; /* type sub code */ + uint16_t icmp_cksum; /* ones complement checksum of struct */ + union + { + unsigned char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* gateway address */ + struct ih_idseq /* echo datagram */ + { + uint16_t icd_id; + uint16_t icd_seq; + } ih_idseq; + uint32_t ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu + { + uint16_t ipm_void; + uint16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv + { + uint8_t irt_num_addrs; + uint8_t irt_wpa; + uint16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union + { + struct + { + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; + } id_ts; + struct + { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; + uint32_t id_mask; + uint8_t id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; + +/* + * Lower bounds on packet lengths for various types. + * For the error advice packets must first insure that the + * packet is large enough to contain the returned ip header. + * Only then can we do the check to see if 64 bits of packet + * data have been returned, since we need to check the returned + * ip header length. + */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#ifndef _IP_VHL +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + /* N.B.: must separately check that ip_hl >= 5 */ +#else +#define ICMP_ADVLEN(p) (8 + (IP_VHL_HL((p)->icmp_ip.ip_vhl) << 2) + 8) + /* N.B.: must separately check that header length >= 5 */ +#endif + +/* Definition of type and code fields. */ +/* defined above: ICMP_ECHOREPLY, ICMP_REDIRECT, ICMP_ECHO */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +/* UNREACH codes */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* net denied */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* host denied */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */ +#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */ +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */ + +/* REDIRECT codes */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ + +/* TIMEXCEED codes */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ + +/* PARAMPROB code */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO \ + || (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT \ + || (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY \ + || (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY \ + || (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + + +__END_DECLS + +#endif /* netinet/ip_icmp.h */ diff --git a/nfq2/windows/nthacks.h b/nfq2/windows/nthacks.h new file mode 100644 index 0000000..cd482f6 --- /dev/null +++ b/nfq2/windows/nthacks.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#define DIRECTORY_QUERY (0x0001) +#define DIRECTORY_TRAVERSE (0x0002) +#define DIRECTORY_CREATE_OBJECT (0x0004) +#define DIRECTORY_CREATE_SUBDIRECTORY (0x0008) +#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) + +typedef struct _PROCESS_SESSION_INFORMATION { + ULONG SessionId; +} PROCESS_SESSION_INFORMATION, *PPROCESS_SESSION_INFORMATION; + +typedef struct _OBJECT_DIRECTORY_INFORMATION { + UNICODE_STRING Name; + UNICODE_STRING TypeName; +} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION; + +#ifdef __cplusplus +extern "C" +{ +#endif + NTSTATUS NTAPI NtOpenDirectoryObject( + _Out_ PHANDLE DirectoryHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + NTSTATUS NTAPI NtQueryDirectoryObject( + _In_ HANDLE DirectoryHandle, + _Out_opt_ PVOID Buffer, + _In_ ULONG Length, + _In_ BOOLEAN ReturnSingleEntry, + _In_ BOOLEAN RestartScan, + _Inout_ PULONG Context, + _Out_opt_ PULONG ReturnLength + ); +#ifdef __cplusplus +}; +#endif diff --git a/nfq2/windows/res/howto.txt b/nfq2/windows/res/howto.txt new file mode 100644 index 0000000..b467934 --- /dev/null +++ b/nfq2/windows/res/howto.txt @@ -0,0 +1,4 @@ +# in 64 bit cygwin +windres winws.rc -O coff -o winws_res64.o +# in 32 bit cygwin +windres winws.rc -O coff -o winws_res32.o diff --git a/nfq2/windows/res/winws.ico b/nfq2/windows/res/winws.ico new file mode 100644 index 0000000..62152be Binary files /dev/null and b/nfq2/windows/res/winws.ico differ diff --git a/nfq2/windows/res/winws.manifest b/nfq2/windows/res/winws.manifest new file mode 100644 index 0000000..f702d38 --- /dev/null +++ b/nfq2/windows/res/winws.manifest @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nfq2/windows/res/winws.rc b/nfq2/windows/res/winws.rc new file mode 100644 index 0000000..ac104f4 --- /dev/null +++ b/nfq2/windows/res/winws.rc @@ -0,0 +1,3 @@ +LANGUAGE 0,0 +1 ICON "winws.ico" +1 24 "winws.manifest" diff --git a/nfq2/windows/res/winws_res32.o b/nfq2/windows/res/winws_res32.o new file mode 100644 index 0000000..1070328 Binary files /dev/null and b/nfq2/windows/res/winws_res32.o differ diff --git a/nfq2/windows/res/winws_res64.o b/nfq2/windows/res/winws_res64.o new file mode 100644 index 0000000..d48e1bb Binary files /dev/null and b/nfq2/windows/res/winws_res64.o differ