可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Here I have a static reference the ranges I need to check:
private static List<string> Ip_Range = new List<string>()
{
"12.144.86.0/23",
"31.201.1.176/30",
"46.36.198.101/32",
"46.36.198.102/31",
"46.36.198.104/31",
"46.136.172.0/24",
"63.65.11.0/24",
"63.65.12.0/25",
"63.65.12.128/26",
"63.65.12.192/27",
"63.65.12.224/28",
"63.65.12.240/29",
"63.65.12.248/30",
"63.65.12.252/31",
"63.65.12.254/32",
"65.173.56.0/21",
"67.23.241.179/32",
"67.23.241.180/30",
"67.23.241.184/29",
"67.23.241.192/30",
"67.23.241.196/31",
"67.23.241.198/32",
"72.32.164.56/29",
"72.46.244.32/28",
"74.91.16.48/29",
"74.91.16.208/29",
"74.91.20.48/28",
"74.91.20.64/29",
"74.112.134.120/29",
"74.112.135.104/29",
"74.205.37.16/29",
"78.24.205.32/28",
"98.129.27.88/29",
"98.129.91.40/29",
"166.114.0.0/16",
"167.157.0.0/16",
"174.143.165.80/29",
"186.0.156.0/22",
"186.2.0.0/17",
"186.27.0.0/17",
"190.0.248.0/21",
"190.3.184.0/21"
};
Here's some pseudo code on how I see it working:
public static bool IpIsWithinRange(string ip) //Something like 127.0.0.1 or 184.56.26.35
{
IPAddress incomingIp = IPAddress.Parse(ip);
foreach (var subnet in Ip_Range)
{
IPAddress sub = IPAddress.Parse(subnet); ?????
if (incomingIp "is in" sub) ?
return true;
}
return false;
}
Any suggestions on how to code up this functionality?
回答1:
If you don't want/can't add another library (as the IPnetwork one) to your project and just need to deal with IPv4 CIDR ranges, here's a quick solution to your problem
// true if ipAddress falls inside the CIDR range, example
// bool result = IsInRange("10.50.30.7", "10.0.0.0/8");
private bool IsInRange(string ipAddress, string CIDRmask)
{
string[] parts = CIDRmask.Split('/');
int IP_addr = BitConverter.ToInt32(IPAddress.Parse(parts[0]).GetAddressBytes(), 0);
int CIDR_addr = BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0);
int CIDR_mask = IPAddress.HostToNetworkOrder(-1 << (32 - int.Parse(parts[1])));
return ((IP_addr & CIDR_mask) == (CIDR_addr & CIDR_mask));
}
the above will allow you to quickly check if a given IPv4 address falls inside a given CIDR range; notice that the above code is barebone, it's up to you to check if a given IP (string) and CIDR range are correct before feeding them to the function (you may just use the tryparse or whatever...)
回答2:
Decided to answer my own question so people can benefit. If it can be improved, please do!
I used the IPNetwork library and it worked out fantastically! Below is the code I used:
using System.Net;
public static class RedirectHelpers
{
public static bool IpIsWithinBoliviaRange(string ip)
{
IPAddress incomingIp = IPAddress.Parse(ip);
foreach (var subnet in Bolivia_Ip_Range)
{
IPNetwork network = IPNetwork.Parse(subnet);
if (IPNetwork.Contains(network, incomingIp))
return true;
}
return false;
}
private static List<string> Bolivia_Ip_Range = new List<string>()
{
"12.144.86.0/23",
"31.201.1.176/30",
"46.36.198.101/32",
"46.36.198.102/31",
"46.36.198.104/31",
"46.136.172.0/24",
"63.65.11.0/24",
"63.65.12.0/25",
"63.65.12.128/26",
"63.65.12.192/27",
"63.65.12.224/28",
"63.65.12.240/29",
"63.65.12.248/30",
"63.65.12.252/31",
"63.65.12.254/32",
"65.173.56.0/21",
"67.23.241.179/32",
"67.23.241.180/30",
"67.23.241.184/29",
"67.23.241.192/30",
"67.23.241.196/31",
"67.23.241.198/32",
"72.32.164.56/29",
"72.46.244.32/28",
"74.91.16.48/29",
"74.91.16.208/29",
"74.91.20.48/28",
"74.91.20.64/29",
"74.112.134.120/29",
"74.112.135.104/29",
"74.205.37.16/29",
"78.24.205.32/28",
"98.129.27.88/29",
"98.129.91.40/29",
"166.114.0.0/16",
"167.157.0.0/16",
"174.143.165.80/29",
"186.0.156.0/22",
"186.2.0.0/17",
"186.27.0.0/17",
"190.0.248.0/21",
"190.3.184.0/21",
"166.114.0.0/16",
"167.157.0.0/16",
"186.2.0.0/18",
"190.11.64.0/20",
"190.11.80.0/20",
"190.103.64.0/20",
"190.104.0.0/19",
"190.107.32.0/20",
"190.129.0.0/17",
"190.181.0.0/18",
"190.186.0.0/18",
"190.186.64.0/18",
"190.186.128.0/18",
"200.7.160.0/20",
"200.58.64.0/20",
"200.58.80.0/20",
"200.58.160.0/20",
"200.58.176.0/20",
"200.75.160.0/20",
"200.85.128.0/20",
"200.87.0.0/17",
"200.87.128.0/17",
"200.105.128.0/19",
"200.105.160.0/19",
"200.105.192.0/19",
"200.112.192.0/20",
"200.119.192.0/20",
"200.119.208.0/20",
"201.222.64.0/19",
"201.222.96.0/19"
};
}
回答3:
Luckily most of the work has already been done for you (so we don't have to). Check out the IPNetwork project. You'll parse all of your CIDR addresses with IPNetwork.Parse
. Then to see if a specific IPAddress
is in range just use IPNetwork.Contains
method.
I got bored so here's a method you can use to test whether an IP address is in range or not:
private Dictionary<string, IPNetwork> netCache = null;
public bool IsInRange(string ipAddress)
{
if (netCache == null)
netCache = Ip_Range.ToDictionary((keyItem) => keyItem, (valueItem) => IPNetwork.Parse(valueItem));
return netCache.Values.Any(net => IPNetwork.Contains(net, IPAddress.Parse(ipAddress)));
}
This is dependent on the Ip_Range
list from your question but translates them to IPNetwork
instances (missing sanity checks for brevity).
Usage:
List<string> addrList = new List<string> { "12.144.86.1", "10.254.6.172" };
addrList.ForEach(addr => Console.WriteLine("{0}: {1}", addr, IsInRange(addr)));
Test Output:
12.144.86.1: True
10.254.6.172: False
Of course there is still a lot that could (and probably should) be done with it, but this proves the concept.
回答4:
If you understand the CIDR notation, you can easily do the math in your parse method.
You basically know that an IPv4 address is 32bits long and that the CIDR notation means that the number of bits behind the "/" are the network address bits (ie the masked out bits), therefore the leftover bits are represent the number of hosts in the subnet.
From wikipedia article:
The number of addresses of a subnet defined by the mask or prefix can
be calculated as 2address size - prefix size, in which the address
size for IPv6 is 128 and 32 for IPv4. For example, in IPv4, a prefix
size of /29 gives: 232-29 = 23 = 8 addresses.
So you could (no I'm not going to work out the details for you) convert your addresses into binary and do the binary AND with the given mask (also in binary form), then you have the network address part of the IP address left, which should match with whatever address you're checking against to see if it's in a particular subnet.
回答5:
For start, you should use that:
IPNetwork ipnetwork = IPNetwork.Parse("192.168.168.100/29");
Console.WriteLine("CIDR: {0}", ipnetwork.Cidr);
Output
CIDR: 29
回答6:
public static bool IpIsInRange(string subnet, string ip)
{
var splitSubnet = subnet.Split('/');
var maskBits = 32 - int.Parse(splitSubnet[1]);
if (maskBits == 32)
{
return true;
}
var subnetIp = BitConverter.ToInt32(IPAddress.Parse(splitSubnet[0]).GetAddressBytes().Reverse().ToArray(), 0) >> maskBits << maskBits;
var clientIp = BitConverter.ToInt32(IPAddress.Parse(ip).GetAddressBytes().Reverse().ToArray(), 0) >> maskBits << maskBits;
return subnetIp == clientIp;
}
回答7:
I use the below method to determine whether a given IP Address is a public one or private/internal:
private bool IsInternalIpAddress(string ipAddress)
{
// notes: http://whatismyipaddress.com/private-ip
var internalIpRanges = Enumerable
.Range(16, 31)
.Select(i => "172.{0}.".FormatWith(i))
.Concat(new[] {"192.168.", "10.", "127."})
.ToArray();
return ipAddress.StartsWith(internalIpRanges);
}