⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tdifw_svc.c

📁 开源的防火墙代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 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 + -