У меня есть большой динамический список IP-адресов, их масок подсети и заданный набор подсетей. Мне нужен код, чтобы определить, в какой подсети находится каждый адрес. Я держу это довольно расплывчатым, потому что я открыт для многих различных решений. У кого-нибудь есть код на С#, который может сделать что-то подобное? Спасибо!
C#. Как определить, какие IP-адреса в списке принадлежат определенной подсети?
Ответы (3)
Во-первых, вам нужен код для маскировки адреса в его подсети:
public IPAddress ApplyMask(IPAddress address, IPAddress mask) {
byte[] addressBytes = address.GetAddressBytes();
byte[] maskBytes = mask.GetAddressBytes();
var appliedMaskBytes =
addressBytes.Zip(
maskBytes,
(addressByte, maskByte) => (byte)(addressByte & maskByte)
)
.ToArray();
return new IPAddress(appliedMaskBytes);
}
Затем, если у вас есть Dictionary<IPAddress, IPAddress>
от IP-адреса до его маски:
IDictionary<IPAddress, IPAddress> maskDictionary;
var masked = ipAddresses
.Select(ipAddress =>
new { IPAddress = ipAddress,
Subnet = ApplyMask(
ipAddress,
maskDictionary[ipAddress]
)
}
)
.GroupBy(x => x.Subnet);
Теперь у вас есть список адресов по подсети. Действуйте соответственно.
(Примечание: у меня нет под рукой компилятора. Извините за мелкие ошибки компилятора.)
{192.168.0.0, 255.255.255.0}
это не то же самое, что {192.168.0.0, 255.255.0.0}
- согласно этой реализации это так.
- person Jonathan Dickinson; 13.09.2011
System.Linq
.
- person jason; 13.09.2011
Вам не нужен список подсетей - их можно вывести. Вы можете сделать это с помощью побитовой математики:
// Key is {Subnet, Subnet Mask}.
// Value is list of IPs in that range.
public static IDictionary<Tuple<IPAddress, IPAddress>, ISet<IPAddress>> AllocateToSubnets(IEnumerable<Tuple<IPAddress, IPAddress>> ips)
{
var dic = new Dictionary<Tuple<IPAddress, IPAddress>, ISet<IPAddress>>();
foreach (var item in ips)
{
var subnet = Tuple.Create(GetSubnetAddress(item.Item1, item.Item2), item.Item2);
ISet<IPAddress> set;
if (!dic.TryGetValue(subnet, out set))
dic.Add(subnet, set = new HashSet<IPAddress>());
if (!set.Add(item.Item1))
{
// Throw an error if you are looking for duplicates.
}
}
return dic;
}
private static IPAddress GetSubnetAddress(IPAddress address, IPAddress mask)
{
var b1 = address.GetAddressBytes();
var b2 = mask.GetAddressBytes();
if (b1.Length != b2.Length)
throw new InvalidOperationException("IPAddress and its mask do not share the same family.");
for (var i = 0; i < b1.Length; i++)
b1[i] &= b2[i];
return new IPAddress(b1);
}
Тестовый код:
var ips = new[]
{
Tuple.Create(IPAddress.Parse("192.168.0.1"), IPAddress.Parse("255.255.255.0")),
Tuple.Create(IPAddress.Parse("192.168.0.1"), IPAddress.Parse("255.255.0.0")),
Tuple.Create(IPAddress.Parse("192.168.0.2"), IPAddress.Parse("255.255.255.0")),
Tuple.Create(IPAddress.Parse("192.168.0.10"), IPAddress.Parse("255.255.255.0")),
Tuple.Create(IPAddress.Parse("192.168.0.10"), IPAddress.Parse("255.255.0.0")),
Tuple.Create(IPAddress.Parse("10.0.0.1"), IPAddress.Parse("255.255.255.0")),
Tuple.Create(IPAddress.Parse("10.1.0.1"), IPAddress.Parse("255.255.0.0")),
Tuple.Create(IPAddress.Parse("10.0.0.2"), IPAddress.Parse("255.255.255.0")),
Tuple.Create(IPAddress.Parse("10.1.0.10"), IPAddress.Parse("255.255.255.0")),
Tuple.Create(IPAddress.Parse("10.1.0.10"), IPAddress.Parse("255.255.0.0")),
};
var subnets = AllocateToSubnets(ips);
Это зависит от того, что для определения вашей подсети имеет. Если это диапазон IP-адресов, который вы можете использовать: Самый простой способ проверить IP-адрес по диапазону значений с помощью c#
Если это маска, вы можете использовать ip&(~mask)
для получения нижнего значения и ip|(~mask)
для получения диапазона и действовать, как указано выше.
Если подсеть указана с количеством битов, которые имеет сетевая маска, вы можете рассчитать: mask=~(UInt32.MaxValue>>n)
и использовать действуйте, как указано выше.
Если вы хотите узнать сетевую маску для данного IP, то я понятия не имею. Про IPv6 тоже не знаю.