📄 packet.c
字号:
if (buffer_len < sizeof(struct tcp_hdr))
{
KdPrint(("[tdi_fw] process_transp: too small buffer for tcp_hdr! (%u)\n",
buffer_len));
return FALSE;
}
tcp_hdr = (struct tcp_hdr *)pointer;
process_tcp(direction, tcp_hdr, log_nfo);
break;
case IPPROTO_UDP:
/* process udp_hdr */
if (buffer_len < sizeof(struct udp_hdr))
{
KdPrint(("[tdi_fw] process_transp: too small buffer for udp_hdr! (%u)\n",
buffer_len));
return FALSE;
}
udp_hdr = (struct udp_hdr *)pointer;
process_udp(direction, udp_hdr, log_nfo);
break;
case IPPROTO_ICMP:
/* process icmp_hdr */
if (buffer_len < sizeof(struct icmp_hdr))
{
KdPrint(("[tdi_fw] process_transp: too small buffer for icmp_hdr! (%u)\n",
buffer_len));
return FALSE;
}
icmp_hdr = (struct icmp_hdr *)pointer;
process_icmp(direction, icmp_hdr, log_nfo);
break;
default:
KdPrint(("[tdi_fw] process_transp: ipproto = %d\n", proto));
}
return TRUE;
}
/* process TCP header and check it against our information about connection objects */
void process_tcp(int direction, struct tcp_hdr *tcp_hdr, struct flt_request *log_nfo)
{
#if DBG
char flags[7];
flags[0] = (tcp_hdr->th_flags & TH_FIN) ? 'F' : ' ';
flags[1] = (tcp_hdr->th_flags & TH_SYN) ? 'S' : ' ';
flags[2] = (tcp_hdr->th_flags & TH_RST) ? 'R' : ' ';
flags[3] = (tcp_hdr->th_flags & TH_PUSH) ? 'P' : ' ';
flags[4] = (tcp_hdr->th_flags & TH_ACK) ? 'A' : ' ';
flags[5] = (tcp_hdr->th_flags & TH_URG) ? 'U' : ' ';
flags[6] = '\0';
KdPrint(("[tdi_fw] tcp %d -> %d (%s)\n",
ntohs(tcp_hdr->th_sport),
ntohs(tcp_hdr->th_dport),
flags));
#endif
log_nfo->packet.tcp_flags = tcp_hdr->th_flags;
((struct sockaddr_in *)(&log_nfo->addr.from))->sin_port = tcp_hdr->th_sport;
((struct sockaddr_in *)(&log_nfo->addr.to))->sin_port = tcp_hdr->th_dport;
check_packet(log_nfo);
}
/* process UDP header and check it against our informatation about address objects */
void process_udp(int direction, struct udp_hdr *udp_hdr, struct flt_request *log_nfo)
{
KdPrint(("[tdi_fw] udp %d -> %d\n", ntohs(udp_hdr->uh_sport), ntohs(udp_hdr->uh_dport)));
((struct sockaddr_in *)(&log_nfo->addr.from))->sin_port = udp_hdr->uh_sport;
((struct sockaddr_in *)(&log_nfo->addr.to))->sin_port = udp_hdr->uh_dport;
check_packet(log_nfo);
}
/* process ICMP header */
void process_icmp(int direction, struct icmp_hdr *icmp_hdr, struct flt_request *log_nfo)
{
KdPrint(("[tdi_fw] icmp (%d.%d)\n", icmp_hdr->icmp_type, icmp_hdr->icmp_code));
log_nfo->packet.icmp_type = icmp_hdr->icmp_type;
log_nfo->packet.icmp_code = icmp_hdr->icmp_code;
check_packet(log_nfo);
}
void init_tcp_states(void)
{
// init g_tcp_states sparse array (don't define RST flags)
#define DEFINE_STATE_IN(state, index, flags_set, flags_not_set) \
g_tcp_states[(state)][DIRECTION_IN][(index)].tcp_flags_set = (flags_set); \
g_tcp_states[(state)][DIRECTION_IN][(index)].tcp_flags_not_set = (flags_not_set)
#define DEFINE_STATE_OUT(state, index, flags_set, flags_not_set) \
g_tcp_states[(state)][DIRECTION_OUT][(index)].tcp_flags_set = (flags_set); \
g_tcp_states[(state)][DIRECTION_OUT][(index)].tcp_flags_not_set = (flags_not_set)
// -connection establishment
// --active (outgoing) connection
// ---SYN retransmitting + 3rd positive answer
DEFINE_STATE_OUT(TCP_STATE_SYN_SENT, 0, TH_SYN, TH_ACK);
DEFINE_STATE_OUT(TCP_STATE_SYN_SENT, 1, TH_ACK, TH_SYN | TH_FIN);
// ---positive answer
DEFINE_STATE_IN(TCP_STATE_SYN_SENT, 0, TH_SYN | TH_ACK, 0);
// --passive (incoming) connection
// ---positive answer
DEFINE_STATE_OUT(TCP_STATE_SYN_RCVD, 0, TH_SYN | TH_ACK, 0);
// ---last connect step: ACK or FIN(ACK)
DEFINE_STATE_IN(TCP_STATE_SYN_RCVD, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_IN(TCP_STATE_SYN_RCVD, 1, TH_FIN, TH_SYN);
// -established in/out: ACK, FIN
DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_IN, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_IN, 1, TH_FIN, TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_IN, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_IN, 1, TH_FIN, TH_SYN);
DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_OUT, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_OUT, 1, TH_FIN, TH_SYN);
// --peer didn't receive 3rd ACK packet
DEFINE_STATE_IN(TCP_STATE_ESTABLISHED_OUT, 2, TH_ACK | TH_SYN, TH_FIN);
DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_OUT, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_ESTABLISHED_OUT, 1, TH_FIN, TH_SYN);
// -connection closing
DEFINE_STATE_IN(TCP_STATE_FIN_WAIT1, 0, TH_FIN, TH_SYN);
DEFINE_STATE_IN(TCP_STATE_FIN_WAIT1, 1, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_FIN_WAIT1, 0, TH_FIN, TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_FIN_WAIT1, 1, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_IN(TCP_STATE_FIN_WAIT2, 0, TH_FIN, TH_SYN);
DEFINE_STATE_IN(TCP_STATE_FIN_WAIT2, 1, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_FIN_WAIT2, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_CLOSE_WAIT, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_LAST_ACK, 0, TH_FIN, TH_SYN);
DEFINE_STATE_OUT(TCP_STATE_LAST_ACK, 1, TH_ACK, TH_FIN | TH_SYN); // answer on FIN retransmitting
DEFINE_STATE_IN(TCP_STATE_LAST_ACK, 0, TH_ACK, TH_FIN | TH_SYN);
DEFINE_STATE_IN(TCP_STATE_LAST_ACK, 1, TH_FIN, TH_SYN); // FIN retransmitting
// -in "closed" state all incoming packets are allowed (except single SYN)
DEFINE_STATE_IN(TCP_STATE_CLOSED, 0, TH_ACK, 0);
DEFINE_STATE_IN(TCP_STATE_CLOSED, 1, TH_FIN, 0);
// -and RST out too
DEFINE_STATE_OUT(TCP_STATE_CLOSED, 0, TH_RST, 0);
// ??? I saw this packet sometimes (maybe there's a bug in my code?)
DEFINE_STATE_OUT(TCP_STATE_CLOSED, 1, TH_ACK, TH_FIN | TH_SYN);
}
/*
* check packet against state in obj_tbl
*
* NOTE: this function is experimental ONLY!!!
* To make work it better I should specify interface information: IP address and network mask
*/
void check_packet(struct flt_request *log_nfo)
{
BOOLEAN correct = FALSE;
struct sockaddr_in *addr_from = (struct sockaddr_in *)&log_nfo->addr.from,
*addr_to = (struct sockaddr_in *)&log_nfo->addr.to;
// check it
if (log_nfo->proto == IPPROTO_TCP)
{
/* TCP protocol */
if ((log_nfo->packet.tcp_flags & TH_SYN) &&
!(log_nfo->packet.tcp_flags & TH_ACK) &&
log_nfo->direction == DIRECTION_IN)
{
// active incoming connection (SYN+ ACK-): check against listening address objects
correct = is_listen(addr_to->sin_addr.s_addr, addr_to->sin_port, IPPROTO_TCP) ||
is_listen(0, addr_to->sin_port, IPPROTO_TCP);
}
else {
int state;
// just check address & port against connection table
if (log_nfo->direction == DIRECTION_OUT)
{
state = get_tcp_conn_state(addr_from->sin_addr.s_addr, addr_from->sin_port,
addr_to->sin_addr.s_addr, addr_to->sin_port);
if (state == TCP_STATE_NONE) // source addr can be 0
state = get_tcp_conn_state(0, addr_from->sin_port, addr_to->sin_addr.s_addr, addr_to->sin_port);
}
else { // DIRECTION_IN
state = get_tcp_conn_state(addr_to->sin_addr.s_addr, addr_to->sin_port,
addr_from->sin_addr.s_addr, addr_from->sin_port);
if (state == TCP_STATE_NONE) // dest addr can be 0
state = get_tcp_conn_state(0, addr_to->sin_port, addr_from->sin_addr.s_addr, addr_from->sin_port);
}
if (log_nfo->packet.tcp_flags & TH_RST)
correct = (state != TCP_STATE_NONE);
else {
// check connection state & header flags against g_tcp_states
int i;
for (i = 0; i < MAX_FLAGS; i++)
{
UCHAR tcp_flags_set = g_tcp_states[state][log_nfo->direction][i].tcp_flags_set;
if (tcp_flags_set == 0)
break;
if ((tcp_flags_set & log_nfo->packet.tcp_flags) == tcp_flags_set &&
!(g_tcp_states[state][log_nfo->direction][i].tcp_flags_not_set & log_nfo->packet.tcp_flags))
{
correct = TRUE;
break;
}
}
}
if (!correct && (log_nfo->packet.tcp_flags & TH_RST) && log_nfo->direction == DIRECTION_OUT)
{
// don't log RSTs on opened ports
correct = is_listen(addr_from->sin_addr.s_addr, addr_from->sin_port, IPPROTO_TCP) ||
is_listen(0, addr_from->sin_port, IPPROTO_TCP);
}
if (!correct)
log_nfo->packet.tcp_state = state;
}
}
else if (log_nfo->proto == IPPROTO_UDP)
{
// UDP: check it against listening address objects
if (log_nfo->direction == DIRECTION_IN)
{
// incoming datagram: check "to" addr & port
correct = is_listen(addr_to->sin_addr.s_addr, addr_to->sin_port, log_nfo->proto) ||
is_listen(0, addr_to->sin_port, log_nfo->proto) ||
(log_nfo->packet.is_broadcast &&
(addr_to->sin_addr.s_addr == (ULONG)-1 ||
is_bcast_listen(addr_to->sin_addr.s_addr, addr_to->sin_port, log_nfo->proto)));
}
else { // DIRECTION_OUT
// outgoing datagram: check "from" addr & port
correct = is_listen(addr_from->sin_addr.s_addr, addr_from->sin_port, log_nfo->proto) ||
is_listen(0, addr_from->sin_port, log_nfo->proto) ||
(log_nfo->packet.is_broadcast && is_bcast_listen(addr_from->sin_addr.s_addr, addr_from->sin_port, log_nfo->proto));
}
}
if (correct)
log_nfo->pid = (ULONG)-1; // don't log this packet
}
#if _WIN32_WINNT >= 0x0500
/* set or remove IP firewall hook */
NTSTATUS set_hook(PacketFilterExtensionPtr hook_fn)
{
UNICODE_STRING ipfilter_name;
NTSTATUS status;
PFILE_OBJECT fileobj = NULL;
PDEVICE_OBJECT devobj;
PF_SET_EXTENSION_HOOK_INFO hook_nfo;
PIRP irp = NULL;
IO_STATUS_BLOCK isb;
RtlInitUnicodeString(&ipfilter_name, DD_IPFLTRDRVR_DEVICE_NAME);
status = IoGetDeviceObjectPointer(
&ipfilter_name,
STANDARD_RIGHTS_ALL,
&fileobj,
&devobj);
if (status != STATUS_SUCCESS)
goto done;
hook_nfo.ExtensionPointer = hook_fn;
irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER,
devobj, &hook_nfo, sizeof(hook_nfo),
NULL, 0, FALSE, NULL, &isb);
if (irp == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
status = IoCallDriver(devobj, irp);
irp = NULL;
done:
/* cleanup */
if (fileobj != NULL)
ObDereferenceObject(fileobj);
if (irp != NULL)
IoFreeIrp(irp);
return status;
}
/* firewall callback hook proc */
PF_FORWARD_ACTION hook_proc(
unsigned char *PacketHeader,
unsigned char *Packet,
unsigned int PacketLength,
unsigned int RecvInterfaceIndex,
unsigned int SendInterfaceIndex,
IPAddr RecvLinkNextHop,
IPAddr SendLinkNextHop)
{
BOOLEAN log = FALSE, result = FALSE;
int direction, iface;
struct ip_hdr *ip_hdr;
struct flt_request log_nfo;
direction = (RecvInterfaceIndex != INVALID_PF_IF_INDEX) ? DIRECTION_IN : DIRECTION_OUT;
iface = (direction == DIRECTION_IN) ? RecvInterfaceIndex : SendInterfaceIndex;
KdPrint(("[tdi_fw] hook_proc: direction = %s; iface = 0x%x; len = %d\n",
direction == DIRECTION_IN ? "in" : "out", iface, PacketLength));
memset(&log_nfo, 0, sizeof(log_nfo));
log_nfo.struct_size = sizeof(log_nfo);
log_nfo.direction = direction;
// ...have not access to ethernet handler
ip_hdr = (struct ip_hdr *)PacketHeader;
if (ip_hdr->ip_dst == 0x0100007f)
{ // don't work with loopback interface
result = TRUE;
goto done;
}
// check we've got the first fragment (don't work with another!)
if ((ntohs(ip_hdr->ip_off) & IP_OFFMASK) != 0 && (ip_hdr->ip_off & IP_DF) == 0)
{
KdPrint(("[tdi_fw] hook_proc: got not first fragment\n"));
result = TRUE;
log = FALSE;
goto done;
}
process_ip(direction, ip_hdr, &log_nfo);
// no way to determine broadcasts without knowing interface IP/mask :-(
log_nfo.packet.is_broadcast = 1; // for datagram processing code
result = process_transp(direction, ip_hdr->ip_p, ip_hdr, Packet, PacketLength, &log_nfo);
if (!result)
goto done;
// using log_nfo->pid as signal to log it
log = (log_nfo.pid == 0);
result = TRUE; // packet headers looks like valid
done:
if (log){
log_nfo.result = result ? FILTER_PACKET_LOG : FILTER_PACKET_BAD;
log_nfo.pid = (ULONG)-1;
log_request(&log_nfo);
}
return result ? PF_FORWARD : PF_DROP;
}
#endif /* _WIN32_WINNT >= 0x0500 */
#endif /* USE_PACKET_ENGINE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -