例如我们需要检查 “中国大陆”、“中国香港” 等地区的IP段,那么我们只需要在 Filter 对象实例之中往 “Addresses” Map 字典对象里面添加 IP+CIDR 格式的IP无间路由就可以,然后调用 Filter 对象实例提供的 IsDirect 函数,返回成功则代表当前检查IP地址是属于 Filter 上面配置的IP路由表内的段上子IP。
C#
namespace VEthernet
{
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using global::VEthernet.Core;
using global::VEthernet.Net.Routing;
public unsafe class Filter
{
public uint Index { get; set; } = uint.MaxValue;
public IDictionary<int, int> Ports { get; } = new ConcurrentDictionary<int, int>();
public IDictionary<string, int> Processes { get; } = new ConcurrentDictionary<string, int>();
public IDictionary<IPAddress, int> Addresses { get; } = new ConcurrentDictionary<IPAddress, int>();
public bool IsDirect(string address, int port)
{
bool b = IPAddress.TryParse(address, out IPAddress ip);
if (!b)
{
return false;
}
return this.IsDirect(ip, port);
}
public virtual bool IsDirect(IPAddress address, int port) => !this.FilterIPEP(address, port);
private bool FilterIPEP(IPAddress address, int port)
{
if (address == null)
{
return false;
}
if (port <= IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
{
return false;
}
if (address.AddressFamily != AddressFamily.InterNetwork)
{
if (this.Ports.ContainsKey(port))
{
return false;
}
if (this.Addresses.ContainsKey(address))
{
return false;
}
return true;
}
fixed (byte* p = address.GetAddressBytes())
{
return this.FilterByINetV4(address, p, port);
}
}
private bool FilterByINetV4(IPAddress address, byte* b, int port)
{
if (b != null)
{
byte k1 = b[0];
if (k1 == 0 || k1 == 10 || k1 == 127 || k1 >= 224)
{
return false;
}
byte k2 = b[1];
if ((k1 == 100 && (k2 >= 64 && k2 <= 127)) ||
(k1 == 169 && k2 == 254) ||
(k1 == 172 && (k2 >= 16 && k2 <= 31)) ||
(k1 == 192 && k2 == 168) ||
(k1 == 198 && (k2 >= 18 && k2 <= 19)) ||
(k1 == 198 && k2 == 100))
{
return false;
}
byte k3 = b[2];
if ((k1 == 192 && k2 == 0 && (k3 == 0 || k3 == 2)) ||
(k1 == 192 && k2 == 88 && k3 == 99) ||
(k1 == 198 && k2 == 51 && k3 == 100) ||
(k1 == 203 && k2 == 0 && k3 == 113))
{
return false;
}
}
if (this.Ports.ContainsKey(port))
{
return false;
}
if (this.Index != uint.MaxValue)
{
if (RouteTableManager.GetBestInterface(address, out uint dwIndex) == 0)
{
if (dwIndex != this.Index)
{
return false;
}
}
}
if (this.Addresses.Count > 0)
{
const int MAX_PREFIX = sizeof(short) << sizeof(int);
for (int cidr = MAX_PREFIX; cidr >= 0; cidr--)
{
uint mask = CheckSum.htonl(uint.MaxValue << (MAX_PREFIX - cidr));
uint addr = *(uint*)b & mask;
IPAddress daddr = new IPAddress(addr);
if (!this.Addresses.TryGetValue(daddr, out int prefix))
{
continue;
}
if (cidr >= prefix)
{
return false;
}
}
}
return true;
}
}
}
C/C++
static BOOL
PRXFilterAddressEP(ULONG address, INT port)
{
PA_Configuration* configuration = PA_Interactive_Current.GetConfiguration();
if (!configuration->EnabledAgent || !configuration->MasterProcessOL) {
return FALSE;
}
if (port <= 0 || port > 65535) {
return FALSE;
}
else { // 屏蔽保留地址段
BYTE k1 = ((BYTE*)&address)[0];
if (k1 == 0 || k1 == 10 || k1 == 127 || k1 >= 224) {
return FALSE;
}
BYTE k2 = ((BYTE*)&address)[1];
if ((k1 == 100 && (k2 >= 64 && k2 <= 127)) ||
(k1 == 169 && k2 == 254) ||
(k1 == 172 && (k2 >= 16 && k2 <= 31)) ||
(k1 == 192 && k2 == 168) ||
(k1 == 198 && (k2 >= 18 && k2 <= 19)) ||
(k1 == 198 && k2 == 100)) {
return FALSE;
}
BYTE k3 = ((BYTE*)&address)[2];
if ((k1 == 192 && k2 == 0 && (k3 == 0 || k3 == 2)) ||
(k1 == 192 && k2 == 88 && k3 == 99) ||
(k1 == 198 && k2 == 51 && k3 == 100) ||
(k1 == 203 && k2 == 0 && k3 == 113)) {
return FALSE;
}
}
if (configuration->RediectIfIndex != UINT_MAX) {
DWORD dwIndex;
if (GetBestInterface(address, &dwIndex) == NO_ERROR) {
if (dwIndex != configuration->RediectIfIndex) {
return FALSE;
}
}
}
PA_Interactive::SynchronizedScope scope(PA_Interactive_Current.GetSynchronizedObject());
{
if (configuration->FilterPortNumber.find(port) != configuration->FilterPortNumber.end()) {
return FALSE;
}
if (!configuration->FilterHostAddress.empty()) {
typedef std::hash_map<ULONG, BYTE> FilterHostAddressHashMap;
FilterHostAddressHashMap& addressMap = configuration->FilterHostAddress;
FilterHostAddressHashMap::iterator addressEndl = addressMap.end();
const int MAX_PREFIX = sizeof(short) << sizeof(int);
for (int cidr = MAX_PREFIX; cidr >= 0; cidr--) {
ULONG mask = htonl(ULONG_MAX << (MAX_PREFIX - cidr));
ULONG addr = address & mask;
FilterHostAddressHashMap::iterator addressTail = addressMap.find(addr);
if (addressTail == addressEndl) {
continue;
}
if (cidr >= addressTail->second) {
return FALSE;
}
}
}
}
return TRUE;
}