/********************************** Функция: sniffer_thread Параметры: VOID *lpParameter - параметр передаваемый в функцию, при запуске нити. Описание: Точка входа рабочего потока. Выбирает из TCP-стека пакет и ищет в данных один из операторов SQL (SELECT, INSERT, UPDATE, DELETE). В случае нахождения - отсылает все печатываемые символы от найденного оператора вправо - в поток-логгер. ***********************************/ DWORD WINAPI sniffer_thread( VOID *lpParameter ) { SnifferThreadParams *params = (SnifferThreadParams *)lpParameter; UINT8 packet[PACKET_SIZE]; WINDIVERT_ADDRESS addr; UINT packet_len; const char *sql_commands [] = { "insert", "select", "update", "delete", "alter", "create", "drop", "grant", nullptr }; while( WinDivertRecv( params->handle(), &packet, sizeof(packet), &addr, &packet_len ) ) { WINDIVERT_IPHDR *ip_header; WINDIVERT_TCPHDR *tcp_header; void *payload = nullptr; UINT payload_len = 0; WinDivertHelperParsePacket(&packet, packet_len, &ip_header, NULL, NULL, NULL, &tcp_header, NULL, &payload, &payload_len); if( payload != nullptr ){ const char *sql_beg = find_in_memory( (const char *)payload, payload_len, sql_commands ); int count = 0; if( sql_beg != nullptr ){ while( sql_beg+count < ((const char *)payload)+payload_len && ( isprint(sql_beg[count]) || sql_beg[count]=='\n') ){ ++count; } std::string sql_request(sql_beg, count); for( std::size_t pos = sql_request.find("\n"); pos != std::string::npos; pos = sql_request.find("\n", pos) ){ sql_request.replace( pos, 1, " " ); } log( ip_header->SrcAddr, tcp_header->SrcPort, sql_request ); } } } return 0; }
void dumpPacket(char *buf, int len, PWINDIVERT_ADDRESS paddr) { char *protocol; UINT16 srcPort = 0, dstPort = 0; WinDivertHelperParsePacket(buf, len, &ip_header, &ipv6_header, &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, &payload_len); // need to cast byte order on port numbers if (tcp_header != NULL) { protocol = "TCP "; srcPort = ntohs(tcp_header->SrcPort); dstPort = ntohs(tcp_header->DstPort); } else if (udp_header != NULL) { protocol = "UDP "; srcPort = ntohs(udp_header->SrcPort); dstPort = ntohs(udp_header->DstPort); } else if (icmp_header || icmpv6_header) { protocol = "ICMP"; } else { protocol = "???"; } if (ip_header != NULL) { UINT8 *src_addr = (UINT8*)&ip_header->SrcAddr; UINT8 *dst_addr = (UINT8*)&ip_header->DstAddr; LOG("%s.%s: %u.%u.%u.%u:%d->%u.%u.%u.%u:%d", protocol, paddr->Direction == WINDIVERT_DIRECTION_OUTBOUND ? "OUT " : "IN ", src_addr[0], src_addr[1], src_addr[2], src_addr[3], srcPort, dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3], dstPort); } else if (ipv6_header != NULL) { UINT16 *src_addr6 = (UINT16*)&ipv6_header->SrcAddr; UINT16 *dst_addr6 = (UINT16*)&ipv6_header->DstAddr; LOG("%s.%s: %x:%x:%x:%x:%x:%x:%x:%x:%d->%x:%x:%x:%x:%x:%x:%x:%x:%d", protocol, paddr->Direction == WINDIVERT_DIRECTION_OUTBOUND ? "OUT " : "IN ", src_addr6[0], src_addr6[1], src_addr6[2], src_addr6[3], src_addr6[4], src_addr6[5], src_addr6[6], src_addr6[7], srcPort, dst_addr6[0], dst_addr6[1], dst_addr6[2], dst_addr6[3], dst_addr6[4], dst_addr6[5], dst_addr6[6], dst_addr6[7], dstPort); } }
static short resetProcess(PacketNode *head, PacketNode *tail) { short reset = FALSE; PacketNode *pac = head->next; while (pac != tail) { if (checkDirection(pac->addr.Direction, resetInbound, resetOutbound) && pac->packetLen > TCP_MIN_SIZE && (setNextCount || calcChance(chance))) { PWINDIVERT_TCPHDR pTcpHdr; WinDivertHelperParsePacket( pac->packet, pac->packetLen, NULL, NULL, NULL, NULL, &pTcpHdr, NULL, NULL, NULL); if (pTcpHdr != NULL) { LOG("injecting reset w/ chance %.1f%%", chance/100.0); pTcpHdr->Rst = 1; WinDivertHelperCalcChecksums(pac->packet, pac->packetLen, 0); reset = TRUE; if (setNextCount > 0) { InterlockedDecrement16(&setNextCount); } } } pac = pac->next; } return reset; }
static short tamperProcess(PacketNode *head, PacketNode *tail) { short tampered = FALSE; PacketNode *pac = head->next; while (pac != tail) { if (checkDirection(pac->addr.Direction, tamperInbound, tamperOutbound) && calcChance(chance)) { char *data = NULL; UINT dataLen = 0; if (WinDivertHelperParsePacket(pac->packet, pac->packetLen, NULL, NULL, NULL, NULL, NULL, NULL, (PVOID*)&data, &dataLen) && data != NULL && dataLen != 0) { // try to tamper the central part of the packet, // since common packets put their checksum at head or tail if (dataLen <= 4) { // for short packet just tamper it all tamper_buf(data, dataLen); LOG("tampered w/ chance %.1f, dochecksum: %d, short packet changed all", chance/10.0, doChecksum); } else { // for longer ones process 1/4 of the lens start somewhere in the middle UINT len = dataLen; UINT len_d4 = len / 4; tamper_buf(data + len/2 - len_d4/2 + 1, len_d4); LOG("tampered w/ chance %.1f, dochecksum: %d, changing %d bytes out of %u", chance/10.0, doChecksum, len_d4, len); } // FIXME checksum seems to have some problem if (doChecksum) { WinDivertHelperCalcChecksums(pac->packet, pac->packetLen, 0); } tampered = TRUE; } } pac = pac->next; } return tampered; }
/* * Entry. */ int __cdecl main(int argc, char **argv) { HANDLE handle, console; UINT i; INT16 priority = 0; unsigned char packet[MAXBUF]; UINT packet_len; WINDIVERT_ADDRESS addr; PWINDIVERT_IPHDR ip_header; PWINDIVERT_IPV6HDR ipv6_header; PWINDIVERT_ICMPHDR icmp_header; PWINDIVERT_ICMPV6HDR icmpv6_header; PWINDIVERT_TCPHDR tcp_header; PWINDIVERT_UDPHDR udp_header; // Check arguments. switch (argc) { case 2: break; case 3: priority = (INT16)atoi(argv[2]); break; default: fprintf(stderr, "usage: %s windivert-filter [priority]\n", argv[0]); fprintf(stderr, "examples:\n"); fprintf(stderr, "\t%s true\n", argv[0]); fprintf(stderr, "\t%s \"outbound and tcp.DstPort == 80\" 1000\n", argv[0]); fprintf(stderr, "\t%s \"inbound and tcp.Syn\" -4000\n", argv[0]); exit(EXIT_FAILURE); } // Get console for pretty colors. console = GetStdHandle(STD_OUTPUT_HANDLE); // Divert traffic matching the filter: handle = WinDivertOpen(argv[1], WINDIVERT_LAYER_NETWORK, priority, WINDIVERT_FLAG_SNIFF); if (handle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_INVALID_PARAMETER) { fprintf(stderr, "error: filter syntax error\n"); exit(EXIT_FAILURE); } fprintf(stderr, "error: failed to open the WinDivert device (%d)\n", GetLastError()); exit(EXIT_FAILURE); } // Max-out the packet queue: if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_LEN, 8192)) { fprintf(stderr, "error: failed to set packet queue length (%d)\n", GetLastError()); exit(EXIT_FAILURE); } if (!WinDivertSetParam(handle, WINDIVERT_PARAM_QUEUE_TIME, 2048)) { fprintf(stderr, "error: failed to set packet queue time (%d)\n", GetLastError()); exit(EXIT_FAILURE); } // Main loop: while (TRUE) { // Read a matching packet. if (!WinDivertRecv(handle, packet, sizeof(packet), &addr, &packet_len)) { fprintf(stderr, "warning: failed to read packet (%d)\n", GetLastError()); continue; } // Print info about the matching packet. WinDivertHelperParsePacket(packet, packet_len, &ip_header, &ipv6_header, &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, NULL); if (ip_header == NULL && ipv6_header == NULL) { fprintf(stderr, "warning: junk packet\n"); } // Dump packet info: putchar('\n'); SetConsoleTextAttribute(console, FOREGROUND_RED); printf("Packet [Direction=%u IfIdx=%u SubIfIdx=%u]\n", addr.Direction, addr.IfIdx, addr.SubIfIdx); if (ip_header != NULL) { UINT8 *src_addr = (UINT8 *)&ip_header->SrcAddr; UINT8 *dst_addr = (UINT8 *)&ip_header->DstAddr; SetConsoleTextAttribute(console, FOREGROUND_GREEN | FOREGROUND_RED); printf("IPv4 [Version=%u HdrLength=%u TOS=%u Length=%u Id=0x%.4X " "Reserved=%u DF=%u MF=%u FragOff=%u TTL=%u Protocol=%u " "Checksum=0x%.4X SrcAddr=%u.%u.%u.%u DstAddr=%u.%u.%u.%u]\n", ip_header->Version, ip_header->HdrLength, ntohs(ip_header->TOS), ntohs(ip_header->Length), ntohs(ip_header->Id), WINDIVERT_IPHDR_GET_RESERVED(ip_header), WINDIVERT_IPHDR_GET_DF(ip_header), WINDIVERT_IPHDR_GET_MF(ip_header), ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)), ip_header->TTL, ip_header->Protocol, ntohs(ip_header->Checksum), src_addr[0], src_addr[1], src_addr[2], src_addr[3], dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]); } if (ipv6_header != NULL) { UINT16 *src_addr = (UINT16 *)&ipv6_header->SrcAddr; UINT16 *dst_addr = (UINT16 *)&ipv6_header->DstAddr; SetConsoleTextAttribute(console, FOREGROUND_GREEN | FOREGROUND_RED); printf("IPv6 [Version=%u TrafficClass=%u FlowLabel=%u Length=%u " "NextHdr=%u HopLimit=%u SrcAddr=", ipv6_header->Version, WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(ipv6_header), ntohl(WINDIVERT_IPV6HDR_GET_FLOWLABEL(ipv6_header)), ntohs(ipv6_header->Length), ipv6_header->NextHdr, ipv6_header->HopLimit); for (i = 0; i < 8; i++) { printf("%x%c", ntohs(src_addr[i]), (i == 7? ' ': ':')); } fputs("DstAddr=", stdout); for (i = 0; i < 8; i++) { printf("%x", ntohs(dst_addr[i])); if (i != 7) { putchar(':'); } } fputs("]\n", stdout); } if (icmp_header != NULL) { SetConsoleTextAttribute(console, FOREGROUND_RED); printf("ICMP [Type=%u Code=%u Checksum=0x%.4X Body=0x%.8X]\n", icmp_header->Type, icmp_header->Code, ntohs(icmp_header->Checksum), ntohl(icmp_header->Body)); } if (icmpv6_header != NULL) { SetConsoleTextAttribute(console, FOREGROUND_RED); printf("ICMPV6 [Type=%u Code=%u Checksum=0x%.4X Body=0x%.8X]\n", icmpv6_header->Type, icmpv6_header->Code, ntohs(icmpv6_header->Checksum), ntohl(icmpv6_header->Body)); } if (tcp_header != NULL) { SetConsoleTextAttribute(console, FOREGROUND_GREEN); printf("TCP [SrcPort=%u DstPort=%u SeqNum=%u AckNum=%u " "HdrLength=%u Reserved1=%u Reserved2=%u Urg=%u Ack=%u " "Psh=%u Rst=%u Syn=%u Fin=%u Window=%u Checksum=0x%.4X " "UrgPtr=%u]\n", ntohs(tcp_header->SrcPort), ntohs(tcp_header->DstPort), ntohl(tcp_header->SeqNum), ntohl(tcp_header->AckNum), tcp_header->HdrLength, tcp_header->Reserved1, tcp_header->Reserved2, tcp_header->Urg, tcp_header->Ack, tcp_header->Psh, tcp_header->Rst, tcp_header->Syn, tcp_header->Fin, ntohs(tcp_header->Window), ntohs(tcp_header->Checksum), ntohs(tcp_header->UrgPtr)); } if (udp_header != NULL) { SetConsoleTextAttribute(console, FOREGROUND_GREEN); printf("UDP [SrcPort=%u DstPort=%u Length=%u " "Checksum=0x%.4X]\n", ntohs(udp_header->SrcPort), ntohs(udp_header->DstPort), ntohs(udp_header->Length), ntohs(udp_header->Checksum)); } SetConsoleTextAttribute(console, FOREGROUND_GREEN | FOREGROUND_BLUE); for (i = 0; i < packet_len; i++) { if (i % 20 == 0) { printf("\n\t"); } printf("%.2X", (UINT8)packet[i]); } SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_BLUE); for (i = 0; i < packet_len; i++) { if (i % 40 == 0) { printf("\n\t"); } if (isprint(packet[i])) { putchar(packet[i]); } else { putchar('.'); } } putchar('\n'); SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); } }
/* * Entry. */ int __cdecl main(int argc, char **argv) { HANDLE handle, console; UINT i; INT16 priority = 0; unsigned char packet[MAXBUF]; UINT packet_len; WINDIVERT_ADDRESS recv_addr, send_addr; PWINDIVERT_IPHDR ip_header; PWINDIVERT_IPV6HDR ipv6_header; PWINDIVERT_ICMPHDR icmp_header; PWINDIVERT_ICMPV6HDR icmpv6_header; PWINDIVERT_TCPHDR tcp_header; PWINDIVERT_UDPHDR udp_header; UINT payload_len; const char *err_str; TCPPACKET reset0; PTCPPACKET reset = &reset0; UINT8 dnr0[sizeof(ICMPPACKET) + 0x0F*sizeof(UINT32) + 8 + 1]; PICMPPACKET dnr = (PICMPPACKET)dnr0; TCPV6PACKET resetv6_0; PTCPV6PACKET resetv6 = &resetv6_0; UINT8 dnrv6_0[sizeof(ICMPV6PACKET) + sizeof(WINDIVERT_IPV6HDR) + sizeof(WINDIVERT_TCPHDR)]; PICMPV6PACKET dnrv6 = (PICMPV6PACKET)dnrv6_0; // Check arguments. switch (argc) { case 2: break; case 3: priority = (INT16)atoi(argv[2]); break; default: fprintf(stderr, "usage: %s windivert-filter [priority]\n", argv[0]); fprintf(stderr, "examples:\n"); fprintf(stderr, "\t%s true\n", argv[0]); fprintf(stderr, "\t%s \"outbound and tcp.DstPort == 80\" 1000\n", argv[0]); fprintf(stderr, "\t%s \"inbound and tcp.Syn\" -400\n", argv[0]); exit(EXIT_FAILURE); } // Initialize all packets. PacketIpTcpInit(reset); reset->tcp.Rst = 1; reset->tcp.Ack = 1; PacketIpIcmpInit(dnr); dnr->icmp.Type = 3; // Destination not reachable. dnr->icmp.Code = 3; // Port not reachable. PacketIpv6TcpInit(resetv6); resetv6->tcp.Rst = 1; resetv6->tcp.Ack = 1; PacketIpv6Icmpv6Init(dnrv6); dnrv6->ipv6.Length = htons(sizeof(WINDIVERT_ICMPV6HDR) + 4 + sizeof(WINDIVERT_IPV6HDR) + sizeof(WINDIVERT_TCPHDR)); dnrv6->icmpv6.Type = 1; // Destination not reachable. dnrv6->icmpv6.Code = 4; // Port not reachable. // Get console for pretty colors. console = GetStdHandle(STD_OUTPUT_HANDLE); // Divert traffic matching the filter: handle = WinDivertOpen(argv[1], WINDIVERT_LAYER_NETWORK, priority, 0); if (handle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_INVALID_PARAMETER && !WinDivertHelperCheckFilter(argv[1], WINDIVERT_LAYER_NETWORK, &err_str, NULL)) { fprintf(stderr, "error: invalid filter \"%s\"\n", err_str); exit(EXIT_FAILURE); } fprintf(stderr, "error: failed to open the WinDivert device (%d)\n", GetLastError()); exit(EXIT_FAILURE); } // Main loop: while (TRUE) { // Read a matching packet. if (!WinDivertRecv(handle, packet, sizeof(packet), &recv_addr, &packet_len)) { fprintf(stderr, "warning: failed to read packet\n"); continue; } // Print info about the matching packet. WinDivertHelperParsePacket(packet, packet_len, &ip_header, &ipv6_header, &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, &payload_len); if (ip_header == NULL && ipv6_header == NULL) { continue; } // Dump packet info: SetConsoleTextAttribute(console, FOREGROUND_RED); fputs("BLOCK ", stdout); SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); if (ip_header != NULL) { UINT8 *src_addr = (UINT8 *)&ip_header->SrcAddr; UINT8 *dst_addr = (UINT8 *)&ip_header->DstAddr; printf("ip.SrcAddr=%u.%u.%u.%u ip.DstAddr=%u.%u.%u.%u ", src_addr[0], src_addr[1], src_addr[2], src_addr[3], dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]); } if (ipv6_header != NULL) { UINT16 *src_addr = (UINT16 *)&ipv6_header->SrcAddr; UINT16 *dst_addr = (UINT16 *)&ipv6_header->DstAddr; fputs("ipv6.SrcAddr=", stdout); for (i = 0; i < 8; i++) { printf("%x%c", ntohs(src_addr[i]), (i == 7? ' ': ':')); } fputs(" ipv6.DstAddr=", stdout); for (i = 0; i < 8; i++) { printf("%x%c", ntohs(dst_addr[i]), (i == 7? ' ': ':')); } putchar(' '); } if (icmp_header != NULL) { printf("icmp.Type=%u icmp.Code=%u ", icmp_header->Type, icmp_header->Code); // Simply drop ICMP } if (icmpv6_header != NULL) { printf("icmpv6.Type=%u icmpv6.Code=%u ", icmpv6_header->Type, icmpv6_header->Code); // Simply drop ICMPv6 } if (tcp_header != NULL) { printf("tcp.SrcPort=%u tcp.DstPort=%u tcp.Flags=", ntohs(tcp_header->SrcPort), ntohs(tcp_header->DstPort)); if (tcp_header->Fin) { fputs("[FIN]", stdout); } if (tcp_header->Rst) { fputs("[RST]", stdout); } if (tcp_header->Urg) { fputs("[URG]", stdout); } if (tcp_header->Syn) { fputs("[SYN]", stdout); } if (tcp_header->Psh) { fputs("[PSH]", stdout); } if (tcp_header->Ack) { fputs("[ACK]", stdout); } putchar(' '); if (ip_header != NULL && !tcp_header->Rst && !tcp_header->Fin) { reset->ip.SrcAddr = ip_header->DstAddr; reset->ip.DstAddr = ip_header->SrcAddr; reset->tcp.SrcPort = tcp_header->DstPort; reset->tcp.DstPort = tcp_header->SrcPort; reset->tcp.SeqNum = (tcp_header->Ack? tcp_header->AckNum: 0); reset->tcp.AckNum = (tcp_header->Syn? htonl(ntohl(tcp_header->SeqNum) + 1): htonl(ntohl(tcp_header->SeqNum) + payload_len)); WinDivertHelperCalcChecksums((PVOID)reset, sizeof(TCPPACKET), 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = !recv_addr.Direction; if (!WinDivertSend(handle, (PVOID)reset, sizeof(TCPPACKET), &send_addr, NULL)) { fprintf(stderr, "warning: failed to send TCP reset (%d)\n", GetLastError()); } } if (ipv6_header != NULL && !tcp_header->Rst && !tcp_header->Fin) { memcpy(resetv6->ipv6.SrcAddr, ipv6_header->DstAddr, sizeof(resetv6->ipv6.SrcAddr)); memcpy(resetv6->ipv6.DstAddr, ipv6_header->SrcAddr, sizeof(resetv6->ipv6.DstAddr)); resetv6->tcp.SrcPort = tcp_header->DstPort; resetv6->tcp.DstPort = tcp_header->SrcPort; resetv6->tcp.SeqNum = (tcp_header->Ack? tcp_header->AckNum: 0); resetv6->tcp.AckNum = (tcp_header->Syn? htonl(ntohl(tcp_header->SeqNum) + 1): htonl(ntohl(tcp_header->SeqNum) + payload_len)); WinDivertHelperCalcChecksums((PVOID)resetv6, sizeof(TCPV6PACKET), 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = !recv_addr.Direction; if (!WinDivertSend(handle, (PVOID)resetv6, sizeof(TCPV6PACKET), &send_addr, NULL)) { fprintf(stderr, "warning: failed to send TCP (IPV6) " "reset (%d)\n", GetLastError()); } } } if (udp_header != NULL) { printf("udp.SrcPort=%u udp.DstPort=%u ", ntohs(udp_header->SrcPort), ntohs(udp_header->DstPort)); if (ip_header != NULL) { UINT icmp_length = ip_header->HdrLength*sizeof(UINT32) + 8; memcpy(dnr->data, ip_header, icmp_length); icmp_length += sizeof(ICMPPACKET); dnr->ip.Length = htons((UINT16)icmp_length); dnr->ip.SrcAddr = ip_header->DstAddr; dnr->ip.DstAddr = ip_header->SrcAddr; WinDivertHelperCalcChecksums((PVOID)dnr, icmp_length, 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = !recv_addr.Direction; if (!WinDivertSend(handle, (PVOID)dnr, icmp_length, &send_addr, NULL)) { fprintf(stderr, "warning: failed to send ICMP message " "(%d)\n", GetLastError()); } } if (ipv6_header != NULL) { UINT icmpv6_length = sizeof(WINDIVERT_IPV6HDR) + sizeof(WINDIVERT_TCPHDR); memcpy(dnrv6->data, ipv6_header, icmpv6_length); icmpv6_length += sizeof(ICMPV6PACKET); memcpy(dnrv6->ipv6.SrcAddr, ipv6_header->DstAddr, sizeof(dnrv6->ipv6.SrcAddr)); memcpy(dnrv6->ipv6.DstAddr, ipv6_header->SrcAddr, sizeof(dnrv6->ipv6.DstAddr)); WinDivertHelperCalcChecksums((PVOID)dnrv6, icmpv6_length, 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = !recv_addr.Direction; if (!WinDivertSend(handle, (PVOID)dnrv6, icmpv6_length, &send_addr, NULL)) { fprintf(stderr, "warning: failed to send ICMPv6 message " "(%d)\n", GetLastError()); } } } putchar('\n'); } }
static int sendAllListPackets() { // send packet from tail to head and remove sent ones int sendCount = 0; UINT sendLen; PacketNode *pnode; #ifdef _DEBUG // check the list is good // might go into dead loop but it's better for debugging PacketNode *p = head; do { p = p->next; } while (p->next); assert(p == tail); #endif while (!isListEmpty()) { pnode = popNode(tail->prev); sendLen = 0; assert(pnode != head); // FIXME inbound injection on any kind of packet is failing with a very high percentage // need to contact windivert auther and wait for next release if (!WinDivertSend(divertHandle, pnode->packet, pnode->packetLen, &(pnode->addr), &sendLen)) { PWINDIVERT_ICMPHDR icmp_header; PWINDIVERT_ICMPV6HDR icmpv6_header; PWINDIVERT_IPHDR ip_header; PWINDIVERT_IPV6HDR ipv6_header; LOG("Failed to send a packet. (%lu)", GetLastError()); dumpPacket(pnode->packet, pnode->packetLen, &(pnode->addr)); // as noted in windivert help, reinject inbound icmp packets some times would fail // workaround this by resend them as outbound // TODO not sure is this even working as can't find a way to test // need to document about this WinDivertHelperParsePacket(pnode->packet, pnode->packetLen, &ip_header, &ipv6_header, &icmp_header, &icmpv6_header, NULL, NULL, NULL, NULL); if ((icmp_header || icmpv6_header) && IS_INBOUND(pnode->addr.Direction)) { BOOL resent; pnode->addr.Direction = WINDIVERT_DIRECTION_OUTBOUND; if (ip_header) { UINT32 tmp = ip_header->SrcAddr; ip_header->SrcAddr = ip_header->DstAddr; ip_header->DstAddr = tmp; } else if (ipv6_header) { UINT32 tmpArr[4]; memcpy(tmpArr, ipv6_header->SrcAddr, sizeof(tmpArr)); memcpy(ipv6_header->SrcAddr, ipv6_header->DstAddr, sizeof(tmpArr)); memcpy(ipv6_header->DstAddr, tmpArr, sizeof(tmpArr)); } resent = WinDivertSend(divertHandle, pnode->packet, pnode->packetLen, &(pnode->addr), &sendLen); LOG("Resend failed inbound ICMP packets as outbound: %s", resent ? "SUCCESS" : "FAIL"); InterlockedExchange16(&sendState, SEND_STATUS_SEND); } else { InterlockedExchange16(&sendState, SEND_STATUS_FAIL); } } else { if (sendLen < pnode->packetLen) { // TODO don't know how this can happen, or it needs to be resent like good old UDP packet LOG("Internal Error: DivertSend truncated send packet."); InterlockedExchange16(&sendState, SEND_STATUS_FAIL); } else { InterlockedExchange16(&sendState, SEND_STATUS_SEND); } } freeNode(pnode); ++sendCount; } assert(isListEmpty()); // all packets should be sent by now return sendCount; }
short TamperNoServer::process(DivertPacket *& dPacket) { /* Check the server rules */ switch ((*ppNoServerConfig)->noServersType) { case NO_SERVERS_CUSTOM: { while (true) { /* Pull an entry off of the list */ TamperNoServerEntry* listEntry = reinterpret_cast<TamperNoServerEntry*>(InterlockedPopEntrySList((*ppNoServerConfig)->noServersList)); /* If it is null, we've reached the end of the list and should leave the loop */ if (listEntry == nullptr) { break; } /* If our version doesn't match the entry version, we have old data and need to clear our list */ if (serverListVersion != listEntry->version) { serverList.clear(); serverListVersion = listEntry->version; } /* Add the port to the list and then free the list entry memory */ serverList.push_back(reinterpret_cast<TamperNoServerEntry*>(listEntry)->server); _aligned_free(listEntry); listEntry = nullptr; /* Loop continues until we get a null pop entry */ } break; } case NO_SERVERS_OFF: default: return 0; } /* Drop any packets traveling over blocked ports */ WINDIVERT_IPHDR *iphdr = nullptr; WINDIVERT_TCPHDR *tcphdr = nullptr; WINDIVERT_UDPHDR *udphdr = nullptr; WinDivertHelperParsePacket(dPacket->packet, dPacket->packetLength, &iphdr, 0, 0, 0, &tcphdr, &udphdr, 0, 0); if (iphdr) { for (UINT32 server : serverList) { if (iphdr->DstAddr == server || iphdr->SrcAddr == server) { /* Drop packet */ free(dPacket); dPacket = nullptr; break; } } return 0; } /* No IP header. Skip this packet */ return 0; }
int main(int argc, char *argv[]) { static const char fragment_size_message[] = "Fragment size should be in range [0 - 65535]\n"; int i, should_reinject = 0; int opt; HANDLE w_filter = NULL; WINDIVERT_ADDRESS addr; char packet[MAX_PACKET_SIZE]; PVOID packet_data; UINT packetLen; UINT packet_dataLen; PWINDIVERT_IPHDR ppIpHdr; PWINDIVERT_TCPHDR ppTcpHdr; int do_passivedpi = 0, do_fragment_http = 0, do_fragment_https = 0, do_host = 0, do_host_removespace = 0, do_additional_space = 0; int http_fragment_size = 2; int https_fragment_size = 2; char *data_addr, *data_addr_rn, *host_addr, *useragent_addr, *method_addr; int data_len, host_len; printf("GoodbyeDPI: Passive DPI blocker and Active DPI circumvention utility\n"); if (argc == 1) { /* enable mode -1 by default */ do_passivedpi = do_host = do_host_removespace \ = do_fragment_http = do_fragment_https = 1; } while ((opt = getopt(argc, argv, "1234prsaf:e:")) != -1) { switch (opt) { case '1': do_passivedpi = do_host = do_host_removespace \ = do_fragment_http = do_fragment_https = 1; break; case '2': do_passivedpi = do_host = do_host_removespace \ = do_fragment_http = do_fragment_https = 1; https_fragment_size = 40; break; case '3': do_passivedpi = do_host = do_host_removespace \ = do_fragment_https = 1; https_fragment_size = 40; case '4': do_passivedpi = do_host = do_host_removespace = 1; break; case 'p': do_passivedpi = 1; break; case 'r': do_host = 1; break; case 's': do_host_removespace = 1; break; case 'a': do_additional_space = 1; do_host_removespace = 1; break; case 'f': do_fragment_http = 1; http_fragment_size = atoi(optarg); if (http_fragment_size <= 0 || http_fragment_size > 65535) { printf(fragment_size_message); exit(EXIT_FAILURE); } break; case 'e': do_fragment_https = 1; https_fragment_size = atoi(optarg); if (https_fragment_size <= 0 || https_fragment_size > 65535) { printf(fragment_size_message); exit(EXIT_FAILURE); } break; default: printf("Usage: goodbyedpi.exe [OPTION...]\n" " -p block passive DPI\n" " -r replace Host with hoSt\n" " -s remove space between host header and its value\n" " -a additional space between Method and Request-URI (enables -s, may break sites)\n" " -f [value] set HTTP fragmentation to value\n" " -e [value] set HTTPS fragmentation to value\n" "\n" " -1 -p -r -s -f 2 -e 2 (most compatible mode, default)\n" " -2 -p -r -s -f 2 -e 40 (better speed yet still compatible)\n" " -3 -p -r -s -e 40 (even better speed)\n" " -4 -p -r -s (best speed)\n"); exit(EXIT_FAILURE); } } printf("Block passive: %d, Fragment HTTP: %d, Fragment HTTPS: %d, " "hoSt: %d, Host no space: %d, Additional space: %d\n", do_passivedpi, (do_fragment_http ? http_fragment_size : 0), (do_fragment_https ? https_fragment_size : 0), do_host, do_host_removespace, do_additional_space); printf("\nOpening filter\n"); filter_num = 0; if (do_passivedpi) { /* IPv4 filter for inbound RST packets with ID = 0 or 1 */ filters[filter_num] = init( "inbound and ip and tcp and " "(ip.Id == 0x0001 or ip.Id == 0x0000) and " "(tcp.SrcPort == 443 or tcp.SrcPort == 80) and tcp.Rst and " DIVERT_NO_LOCALNETS_SRC, WINDIVERT_FLAG_DROP); filter_num++; } /* * IPv4 filter for inbound HTTP redirection packets and * active DPI circumvention */ filters[filter_num] = init("ip and tcp and " "(inbound and ((" "((ip.Id == 0x0001 or ip.Id == 0x0000) and tcp.SrcPort == 80 and tcp.Ack) or " "((tcp.SrcPort == 80 or tcp.SrcPort == 443) and tcp.Ack and tcp.Syn)" ") and " DIVERT_NO_LOCALNETS_SRC ") or " "(outbound and " "(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " DIVERT_NO_LOCALNETS_DST ")" ")", 0); w_filter = filters[filter_num]; filter_num++; for (i = 0; i < filter_num; i++) { if (filters[i] == NULL) die(); } printf("Filter activated!\n"); signal(SIGINT, sigint_handler); while (1) { if (WinDivertRecv(w_filter, packet, sizeof(packet), &addr, &packetLen)) { //printf("Got %s packet, len=%d!\n", addr.Direction ? "inbound" : "outbound", // packetLen); should_reinject = 1; if (WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen)) { //printf("Got parsed packet, len=%d!\n", packet_dataLen); /* Got a packet WITH DATA */ /* Handle INBOUND packet with data and find HTTP REDIRECT in there */ if (addr.Direction == WINDIVERT_DIRECTION_INBOUND && packet_dataLen > 16) { /* If INBOUND packet with DATA (tcp.Ack) */ /* Drop packets from filter with HTTP 30x Redirect */ if (do_passivedpi && is_passivedpi_redirect(packet_data, packet_dataLen)) { //printf("Dropping HTTP Redirect packet!\n"); should_reinject = 0; } } /* Handle OUTBOUND packet, search for Host header */ else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND && packet_dataLen > 16 && ppTcpHdr->DstPort == htons(80) && find_http_method_end(packet_data) && (do_host || do_host_removespace)) { data_addr = find_host_header(packet_data, packet_dataLen); if (data_addr) { if (do_host) { /* Replace "Host: " with "hoSt: " */ memcpy(data_addr, http_host_replace, strlen(http_host_replace)); //printf("Replaced Host header!\n"); } if (do_additional_space && do_host_removespace) { /* End of "Host:" without trailing space */ host_addr = data_addr + strlen(http_host_find) - 1; method_addr = find_http_method_end(packet_data); if (method_addr) { memmove(method_addr + 1, method_addr, (PVOID)host_addr - (PVOID)method_addr); } } else if (do_host_removespace) { host_addr = data_addr + strlen(http_host_find); data_addr_rn = dumb_memmem(host_addr, packet_dataLen - ((PVOID)host_addr - packet_data), "\r\n", 2); if (data_addr_rn) { /* We move Host header value by one byte to the left and then * "insert" stolen space to the end of User-Agent value because * some web servers are not tolerant to additional space in the * end of Host header. * * Nothing is done if User-Agent header is missing. */ host_len = data_addr_rn - host_addr; useragent_addr = find_useragent_header(packet_data, packet_dataLen); if (host_len <= 253 && useragent_addr && useragent_addr > host_addr) { /* Performing action only if User-Agent header goes after Host */ useragent_addr += strlen(http_useragent_find); /* useragent_addr is in the beginning of User-Agent value */ data_len = packet_dataLen - ((PVOID)useragent_addr - packet_data); data_addr_rn = dumb_memmem(useragent_addr, data_len, "\r\n", 2); /* data_addr_rn is in the end of User-Agent value */ if (data_addr_rn) { data_len = (PVOID)data_addr_rn - (PVOID)host_addr; /* Move one byte to the left from "Host:" * to the end of User-Agen */ memmove(host_addr - 1, host_addr, data_len); /* Put space in the end of User-Agent header */ *(char*)(data_addr_rn - 1) = ' '; //printf("Replaced Host header!\n"); } } } } WinDivertHelperCalcChecksums(packet, packetLen, 0); } } } /* Else if we got TCP packet without data */ else if (WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, NULL, NULL, NULL, &ppTcpHdr, NULL, NULL, NULL)) { /* If we got SYN+ACK packet */ if (addr.Direction == WINDIVERT_DIRECTION_INBOUND && ppTcpHdr->Syn == 1) { //printf("Changing Window Size!\n"); if (do_fragment_http && ppTcpHdr->SrcPort == htons(80)) { change_window_size(packet, http_fragment_size); WinDivertHelperCalcChecksums(packet, packetLen, 0); } else if (do_fragment_https && ppTcpHdr->SrcPort != htons(80)) { change_window_size(packet, https_fragment_size); WinDivertHelperCalcChecksums(packet, packetLen, 0); } } } if (should_reinject) { //printf("Re-injecting!\n"); WinDivertSend(w_filter, packet, packetLen, &addr, NULL); } } else { // error, ignore printf("Error receiving packet!\n"); break; } } }