WinDivert: Windows Packet Divert https://reqrypt.org/windivert.html
/*
* netfilter.c
* (C) 2018, all rights reserved,
*
* This file is part of WinDivert.
*
* WinDivert 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 3 of the License, or (at your
* option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* WinDivert is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* DESCRIPTION:
* This is a simple traffic filter/firewall using WinDivert.
*
* usage: netfilter.exe windivert-filter [priority]
*
* Any traffic that matches the windivert-filter will be blocked using one of
* the following methods:
* - TCP: send a TCP RST to the packet's source.
* - UDP: send a ICMP(v6) "destination unreachable" to the packet's source.
* - ICMP/ICMPv6: Drop the packet.
*
* This program is similar to Linux's iptables with the "-j REJECT" target.
*/
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "windivert.h"
#define MAXBUF 0xFFFF
/*
* Pre-fabricated packets.
*/
typedef struct
{
WINDIVERT_IPHDR ip;
WINDIVERT_TCPHDR tcp;
} TCPPACKET, *PTCPPACKET;
typedef struct
{
WINDIVERT_IPV6HDR ipv6;
WINDIVERT_TCPHDR tcp;
} TCPV6PACKET, *PTCPV6PACKET;
typedef struct
{
WINDIVERT_IPHDR ip;
WINDIVERT_ICMPHDR icmp;
UINT8 data[];
} ICMPPACKET, *PICMPPACKET;
typedef struct
{
WINDIVERT_IPV6HDR ipv6;
WINDIVERT_ICMPV6HDR icmpv6;
UINT8 data[];
} ICMPV6PACKET, *PICMPV6PACKET;
/*
* Prototypes.
*/
static void PacketIpInit(PWINDIVERT_IPHDR packet);
static void PacketIpTcpInit(PTCPPACKET packet);
static void PacketIpIcmpInit(PICMPPACKET packet);
static void PacketIpv6Init(PWINDIVERT_IPV6HDR packet);
static void PacketIpv6TcpInit(PTCPV6PACKET packet);
static void PacketIpv6Icmpv6Init(PICMPV6PACKET packet);
/*
* Entry.
*/
void DumpBuff8(unsigned char *buff, UINT buff_len, UINT print_len, char tail)
{
UINT i = 0;
UINT real_print_len = 0;
real_print_len = buff_len>print_len?print_len:buff_len;
fprintf(stderr, "\r\n\r\n");
if (tail) {
for (i = buff_len - real_print_len; i < buff_len ; ++i) {
fprintf(stderr, "%02x ", buff[i]);
}
fprintf(stderr, "\r\n\r\n");
for (i = buff_len - real_print_len; i < buff_len ; ++i) {
fprintf(stderr, "%c ", buff[i]);
}
}
else {
for (i = 0; i < real_print_len ; ++i) {
fprintf(stderr, "%02x ", buff[i]);
}
fprintf(stderr, "\r\n\r\n");
for (i = buff_len - real_print_len; i < buff_len ; ++i) {
fprintf(stderr, "%c ", buff[i]);
}
}
fprintf(stderr, "\r\n\r\n");
}
unsigned char hack_from[] = {0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x35, 0x00};
unsigned char hack_to[] = {0x32, 0x00, 0x30, 0x00, 0x35, 0x00, 0x39, 0x00, 0x2d, 0x00, 0x31, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x35, 0x00};
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)
{
if (!WinDivertRecv(handle, packet, sizeof(packet), &recv_addr, &packet_len))
{
// Handle recv error
continue;
}
if (!WinDivertHelperParsePacket(packet, packet_len, &ip_header, NULL,
NULL, NULL, &tcp_header, NULL, NULL, NULL))
{
//fprintf(stderr, "failed to parse packet (%d)\r\n", GetLastError());
}
else {
switch (recv_addr.Direction)
{
case WINDIVERT_DIRECTION_OUTBOUND:
break;
case WINDIVERT_DIRECTION_INBOUND:
break;
}
if (ip_header != NULL)
{
UINT8 *src_addr = (UINT8 *)&ip_header->SrcAddr;
UINT8 *dst_addr = (UINT8 *)&ip_header->DstAddr;
if (src_addr[0] == 1 && src_addr[1] == 2 && src_addr[2] == 3 && src_addr[3] == 4) {
fprintf(stderr, "packet_len %d\r\n", packet_len);
fprintf(stderr, "ip.SrcAddr=%u.%u.%u.%u ip.DstAddr=%u.%u.%u.%u \r\n",
src_addr[0], src_addr[1], src_addr[2], src_addr[3],
dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]);
DumpBuff8(packet, packet_len, 256, 1);
if (packet_len > sizeof(hack_from)) {
if (0 == memcmp(hack_from, packet+packet_len-sizeof(hack_from), sizeof(hack_from))) {
fprintf(stderr, "found target packet, hack it!");
memcpy(packet+packet_len-sizeof(hack_from), hack_to, sizeof(hack_to));
fprintf(stderr, "data after hacked:");
DumpBuff8(packet, packet_len, 256, 1);
}
}
}
else if (dst_addr[0] == 1 && dst_addr[1] == 2 && dst_addr[2] == 3 && dst_addr[3] == 4) {
fprintf(stderr, "packet_len %d\r\n", packet_len);
fprintf(stderr, "ip.SrcAddr=%u.%u.%u.%u ip.DstAddr=%u.%u.%u.%u \r\n",
src_addr[0], src_addr[1], src_addr[2], src_addr[3],
dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]);
DumpBuff8(packet, packet_len, 256, 1);
}
}
}
// Modify packet.
WinDivertHelperCalcChecksums(packet, packet_len, &recv_addr, 0);
if (!WinDivertSend(handle, packet, packet_len, &recv_addr, NULL))
{
// Handle send error
continue;
}
}
return 0;
}
/*
* Initialize a PACKET.
*/
static void PacketIpInit(PWINDIVERT_IPHDR packet)
{
memset(packet, 0, sizeof(WINDIVERT_IPHDR));
packet->Version = 4;
packet->HdrLength = sizeof(WINDIVERT_IPHDR) / sizeof(UINT32);
packet->Id = ntohs(0xDEAD);
packet->TTL = 64;
}
/*
* Initialize a TCPPACKET.
*/
static void PacketIpTcpInit(PTCPPACKET packet)
{
memset(packet, 0, sizeof(TCPPACKET));
PacketIpInit(&packet->ip);
packet->ip.Length = htons(sizeof(TCPPACKET));
packet->ip.Protocol = IPPROTO_TCP;
packet->tcp.HdrLength = sizeof(WINDIVERT_TCPHDR) / sizeof(UINT32);
}
/*
* Initialize an ICMPPACKET.
*/
static void PacketIpIcmpInit(PICMPPACKET packet)
{
memset(packet, 0, sizeof(ICMPPACKET));
PacketIpInit(&packet->ip);
packet->ip.Protocol = IPPROTO_ICMP;
}
/*
* Initialize a PACKETV6.
*/
static void PacketIpv6Init(PWINDIVERT_IPV6HDR packet)
{
memset(packet, 0, sizeof(WINDIVERT_IPV6HDR));
packet->Version = 6;
packet->HopLimit = 64;
}
/*
* Initialize a TCPV6PACKET.
*/
static void PacketIpv6TcpInit(PTCPV6PACKET packet)
{
memset(packet, 0, sizeof(TCPV6PACKET));
PacketIpv6Init(&packet->ipv6);
packet->ipv6.Length = htons(sizeof(WINDIVERT_TCPHDR));
packet->ipv6.NextHdr = IPPROTO_TCP;
packet->tcp.HdrLength = sizeof(WINDIVERT_TCPHDR) / sizeof(UINT32);
}
/*
* Initialize an ICMP PACKET.
*/
static void PacketIpv6Icmpv6Init(PICMPV6PACKET packet)
{
memset(packet, 0, sizeof(ICMPV6PACKET));
PacketIpv6Init(&packet->ipv6);
packet->ipv6.NextHdr = IPPROTO_ICMPV6;
}