phpipam / phpipam

phpipam development repository
https://phpipam.net
2.23k stars 733 forks source link

Orphan IP addresses #1526

Open poodad opened 7 years ago

poodad commented 7 years ago

I have discovered that I somehow have orphan IP addresses. I don't know how it happened, but I suspect that I had created subnets with auto discovery on, then deleted the subnet.

Via the API, I can search for the IP address by using the search by IP address method, and the returned subnet ID looks reasonable (32 in this case), but using the API to search for the subnet ID returns no result (presumably, this subnet was deleted at some point).

If I search for the IP address in the GUI, It is found, but shows the subnet as "0.0.0.0/", and if I try to delete it, the GUI says "Invalid subnet ID".

If I use the GUI to search for subnet "0.0.0.0/", no results are returned.

phpIPAM needs a tool to run through the IP addresses and delete ones that reference an invalid subnet ID.

Also, any idea of how I can find all of these bogus IP addresses? There does not appear to be a way to get all IP addresses via the API. I tried getting all sections, then getting the subnets in each section to build a list of valid subnets. Then I tried getting all IP addresses in the subnet IDs that were missing from that list. That did not return any IP addresses.

I really don't want to have to iterate over all of the possible IP addresses in all my subnets looking for ones that don't have valid subnet IDs. That would takes days to run.

poodad commented 7 years ago

I should have added that the orphans I've found were autodiscovered.

I suspect there is a race condition where if you delete a subnet while the autodiscovery process is running, the process can continue to create IP addresses in the now invalid subnet.

GaryAllan commented 7 years ago

Hello poodad,

You can remove ipaddresses that don't belong to a subnet using the MySQL query below....

DELETE FROM ipaddresses WHERE subnetId NOT IN (SELECT id FROM subnets);

This is more aggressive and will also delete IP addresses belonging to any subnet that has descendants.

DELETE FROM ipaddresses WHERE SubnetId NOT IN (SELECT subnets.id FROM subnets LEFT JOIN subnets AS child ON subnets.id = child.masterSubnetId WHERE child.id IS NULL);

Usual advice of backing up your MySQL database before making changes applies.

poodad commented 7 years ago

I was afraid to manipulate the database directly, so what I did was to write a perl program to read the id and subnetId from the ipaddresses table and delete any IP addresses (by id) that had an invalid subnetId via the API.

poodad commented 7 years ago

Looking at the code for the discovery script, I believe there is indeed a huge race condition. Once the script starts scanning a particular subnet, it WILL create the found IP addresses using the subnet's ID - even if the subnet has since been deleted.

The fix might be to check the validity of the subnet ID after discover completes, but before inserting the discovered IP addresses, and locking the database while actually adding rows to the ipaddress table.

Another fix could be to re-write the discovery script to use the API to insert the discovered IP addresses. Very inefficient, but a pretty easy fix.