📄 tdifw_svc.c
字号:
{
case DIRECTION_IN:
direction = "IN";
break;
case DIRECTION_OUT:
direction = "OUT";
break;
case DIRECTION_ANY:
direction = "*";
break;
default:
direction = "?";
}
if (_snprintf(msg, sizeof(msg),
"%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s",
tdi_msg,
(request->proto == IPPROTO_TCP) ? "TCP" :
(request->proto == IPPROTO_UDP ? "UDP" : "RawIP"),
direction,
addr_from, addr_to, size_str, pname, uname) == -1)
msg[sizeof(msg) - 1] = '\0';
// sound it!
if (request->result == FILTER_DENY)
{
// TODO: try to sound it by voice of user!
if (request->direction == DIRECTION_IN && wave_deny_in[0] != '\0')
PlaySound(wave_deny_in, NULL, SND_FILENAME | SND_ASYNC);
if (request->direction == DIRECTION_OUT && wave_deny_out[0] != '\0')
PlaySound(wave_deny_out, NULL, SND_FILENAME | SND_ASYNC);
}
log_msg(msg, request->result == FILTER_ALLOW ? MSGTYPE_ALLOW : MSGTYPE_DENY);
}
else if (request->result == FILTER_PACKET_LOG || request->result == FILTER_PACKET_BAD)
{
char flags[50], proto[50];
// prepare TCP flags or ICMP type
if (request->result == FILTER_PACKET_LOG)
{
if (request->proto == IPPROTO_TCP)
{
UCHAR th_flags = request->packet.tcp_flags;
flags[0] = (th_flags & TH_FIN) ? 'F' : '-';
flags[1] = (th_flags & TH_SYN) ? 'S' : '-';
flags[2] = (th_flags & TH_RST) ? 'R' : '-';
flags[3] = (th_flags & TH_PUSH) ? 'P' : '-';
flags[4] = (th_flags & TH_ACK) ? 'A' : '-';
flags[5] = (th_flags & TH_URG) ? 'U' : '-';
flags[6] = '\0';
}
else if (request->proto == IPPROTO_ICMP)
sprintf(flags, "%d.%d", request->packet.icmp_type, request->packet.icmp_code);
else
flags[0] = '\0';
}
else
flags[0] = '\0';
switch (request->proto)
{
case IPPROTO_TCP:
if (request->packet.tcp_state > TCP_STATE_NONE &&
request->packet.tcp_state < TCP_STATE_MAX)
sprintf(proto, "TCP(%s)", g_tcp_states[request->packet.tcp_state]);
else
strcpy(proto, "TCP");
break;
case IPPROTO_UDP:
strcpy(proto, "UDP");
break;
case IPPROTO_ICMP:
strcpy(proto, "ICMP");
break;
default:
sprintf(proto, "%d", request->proto);
}
// log it! (packet filter message)
if (_snprintf(msg, sizeof(msg),
"%s\t%s\t%s\t%s\t%s\t%u\t%s",
(request->result == FILTER_PACKET_LOG) ? "PACKET" : "BAD_PACKET",
proto,
(request->direction == DIRECTION_IN) ? "IN" : "OUT",
addr_from, addr_to,
(request->direction == DIRECTION_IN) ? request->log_bytes_in : request->log_bytes_out,
flags) == -1)
msg[sizeof(msg) - 1] = '\0';
log_msg(msg, request->result == FILTER_PACKET_LOG ? MSGTYPE_ALLOW : MSGTYPE_DENY);
}
}
}
/*
* write message to console, log file or probably to eventlog
* don't call any error functions! avoid infinite recurse.
*/
void log_msg(const char *msg, int type)
{
static int file_day = 0; // for midnight checking
static ULONG event_num = 1; // number of event in log file
// if working in console mode write message to console
if (g_console)
{
if (type == MSGTYPE_ERROR)
fprintf(stderr, "%s\n", msg);
else
printf("%s\n", msg);
}
// write to eventlog if filter is set
if ((type == MSGTYPE_ALLOW && g_eventlog_allow) ||
(type == MSGTYPE_DENY && g_eventlog_deny) ||
(type == MSGTYPE_ERROR && g_eventlog_error))
{
HANDLE hEventSource;
const char *strings;
// write message to event log
// Use event logging to log the error.
//
hEventSource = RegisterEventSource(NULL, "tdifw_svc");
if (hEventSource != NULL)
{
WORD event_type;
strings = msg; // write message without timestamp
event_type = (type == MSGTYPE_ALLOW) ? EVENTLOG_AUDIT_SUCCESS :
(type == MSGTYPE_DENY ? EVENTLOG_AUDIT_FAILURE : EVENTLOG_ERROR_TYPE);
if (!ReportEvent(hEventSource, // handle of event source
event_type,
0, // event category
MSG, // event ID
NULL, // current user's SID
1, // strings in lpszStrings
0, // no bytes of raw data
&strings, // array of error strings
NULL))
{ // no raw data
#ifdef _DEBUG
MessageBeep(0);
OutputDebugString("log_msg: ReportEvent\n");
#endif
}
DeregisterEventSource(hEventSource);
}
}
else {
// write message to log
time_t tv;
struct tm *tm;
char tm_msg[1024];
time(&tv);
tm = localtime(&tv);
if (tm == NULL)
{
#ifdef _DEBUG
MessageBeep(0);
OutputDebugString("log_msg: localtime\n");
#endif
return;
}
if (g_logfile == NULL || tm->tm_mday != file_day)
{
char fname[MAX_PATH];
if (g_logfile != NULL)
{
// wow! we're working at midnight! change log file!
fprintf(g_logfile, "--- midnight ---\n");
fclose(g_logfile);
g_logfile = NULL;
}
file_day = tm->tm_mday;
// open logfile
if (_snprintf(fname, sizeof(fname),
"%s\\system32\\LogFiles\\tdifw\\%04d%02d%02d.log",
getenv("SystemRoot"),
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday) == -1)
{
#ifdef _DEBUG
MessageBeep(0);
OutputDebugString("log_msg: _snprintf overflow!\n");
#endif
return;
}
g_logfile = fopen(fname, "a");
if (g_logfile == NULL)
{
#ifdef _DEBUG
MessageBeep(0);
OutputDebugString("log_msg: fopen error!\n");
#endif
return;
}
fprintf(g_logfile, "--- begin ---\n");
}
if (_snprintf(tm_msg, sizeof(tm_msg),
"%010u %02d:%02d:%02d\t%s",
event_num++, tm->tm_hour, tm->tm_min, tm->tm_sec, msg) == -1)
tm_msg[sizeof(tm_msg) - 1] = '\0';
// write it to log file
fprintf(g_logfile, "%s\n", tm_msg);
fflush(g_logfile);
}
}
#define MAX_SECTION_SIZE (16 * 1024)
BOOL load_config(const char *config)
{
char *section = NULL, *p;
DWORD n, pids[100];
BOOL result = FALSE;
int line, chain, i;
if (!read_config(config))
return FALSE;
// save config to global variable (for get_host_by_name)
g_config_file = config;
// load information about users
if (!load_users(config))
{
error("start: Fatal error! Can't load users information!\n");
goto done;
}
// parse & add rules default and process-related
section = (char *)malloc(MAX_SECTION_SIZE);
if (section == NULL)
{
liberr("malloc");
goto done;
}
GetPrivateProfileSection("_main_", section, MAX_SECTION_SIZE, config);
// get lines
chain = 0;
for (p = section, line = 1; *p != '\0'; p += strlen(p) + 1, line++)
{
char *p2;
if (*p == ';' || *p == '#')
continue; // comment
p2 = strchr(p, '=');
if (p2 == NULL)
{
error("%s:[_main_]:%d: invalid line format (no '=' character)", config, line);
continue;
}
if (chain >= MAX_CHAINS_COUNT)
{
error("%s:[_main_]:%d: too many rules lines!", config, line);
break;
}
*p2 = '\0'; // temporary kill '='
add_rules_name(p, config, chain);
*p2 = '='; // recover '=' to make strlen(p) works right
chain++;
}
// try to get names for existing processes
if (pEnumProcesses != NULL && pEnumProcesses(pids, sizeof(pids), &n))
{
DWORD i;
n /= sizeof(DWORD);
for (i = 0; i < n; i++)
{
char pname[MAX_PATH];
if (get_pname_by_pid(pids[i], pname + sizeof(DWORD), sizeof(pname) - sizeof(DWORD)))
{
// send information to driver about pid and pname
DWORD nn;
*(DWORD *)pname = pids[i];
if (!DeviceIoControl(g_device, IOCTL_CMD_SETPNAME, pname,
sizeof(DWORD) + strlen(pname + sizeof(DWORD)) + 1,
NULL, 0, &nn, NULL))
winerr("DeviceIoControl");
}
}
}
// activate all chains!
for (i = 0; i < chain; i++)
{
// activate chain #i
if (!DeviceIoControl(g_device, IOCTL_CMD_ACTIVATECHAIN, &i, sizeof(i),
NULL, 0, &n, NULL))
winerr("start: DeviceIoControl");
}
result = TRUE;
done:
free(section);
return result;
}
BOOL read_config(const char *config)
{
static char config_name[] = "_config_";
static char signature_name[] = "_signature_";
static char signature_value[] = "$tdi_fw$";
char buf[100];
// first, check config file signature
GetPrivateProfileString(signature_name, signature_name, "", buf, sizeof(buf), config);
if (strcmp(buf, signature_value) != 0)
{
error("\"%s\": invalid configuration file", config);
return FALSE;
}
// get g_eventlog_xxx values
g_eventlog_allow = GetPrivateProfileInt(config_name, "eventlog_allow", FALSE, config);
g_eventlog_deny = GetPrivateProfileInt(config_name, "eventlog_deny", FALSE, config);
g_eventlog_error = GetPrivateProfileInt(config_name, "eventlog_error", FALSE, config);
// read wave_deny_in/out values
GetPrivateProfileString(config_name, "wave_deny_in", "", wave_deny_in, sizeof(wave_deny_in), config);
GetPrivateProfileString(config_name, "wave_deny_out", "", wave_deny_out, sizeof(wave_deny_out), config);
return TRUE;
}
BOOL add_rules_name(const char *main_name, const char *config, int chain)
{
char buf[1024], *p, *p2, *section = NULL;
BOOL result = FALSE;
DWORD n;
section = (char *)malloc(MAX_SECTION_SIZE);
if (section == NULL)
{
liberr("malloc");
goto done;
}
/* 1. get ruleset string */
GetPrivateProfileString("_main_", main_name, "", buf, sizeof(buf), config);
if (*buf == '\0')
goto done; // no rules
// reset all rules for chain
if (!DeviceIoControl(g_device, IOCTL_CMD_CLEARCHAIN, &chain, sizeof(chain),
NULL, 0, &n, NULL))
{
winerr("DeviceIoControl");
goto done;
}
if (chain != 0)
{
// set chain name
int len = sizeof(int) + MAX_PATH;
char *data = (char *)malloc(len);
if (data == NULL)
{
liberr("malloc");
goto done;
}
*(int *)data = chain;
// try to extract environment variables from p to main_name
ExpandEnvironmentStrings(main_name, data + sizeof(int), MAX_PATH);
len = sizeof(int) + strlen(data + sizeof(int)) + 1;
if (!DeviceIoControl(g_device, IOCTL_CMD_SETCHAINPNAME, data, len,
NULL, 0, &n, NULL))
{
winerr("DeviceIoControl");
free(data);
goto done;
}
free(data);
}
/* 2. for each word in main_name string */
p = buf;
while (p != NULL)
{
p2 = strchr(p, ' ');
if (p2 != NULL)
{
while (*p2 == ' ')
*(p2++) = '\0';
}
if (*p != '\0')
{
// get section by name in p
GetPrivateProfileSection(p, section, MAX_SECTION_SIZE, config);
if (*section == '\0')
error("\"%s\": unexistant or empty section %s", config, p);
else
add_rules(config, section, p, chain);
}
p = p2;
}
result = TRUE;
done:
free(section);
return result;
}
void add_rules(const char *config, char *buf, const char *name, int chain)
{
char *p, *p2;
int n_str;
DWORD n;
UCHAR sid_mask[MAX_SIDS_COUNT / 8];
get_sid_mask(config, name, sid_mask);
for (p = buf, n_str = 1; *p != '\0'; p = p2, n_str++)
{
struct flt_rule rule;
char num[10];
p2 = p + strlen(p) + 1;
if (*buf == ';' || *buf == '\0')
continue; // empty line or comment
memset(&rule, 0, sizeof(rule));
// parse it!
if (!parse_rule(p, &rule))
{
error("Error in line #%d of section [%s]", n_str, name);
continue;
}
// set chain
rule.chain = chain;
// set SID mask
memcpy(rule.sid_mask, sid_mask, sizeof(rule.sid_mask));
if (rule.rule_id[0] == '\0')
{
// set default rule name: name of section + n_str
strncpy(rule.rule_id, name, RULE_ID_SIZE); // string can be not zero-terminated
sprintf(num, ":%d", n_str);
if (strlen(name) + strlen(num) < RULE_ID_SIZE)
memcpy(rule.rule_id + strlen(name), num, strlen(num)); // string can be not zero-terminated
else
memcpy(rule.rule_id + RULE_ID_SIZE - strlen(num), num, strlen(num));
}
// append rule
if (!DeviceIoControl(g_device, IOCTL_CMD_APPENDRULE, &rule, sizeof(rule),
NULL, 0, &n, NULL))
{
winerr("start: DeviceIoControl");
break;
}
}
}
BOOL get_pname_by_pid(u_long pid, char *buf, int buf_size)
{
BOOL result;
HANDLE h_process;
HMODULE h_module = NULL;
DWORD n;
if (g_psapi == NULL)
return FALSE; // failed to load psapi.dll
// try to resolve pid to pname
h_process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (h_process != NULL)
pEnumProcessModules(h_process, &h_module, sizeof(h_module), &n);
// on error write pid
if (h_module == NULL ||
pGetModuleFileNameEx(h_process, h_module, buf, buf_size) == 0)
{
// for "System" process last error value is:
// * ERROR_PARTIAL_COPY (on 2k)
// * ERROR_NOACCESS (on NT4)
// ??? on other (TODO: think about another way)
if (GetLastError() == ERROR_PARTIAL_COPY ||
GetLastError() == ERROR_NOACCESS)
{
strncpy(buf, "System", buf_size);
buf[buf_size - 1] = '\0';
result = TRUE;
}
else {
*buf = '\0';
result = FALSE;
}
}
else {
if (strchr(buf, '~') != NULL)
{ // XXX is it a right way?
// try to convert long name to short name
char long_name[MAX_PATH];
my_GetLongPathName(buf, long_name, sizeof(long_name));
strncpy(buf, long_name, buf_size - 1);
buf[buf_size - 1] = '\0';
}
result = TRUE;
}
if (h_process != NULL)
CloseHandle(h_process);
return result;
}
void prepare_addr(char *buf, int size, u_long addr)
{
// XXX do we need resolving?
strcpy(buf, inet_ntoa(*(struct in_addr *)&addr));
}
ULONG get_host_by_name(const char *hostname, char *net_mask)
{
// resolve address using config file (DNS way is insecure)
char addr[100], *p;
GetPrivateProfileString("_hosts_", hostname, "", addr, sizeof(addr), g_config_file);
if (*addr == '\0')
return INADDR_NONE;
p = strchr(addr, '/');
if (p != NULL)
{
// got net_mask!
*(p++) = '\0';
// max size is 2 characters! (/xx)
strncpy(net_mask, p, 2);
net_mask[2] = '\0';
}
else
*net_mask = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -