📄 tdifw_svc.c
字号:
/* Copyright (c) 2002-2005 Vladislav Goncharov.
*
* Redistribution and use in source forms, with and without modification,
* are permitted provided that this entire comment appears intact.
*
* Redistribution in binary form may occur without any restrictions.
*
* This software is provided ``AS IS'' without any warranties of any kind.
*/
// $Id: tdifw_svc.c,v 1.23 2003/09/04 15:20:10 dev Exp $
/*
* TdiFw helper service
*/
#include <windows.h>
#include <winioctl.h>
#include <winsock.h>
#include <mmsystem.h>
#include <stdio.h>
#include <time.h>
#include "iphlpapi.h"
#include "flt_rule.h"
#include "ipc.h"
#include "net.h"
#include "tdifw_svc.h"
#include "thread.h"
#include "msg.h"
#define DISP_BUF_SIZE 0x10000
HANDLE g_device = INVALID_HANDLE_VALUE;
static HANDLE g_event = NULL;
static HANDLE g_exit_event = NULL;
static HANDLE g_pipe = INVALID_HANDLE_VALUE;
static HANDLE g_dispatcher = NULL;
static char *g_disp_buf = NULL;
static DWORD WINAPI dispatcher(LPVOID param);
static DWORD WINAPI restart_thread(LPVOID param);
static void dispatch_request(struct flt_request *request);
static FILE *g_logfile = NULL;
static const char *g_config_file = NULL;
static BOOL load_config(const char *config);
static BOOL read_config(const char *config);
static BOOL add_rules_name(const char *main_name, const char *config, int chain);
static void add_rules(const char *config, char *buf, const char *name, int chain);
static BOOL get_pname_by_pid(u_long pid, char *buf, int buf_size);
static void prepare_addr(char *buf, int size, u_long addr);
static void my_GetLongPathName(LPCSTR lpszShortPath, LPSTR lpszLongPath,
DWORD cchBuffer);
static int compare_ln(const void *arg1, const void *arg2);
static int compare_tn(const void *arg1, const void *arg2);
static void get_traffic_stats(unsigned __int64 *stats);
// some config switches
static BOOL g_eventlog_allow = FALSE;
static BOOL g_eventlog_deny = FALSE;
static BOOL g_eventlog_error = FALSE;
// wave files to play :-)
static char wave_deny_in[MAX_PATH];
static char wave_deny_out[MAX_PATH];
static void log_msg(const char *msg, int type);
enum
{
MSGTYPE_ALLOW,
MSGTYPE_DENY,
MSGTYPE_ERROR
};
static char g_device_name[] = "\\\\.\\tdifw";
static char g_nfo_device_name[] = "\\\\.\\tdifw_nfo";
// for dynamic linking with psapi.dll
static void link_psapi(void);
typedef BOOL WINAPI EnumProcesses_t(DWORD *, DWORD, DWORD *);
typedef BOOL WINAPI EnumProcessModules_t(HANDLE, HMODULE*, DWORD, DWORD*);
typedef BOOL WINAPI GetModuleFileNameEx_t(HANDLE, HMODULE, LPTSTR, DWORD);
static HMODULE g_psapi = NULL;
static EnumProcesses_t *pEnumProcesses = NULL;
static EnumProcessModules_t *pEnumProcessModules = NULL;
static GetModuleFileNameEx_t *pGetModuleFileNameEx = NULL;
// for routing code
static ULONG get_if_ip(ULONG remote_ip);
static ULONG route_ip(ULONG remote_ip);
static ULONG get_if_index_ip(ULONG if_index);
// for SID stuff
static BOOL load_users(const char *config);
static void get_sid_mask(const char *config, const char *name, UCHAR *sid_mask);
static BOOL check_for_name(const char *config, const char *section, const char *value, const char *name);
static const char *g_tcp_states[] =
{
"?",
"SYN_SENT",
"SYN_RCVD",
"ESTABLISHED(in)",
"ESTABLISHED(out)",
"FIN_WAIT1",
"FIN_WAIT2",
"TIME_WAIT",
"CLOSE_WAIT",
"LAST_ACK",
"CLOSED"
};
int start(const char *config)
{
int result = FALSE;
WSADATA wsd;
DWORD thread_id;
WSAStartup(MAKEWORD(1, 1), &wsd);
// try to dynamically link psapi.dll
link_psapi();
/* connect with driver */
g_device = CreateFile(g_device_name, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (g_device == INVALID_HANDLE_VALUE)
{
winerr(g_device_name);
goto done;
}
/* open event for driver communication */
g_event = OpenEvent(SYNCHRONIZE, FALSE, "tdifw_request");
if (g_event == NULL)
{
winerr("start: OpenEvent");
goto done;
}
/* load config & rules */
if (!load_config(config))
goto done;
/* start dispatcher thread */
g_exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (g_exit_event == NULL)
{
winerr("start: CreateEvent");
goto done;
}
g_disp_buf = (char *)malloc(DISP_BUF_SIZE);
if (g_disp_buf == NULL)
{
liberr("start: malloc");
goto done;
}
log_msg("START", MSGTYPE_ALLOW);
g_dispatcher = lib_CreateThread(NULL, 0, dispatcher, (LPVOID)config, 0, &thread_id);
if (g_dispatcher == NULL)
{
winerr("start: lib_CreateThread");
goto done;
}
result = TRUE;
done:
if (!result)
stop();
return result;
}
void stop(void)
{
// collect statistics
if (g_logfile != NULL)
{
// output traffic statistic!
unsigned __int64 traffic[TRAFFIC_MAX];
char msg[200];
get_traffic_stats(traffic);
sprintf(msg, "TRAFFIC\t%I64u/%I64u\t%I64u/%I64u",
traffic[TRAFFIC_TOTAL_OUT], traffic[TRAFFIC_TOTAL_IN],
traffic[TRAFFIC_COUNTED_OUT], traffic[TRAFFIC_COUNTED_IN]);
log_msg(msg, MSGTYPE_ALLOW);
}
// disconnect from driver
if (g_device != INVALID_HANDLE_VALUE)
{
HANDLE old_h = g_device;
g_device = INVALID_HANDLE_VALUE;
CancelIo(old_h);
CloseHandle(old_h);
}
// stop dispatcher thread
if (g_exit_event != NULL)
SetEvent(g_exit_event);
if (g_dispatcher != NULL)
{
WaitForSingleObject(g_dispatcher, INFINITE);
g_dispatcher = NULL;
}
// close logfile
if (g_logfile != NULL)
{
log_msg("STOP", MSGTYPE_ALLOW);
fprintf(g_logfile, "--- end ---\n");
fclose(g_logfile);
g_logfile = NULL;
}
if (g_exit_event != NULL)
CloseHandle(g_exit_event);
if (g_event != NULL)
CloseHandle(g_event);
if (g_disp_buf != NULL)
{
free(g_disp_buf);
g_disp_buf = NULL;
}
}
void wait(void)
{
if (g_exit_event != NULL)
WaitForSingleObject(g_exit_event, INFINITE);
}
/* output functions */
void error(const char *fmt, ...)
{
va_list ap;
char message[1024];
// prepare message
va_start(ap, fmt);
if (_vsnprintf(message, sizeof(message), fmt, ap) == -1)
message[sizeof(message) - 1] = '\0';
va_end(ap);
// got message
log_msg(message, MSGTYPE_ERROR);
}
void winerr(const char *fn)
{
char *win_msg = NULL;
DWORD code = GetLastError();
if (code == 0)
error("WINERR\t%s:", fn);
else {
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,NULL,code,
MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPTSTR)&win_msg,0,NULL);
if (win_msg != NULL)
{
// kill \r\n
int len = strlen(win_msg);
if (len >= 1)
win_msg[len-1]=0;
if (len >= 2)
win_msg[len-2]=0;
error("WINERR\t%s: %s", fn, win_msg);
LocalFree(win_msg);
}
else
error("WINERR\t%s: %d (0x%x)", fn, code, code);
}
// save error code
SetLastError(code);
}
void liberr(const char *fn)
{
int code = errno;
if (code != 0)
error("LIBERR\t%s: %s", fn, strerror(code));
else
error("LIBERR\t%s:", fn);
}
/* dispatcher thread */
DWORD WINAPI dispatcher(LPVOID param)
{
char *config = (char *)param;
HANDLE handles[2];
DWORD i, n;
handles[0] = g_event;
handles[1] = g_exit_event;
for (;;){
if (!DeviceIoControl(g_device, IOCTL_CMD_GETREQUEST, NULL, 0,
g_disp_buf, DISP_BUF_SIZE, &n, NULL))
{
winerr("dispatcher: DeviceIoControl");
break;
}
if (n == 0)
{
DWORD wait;
// if working with log file flush it!
if (g_logfile != NULL)
fflush(g_logfile);
// wait for data
wait = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (wait == WAIT_OBJECT_0 + 1)
break;
else if (wait != WAIT_OBJECT_0)
{
winerr("dispatcher: WaitForSingleObject");
break;
}
continue;
}
for (i = 0; i < n;)
{
struct flt_request *request;
if (n - i < sizeof(*request))
break;
request = (struct flt_request *)(g_disp_buf + i);
dispatch_request(request);
i += request->struct_size;
}
}
if (g_device != INVALID_HANDLE_VALUE)
{
DWORD thread_id;
error("dispatcher: unexpected exit!");
// restart tdifw_svc
lib_CreateThread(NULL, 0, restart_thread, config, 0, &thread_id);
}
return 0;
}
DWORD WINAPI restart_thread(LPVOID param)
{
char *config = (char *)param;
error("restarting...");
stop();
start(config);
return 0;
}
/* log filter request from filter driver */
void dispatch_request(struct flt_request *request)
{
u_long from_ip, to_ip;
u_short from_port, to_port;
char msg[1024], pname_buf[MAX_PATH], addr_from[100], addr_to[100], *pname, uname[200];
if (request->log_skipped != 0)
{
if (_snprintf(msg, sizeof(msg), "SKIP\t%u", request->log_skipped) == -1)
msg[sizeof(msg) - 1] = '\0';
log_msg(msg, MSGTYPE_ERROR);
}
if (request->pid != (ULONG)-1)
{
if (request->pname == NULL)
{
// try to resolve pid to pname
if (get_pname_by_pid(request->pid, pname_buf + sizeof(DWORD), sizeof(pname_buf) - sizeof(DWORD)))
{
// send message to driver to send process name next time
DWORD n;
pname = pname_buf + sizeof(DWORD);
*(DWORD *)pname_buf = request->pid;
if (!DeviceIoControl(g_device, IOCTL_CMD_SETPNAME, pname_buf,
sizeof(DWORD) + strlen(pname) + 1,
NULL, 0, &n, NULL))
winerr("DeviceIoControl");
}
else {
error("PROCESS\tCan't resolve pid %u!", request->pid);
sprintf(pname_buf, "pid:%u", request->pid);
pname = pname_buf;
}
}
else
pname = (char *)&request[1];
}
else
pname = "";
if (request->sid_a != NULL)
{
SID_AND_ATTRIBUTES *sa;
char user[100], domain[100];
DWORD size1, size2;
SID_NAME_USE type;
if (request->pname != NULL)
{
char *buf = (char *)&request[1];
buf += strlen(buf) + 1;
sa = (SID_AND_ATTRIBUTES *)buf;
}
else
sa = (SID_AND_ATTRIBUTES *)&request[1];
// convert sid from relative pointer to absolute
sa->Sid = (PSID)((char *)sa + (ULONG)sa->Sid);
size1 = sizeof(user);
size2 = sizeof(domain);
if (LookupAccountSid(NULL, sa->Sid, user, &size1, domain, &size2, &type))
{
if (_snprintf(uname, sizeof(uname), "{%s\\%s}", domain, user) == -1)
uname[sizeof(uname) - 1] = '\0';
}
else
strcpy(uname, "{??\\??}"); // TODO: convert SID to string
}
else
uname[0] = '\0';
// check is it request type "TYPE_RESOLVE_PID"
if (request->type == TYPE_RESOLVE_PID)
{
if (_snprintf(msg, sizeof(msg), "PROCESS\t%u\t%s\t%s", request->pid, pname, uname) == -1)
msg[sizeof(msg) - 1] = '\0';
log_msg(msg, MSGTYPE_ALLOW);
}
else if (request->type == TYPE_LISTEN || request->type == TYPE_NOT_LISTEN)
{
// using from_ip & from_port as listen_ip & listen_port
from_ip = ((struct sockaddr_in *)&request->addr.from)->sin_addr.s_addr;
from_port = ntohs(((struct sockaddr_in *)&request->addr.from)->sin_port);
prepare_addr(addr_from, sizeof(addr_from), from_ip);
sprintf(addr_from + strlen(addr_from), ":%d", from_port);
if (_snprintf(msg, sizeof(msg),
"%s\tTCP\t%s\t%s\t%s",
(request->type == TYPE_LISTEN) ? "LISTEN" : "NOT_LISTEN",
addr_from, pname, uname) == -1)
msg[sizeof(msg) - 1] = '\0';
log_msg(msg, MSGTYPE_ALLOW);
}
else {
// prepare message
from_ip = ((struct sockaddr_in *)&request->addr.from)->sin_addr.s_addr;
from_port = ntohs(((struct sockaddr_in *)&request->addr.from)->sin_port);
to_ip = ((struct sockaddr_in *)&request->addr.to)->sin_addr.s_addr;
to_port = ntohs(((struct sockaddr_in *)&request->addr.to)->sin_port);
// prepare address "from" & "to"
if (from_ip == 0)
{
// try to route "to" addr to get "from"
from_ip = get_if_ip(to_ip);
}
prepare_addr(addr_from, sizeof(addr_from), from_ip);
if (to_ip == 0)
{
// some kind of "reverse route" :-)
to_ip = get_if_ip(from_ip);
}
prepare_addr(addr_to, sizeof(addr_to), to_ip);
// add ports if nonzero
if (from_port != 0)
sprintf(addr_from + strlen(addr_from), ":%d", from_port);
if (to_port != 0)
sprintf(addr_to + strlen(addr_to), ":%d", to_port);
if (request->result == FILTER_ALLOW || request->result == FILTER_DENY ||
request->result == FILTER_DISCONNECT)
{
// log it! (TDI message)
char tdi_msg[100 + RULE_ID_SIZE], size_str[64], *direction;
switch (request->result)
{
case FILTER_ALLOW:
strcpy(tdi_msg, "ALLOW");
break;
case FILTER_DENY:
strcpy(tdi_msg, "DENY");
break;
default:
strcpy(tdi_msg, "CLOSED");
}
if (request->result != FILTER_DISCONNECT)
{
int size;
size_str[0] = '\0';
switch (request->type)
{
case TYPE_CONNECT_CANCELED:
strcat(tdi_msg, "(CANCELED)");
break;
case TYPE_CONNECT_RESET:
strcat(tdi_msg, "(RESET)");
break;
case TYPE_CONNECT_TIMEOUT:
strcat(tdi_msg, "(TIMEOUT)");
break;
case TYPE_CONNECT_UNREACH:
strcat(tdi_msg, "(UNREACH)");
break;
case TYPE_CONNECT_ERROR:
sprintf(tdi_msg + strlen(tdi_msg), "(ERR:%x)", request->status);
break;
case TYPE_DATAGRAM:
size = (request->direction == DIRECTION_IN) ? request->log_bytes_in : request->log_bytes_out;
if (size != (ULONG)-1)
sprintf(size_str, "%u", size);
break;
}
strcat(tdi_msg, "\t[");
size = strlen(tdi_msg);
memcpy(tdi_msg + size, request->log_rule_id, RULE_ID_SIZE);
tdi_msg[size + RULE_ID_SIZE + 1] = '\0'; // string can be not zero-terminated
strcat(tdi_msg, "]");
}
else
sprintf(size_str, "%u/%u", request->log_bytes_out, request->log_bytes_in);
switch (request->direction)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -