// Spludlow Software
// Copyright © Samuel P. Ludlow 2020 All Rights Reserved
// Distributed under the terms of the GNU General Public License version 3
// Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
// https://www.spludlow.co.uk/LICENCE.TXT
// The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission
// v1.14
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetFwTypeLib; // C:\Windows\System32\FirewallAPI.dll
using System.IO;
using System.Data;
namespace Spludlow.Net
{
///
/// Some methods for setting an IP block list in Windows Firewall needs runing as admin (Make the CallText on the Spludlow Call page and run with Spludlow-Process.exe)
/// Also method for getting Audit Failure IPs out of the Security Event Log
///
public class Firewall
{
private static string _BlockRuleName = "Spludlow IP Block";
///
/// Configure Windows Firewall to block all incoming connections from specified IP
/// Creates rule if not exists (first time)
/// Takes care of duplicates and sorts the list
///
public static void BlockIP(string ipAddress)
{
BlockIP(new string[] { ipAddress });
}
public static void BlockIP(string[] ipAddresses)
{
INetFwPolicy2 policy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
INetFwRule2 rule = GetRule(policy, _BlockRuleName);
if (rule == null)
{
rule = (INetFwRule2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule"));
rule.Name = _BlockRuleName;
rule.Description = "";
rule.Action = NET_FW_ACTION_.NET_FW_ACTION_BLOCK;
rule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
rule.Enabled = true;
List ips = new List(ipAddresses);
ips.Sort();
rule.RemoteAddresses = MakeAddresses(ips);
policy.Rules.Add(rule);
}
else
{
List ips = RemoteAddresses(rule);
foreach (string ip in ipAddresses)
{
if (ips.Contains(ip) == false)
ips.Add(ip);
}
ips.Sort();
rule.RemoteAddresses = MakeAddresses(ips);
}
}
public static string[] ListBlockedIP()
{
INetFwPolicy2 policy = (INetFwPolicy2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
INetFwRule2 rule = GetRule(policy, _BlockRuleName);
if (rule == null)
return new string[0];
return RemoteAddresses(rule).ToArray();
}
private static INetFwRule2 GetRule(INetFwPolicy2 policy, string name)
{
try
{
return (INetFwRule2)policy.Rules.Item(_BlockRuleName);
}
catch (FileNotFoundException)
{
return null;
}
}
private static List RemoteAddresses(INetFwRule2 rule)
{
List ips = new List();
string[] parts = Spludlow.Text.Split(rule.RemoteAddresses, ',', true, false);
foreach (string part in parts)
{
string ip = part.Substring(0, part.IndexOf("/"));
if (ips.Contains(ip) == false)
ips.Add(ip);
}
ips.Sort();
return ips;
}
private static string MakeAddresses(List ips)
{
StringBuilder remote = new StringBuilder();
foreach (string ip in ips)
{
if (remote.Length > 0)
remote.Append(",");
remote.Append(ip);
remote.Append("/255.255.255.255");
}
return remote.ToString();
}
///
/// Run this against an XML Event Log export then check the Report in Spludlow Logs to get IP list
///
public static void ReportSecurityEventLogIPs(string xmlFilename, bool reportCountry)
{
DataTable table = ProcessEventLogsExport(xmlFilename);
DataTable resultTable = Spludlow.Data.TextTable.ReadText(new string[]
{
"Event_Id SystemTime System_EventID TargetUserName IpAddress",
"Int32 DateTime String String String",
});
foreach (DataRow row in table.Rows)
{
string eventId = (string)row["System_EventID"];
if (eventId != "4625")
continue;
string ip = (string)row["IpAddress"];
if (ip == "-")
continue;
resultTable.ImportRow(row);
}
resultTable = Spludlow.Data.ADO.CountOccurrence(resultTable, "IpAddress");
if (reportCountry == true)
{
resultTable.Columns.Add("Country", typeof(string));
foreach (DataRow row in resultTable.Rows)
row["Country"] = Spludlow.Net.IpWhoIs.CountryCode((string)row["IpAddress"]);
}
Spludlow.Log.Report("ProcessEventLogsExport", resultTable);
}
///
/// Put the exported XML into a single table
///
public static DataTable ProcessEventLogsExport(string xmlFilename)
{
// Process into tables
DataSet dataSet = Spludlow.Data.XML.ConvertRelational(xmlFilename, "Events");
// Result Table
DataTable table = new DataTable();
table.Columns.Add("Event_Id", typeof(int));
table.Columns.Add("SystemTime", typeof(DateTime));
// Add all system columns
foreach (DataColumn column in dataSet.Tables["System"].Columns)
{
if (column.ColumnName.EndsWith("_Id") == false)
table.Columns.Add("System_" + column.ColumnName, column.DataType);
}
// Add all data name columns
HashSet dataColumns = new HashSet();
foreach (DataRow row in dataSet.Tables["Data"].Rows)
{
string name = (string)row["Name"];
if (dataColumns.Contains(name) == false)
dataColumns.Add(name);
}
foreach (string name in dataColumns)
table.Columns.Add(name, typeof(string));
// Each event
foreach (DataRow EventRow in dataSet.Tables["Event"].Rows)
{
int Event_Id = (int)EventRow["Event_Id"];
// Find resolver ID
DataRow EventDataRow = FindRow(dataSet.Tables["EventData"], "Event_Id = " + Event_Id, true);
if (EventDataRow == null)
continue;
int EventData_Id = (int)EventDataRow["EventData_Id"];
// New Result row
DataRow row = table.NewRow();
row["Event_Id"] = Event_Id;
// Add info from System table
DataRow SystemRow = FindRow(dataSet.Tables["System"], "Event_Id = " + Event_Id, false);
foreach (DataColumn column in dataSet.Tables["System"].Columns)
{
if (table.Columns.Contains("System_" + column.ColumnName) == true)
row["System_" + column.ColumnName] = SystemRow[column.ColumnName];
}
int System_Id = (int)SystemRow["System_Id"];
// Get the time
DataRow TimeCreatedRow = FindRow(dataSet.Tables["TimeCreated"], "System_Id = " + System_Id, false);
row["SystemTime"] = DateTime.Parse((string)TimeCreatedRow["SystemTime"]);
// Add the data
foreach (DataRow DataRow in dataSet.Tables["Data"].Select("EventData_Id = " + EventData_Id))
{
if (DataRow.IsNull("DataValue") == false)
row[(string)DataRow["Name"]] = (string)DataRow["DataValue"];
}
table.Rows.Add(row);
}
return table;
}
private static DataRow FindRow(DataTable table, string filter, bool dontThrow)
{
DataRow[] rows = table.Select(filter);
if (rows.Length == 1)
return rows[0];
if (dontThrow == true && rows.Length == 0)
return null;
throw new ApplicationException("FindRow did not find one row: " + table.TableName + ", " + filter + ", " + rows.Length);
}
}
}