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 (DivertHelperParsePacket(pac->packet, pac->packetLen, NULL, NULL, NULL, NULL, NULL, NULL, (PVOID*)&data, &dataLen) && data != NULL && dataLen != 0) { // trying to tamper the more center 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) { DivertHelperCalcChecksums(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; 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'); } }