Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: IPNetwork Subtract #56

Open
HunterMitchell opened this issue Mar 29, 2019 · 10 comments
Open

Feature request: IPNetwork Subtract #56

HunterMitchell opened this issue Mar 29, 2019 · 10 comments

Comments

@HunterMitchell
Copy link

Looking at the source code, I see a method called: TrySubstractNetwork. I attempted to use a slightly modified version of this function and it was extremely slow.

I am trying to take two lists IncludedRanages and ExcludedRanges and have something consolidate adjacent and overlapping ranges/networks. Is this something easily added?

@HunterMitchell HunterMitchell changed the title Feature request: IPNetwork Difference Feature request: IPNetwork Subtract Mar 29, 2019
@lduchosal
Copy link
Owner

TrySubstractNetwork is really slow, we need to find a fast algorithm to substract two big subnets.

@fravelgue
Copy link

Not sure, it's same requirement. But I'm using RangeTree [1] to store ranges of IPs, and searching for IPs in it.
[1] https://github.com/mbuchetics/RangeTree

@lduchosal
Copy link
Owner

Thanks for pointing this out. I'll have a look when time permits.

@sakib1361
Copy link

Rather than trying to subtract ip address via range, I found that adding subnet via binary elimination might be faster. The idea is to split network into two until all the split networks are free of the subtract target. These subnets can be farther split to subtract multiple networks. Finally the split parts free from subtract networks can be joined together.
A sample has been shown here. Currently it fits my project needs. Not sure it is fully correct though. Dont like the idea of recursion. If I find a better idea, will update the code.
https://github.com/sakib1361/IPTest

@agowa
Copy link

agowa commented Aug 19, 2020

I don't know why one wants to subtract IP addresses, but it could easily be done using something like this:

#powershell

$minuend = ([System.Net.IPAddress]"192.168.2.27").MapToIPv6()
$subtrahend = ([System.Net.IPAddress]"0.0.2.0").MapToIPv6()

$difference = [System.Net.IPAddress]([bigint]($minuend.GetAddressBytes()) - [bigint]($subtrahend.GetAddressBytes())).ToByteArray()

$displayAddress = ($difference.IsIPv4MappedToIPv6) ? $difference.MapToIPv4().IPAddressToString : $difference.IPAddressToString
Write-Host "Next usable ip is: $displayAddress"

@lduchosal
Copy link
Owner

substract

192.168.0.0/24 - 192.168.0.128/26 = [ 192.168.0.0/25 , 192.168.0.192/26 ]

How would you solve the following ?
0.0.0.0/0 - 10.0.0.1/32 =

@lduchosal
Copy link
Owner

0.0.0.0/0 - 10.0.0.1/32 = [

0.0.0.0/5,
8.0.0.0/7,
10.0.0.0/32,
10.0.0.2/31,
10.0.0.4/30,
10.0.0.8/29,
10.0.0.16/28,
10.0.0.32/27,
10.0.0.64/26,
10.0.0.128/25,
10.0.1.0/24,
10.0.2.0/23,
10.0.4.0/22,
10.0.8.0/21,
10.0.16.0/20,
10.0.32.0/19,
10.0.64.0/18,
10.0.128.0/17,
10.1.0.0/16,
10.2.0.0/15,
10.4.0.0/14,
10.8.0.0/13,
10.16.0.0/12,
10.32.0.0/11,
10.64.0.0/10,
10.128.0.0/9,
11.0.0.0/8,
12.0.0.0/6,
16.0.0.0/4,
32.0.0.0/3,
64.0.0.0/2,
128.0.0.0/1

]

@agowa
Copy link

agowa commented Aug 26, 2020

oh, you mean getting the symmetric difference of the address space and not to subtract the addresses (aka. there binary values) from each other.

Venn0110.svg

Than a more logical representation would be to take two lists of ip prefixes and return a list with the actual symmetrical difference.

@RobThree
Copy link

RobThree commented Sep 13, 2021

Rather than trying to subtract ip address via range, I found that adding subnet via binary elimination might be faster. The idea is to split network into two until all the split networks are free of the subtract target. These subnets can be farther split to subtract multiple networks. Finally the split parts free from subtract networks can be joined together.

Exactly. This is how it's supposed to be done and can be very fast since all you do is split recursively. I have implemented the algorithm here (disclaimer, stating the obvious: author here).

For an example:

var network = NetworkHelper.Parse("192.168.0.0/16");
var desired = NetworkHelper.Parse("192.168.10.16/28");
var result = network.Extract(desired);

// Result:
// 192.168.0.0/21
// 192.168.8.0/23
// 192.168.10.0/28
// 192.168.10.16/28
// 192.168.10.32/27
// 192.168.10.64/26
// 192.168.10.128/25
// 192.168.11.0/24
// 192.168.12.0/22
// 192.168.16.0/20
// 192.168.32.0/19
// 192.168.64.0/18
// 192.168.128.0/17

You can also pass "0.0.0.0/28" to 'extract' any /28 from the given network. Works with IPv6 as well. What may help is using a visual subnet calculator like this one (no affiliation) to help visualize the concept. @lduchosal's exampe would be done as:

var network = NetworkHelper.Parse("0.0.0.0/0");
var desired = NetworkHelper.Parse("10.0.0.1/32");

var result = network.Extract(desired);
var resulttext = string.Join("\n", result.Select(n => $"{n.Prefix}/{n.PrefixLength}"));

@lduchosal
Copy link
Owner

@RobThree thanks, I'll dig into your proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants