static DWORD divertReadLoop(LPVOID arg) { char packetBuf[MAX_PACKETSIZE]; DIVERT_ADDRESS addrBuf; UINT readLen; PacketNode *pnode; DWORD waitResult; UNREFERENCED_PARAMETER(arg); for(;;) { // each step must fully consume the list assert(isListEmpty()); // FIXME has failed this assert before. don't know why if (!DivertRecv(divertHandle, packetBuf, MAX_PACKETSIZE, &addrBuf, &readLen)) { DWORD lastError = GetLastError(); if (lastError == ERROR_INVALID_HANDLE || lastError == ERROR_OPERATION_ABORTED) { // treat closing handle as quit LOG("Handle died or operation aborted. Exit loop."); return 0; } LOG("Failed to recv a packet. (%lu)", GetLastError()); continue; } if (readLen > MAX_PACKETSIZE) { // don't know how this can happen LOG("Interal Error: DivertRecv truncated recv packet."); } //dumpPacket(packetBuf, readLen, &addrBuf); waitResult = WaitForSingleObject(mutex, INFINITE); switch(waitResult) { case WAIT_OBJECT_0: /***************** enter critical region ************************/ if (stopLooping) { LOG("Lost last recved packet but user stopped. Stop read loop."); /***************** leave critical region ************************/ if (!ReleaseMutex(mutex)) { LOG("Falal: Failed to release mutex on stopping (%lu). Will stop anyway.", GetLastError()); } return 0; } // create node and put it into the list pnode = createNode(packetBuf, readLen, &addrBuf); appendNode(pnode); divertConsumeStep(); /***************** leave critical region ************************/ if (!ReleaseMutex(mutex)) { LOG("Falal: Failed to release mutex (%lu)", GetLastError()); ABORT(); } break; case WAIT_TIMEOUT: LOG("Aquire timeout, dropping one read packet"); continue; break; case WAIT_ABANDONED: LOG("Aquire abandoned."); return 0; case WAIT_FAILED: LOG("Aquire failed."); return 0; } } }
/* * Entry. */ int __cdecl main(int argc, char **argv) { HANDLE handle, console; UINT i; INT16 priority = 0; char packet[MAXBUF]; UINT packet_len; DIVERT_ADDRESS recv_addr, send_addr; PDIVERT_IPHDR ip_header; PDIVERT_IPV6HDR ipv6_header; PDIVERT_ICMPHDR icmp_header; PDIVERT_ICMPV6HDR icmpv6_header; PDIVERT_TCPHDR tcp_header; PDIVERT_UDPHDR udp_header; UINT payload_len; 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(DIVERT_IPV6HDR) + sizeof(DIVERT_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 divert-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); } // 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(DIVERT_ICMPV6HDR) + 4 + sizeof(DIVERT_IPV6HDR) + sizeof(DIVERT_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 = DivertOpen(argv[1], 0, priority, 0); 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 Divert device (%d)\n", GetLastError()); exit(EXIT_FAILURE); } // Main loop: while (TRUE) { // Read a matching packet. if (!DivertRecv(handle, packet, sizeof(packet), &recv_addr, &packet_len)) { fprintf(stderr, "warning: failed to read packet\n"); continue; } // Print info about the matching packet. DivertHelperParse(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) { 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)); DivertHelperCalcChecksums((PVOID)reset, sizeof(TCPPACKET), 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = !recv_addr.Direction; if (!DivertSend(handle, (PVOID)reset, sizeof(TCPPACKET), &send_addr, NULL)) { fprintf(stderr, "warning: failed to send TCP reset (%d)\n", GetLastError()); } } if (ipv6_header != NULL) { 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)); DivertHelperCalcChecksums((PVOID)resetv6, sizeof(TCPV6PACKET), 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = !recv_addr.Direction; if (!DivertSend(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) { // NOTE: For some ICMP error messages, WFP does not seem to // support INBOUND injection. As a work-around, we // always inject OUTBOUND. 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; DivertHelperCalcChecksums((PVOID)dnr, icmp_length, 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = DIVERT_DIRECTION_OUTBOUND; if (!DivertSend(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(DIVERT_IPV6HDR) + sizeof(DIVERT_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)); DivertHelperCalcChecksums((PVOID)dnrv6, icmpv6_length, 0); memcpy(&send_addr, &recv_addr, sizeof(send_addr)); send_addr.Direction = DIVERT_DIRECTION_OUTBOUND; if (!DivertSend(handle, (PVOID)dnrv6, icmpv6_length, &send_addr, NULL)) { fprintf(stderr, "warning: failed to send ICMPv6 message " "(%d)\n", GetLastError()); } } } putchar('\n'); } }
/* * Entry. */ int __cdecl main(int argc, char **argv) { HANDLE handle, console; UINT i; INT16 priority = 0; char packet[MAXBUF]; UINT packet_len; DIVERT_ADDRESS addr; PDIVERT_IPHDR ip_header; PDIVERT_IPV6HDR ipv6_header; PDIVERT_ICMPHDR icmp_header; PDIVERT_ICMPV6HDR icmpv6_header; PDIVERT_TCPHDR tcp_header; PDIVERT_UDPHDR udp_header; // Check arguments. switch (argc) { case 2: break; case 3: priority = (INT16)atoi(argv[2]); break; default: fprintf(stderr, "usage: %s divert-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 = DivertOpen(argv[1], 0, priority, DIVERT_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 Divert device (%d)\n", GetLastError()); exit(EXIT_FAILURE); } // Max-out the packet queue: if (!DivertSetParam(handle, DIVERT_PARAM_QUEUE_LEN, 8192)) { fprintf(stderr, "error: failed to set packet queue length (%d)\n", GetLastError()); exit(EXIT_FAILURE); } if (!DivertSetParam(handle, DIVERT_PARAM_QUEUE_TIME, 1024)) { fprintf(stderr, "error: failed to set packet queue time (%d)\n", GetLastError()); exit(EXIT_FAILURE); } // Main loop: while (TRUE) { // Read a matching packet. if (!DivertRecv(handle, packet, sizeof(packet), &addr, &packet_len)) { fprintf(stderr, "warning: failed to read packet (%d)\n", GetLastError()); continue; } // Print info about the matching packet. DivertHelperParse(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), DIVERT_IPHDR_GET_RESERVED(ip_header), DIVERT_IPHDR_GET_DF(ip_header), DIVERT_IPHDR_GET_MF(ip_header), ntohs(DIVERT_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, DIVERT_IPV6HDR_GET_TRAFFICCLASS(ipv6_header), ntohl(DIVERT_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); } }