Description
When a device's last_ip (public IP) keeps changing back and forth between two (or more) public IPs that resolve to different geolocations, the user receives an "Estimated location updated" notification on every change, indefinitely. A device whose public IP oscillates (for example behind a load balancer, a dual-WAN setup, or a flapping CGNAT assignment) produces a continuous stream of notifications.
Steps to reproduce
- Enable the Estimated Location feature for an organization (WHOIS configured,
estimated_location_enabled = True).
- Have a device report
last_ip = A, where A resolves via WHOIS to location A. An estimated location is created ("created" notification).
- Device reports
last_ip = B, where B resolves to a different location B. Estimated location updates to B ("updated" notification).
- Device reports
last_ip = A again. Estimated location updates back to A ("updated" notification).
- Device continues flapping A -> B -> A -> B. A new "updated" notification is generated on every flap.
Expected behavior
A device oscillating between the same small set of IPs/locations should not generate an unbounded stream of "updated" notifications. Returning to a location the device recently had should be deduplicated or debounced.
Actual behavior
One estimated_location_info notification (level info, "updated successfully") is generated for every last_ip change that resolves to different coordinates, with no throttling.
Root cause analysis
Every existing dedup/throttle layer compares only the new WHOIS result against the device's currently stored estimated location. None of them track oscillation history or apply any time-based debounce, so an A -> B -> A -> B sequence satisfies the "something changed" guard on every flap:
whois_fetched_handler skips the task only when neither address nor coordinates changed in the WHOIS record. On a flap between different locations both change, so the task always runs. (openwisp_controller/geo/estimated_location/handlers.py:55-61)
- The update path in
_create_or_update_estimated_location builds update_fields by diffing the incoming WHOIS values against the stored Location. On A -> B -> A -> B the incoming coordinates always differ from what is stored, so update_fields is always non-empty and the notification fires. (openwisp_controller/geo/estimated_location/service.py:119-135)
- The cached-WHOIS path does not help: even when no external WHOIS call is made because the record is still fresh,
whois_lookup_skipped_handler still triggers the task, which reaches the same update path and notifies. (openwisp_controller/geo/estimated_location/handlers.py:66-81)
Note on test coverage
The existing test test_unchanged_whois_data_no_location_recreation (openwisp_controller/geo/estimated_location/tests/tests.py:692-731) only covers flapping to the same IP / identical WHOIS data, where update_fields is empty and no notification fires. The different-location flap case has no coverage.
Environment
- openwisp-controller: 1.3.0 alpha (development, commit 328af64)
- Estimated Location feature enabled with WHOIS configured
Description
When a device's
last_ip(public IP) keeps changing back and forth between two (or more) public IPs that resolve to different geolocations, the user receives an "Estimated location updated" notification on every change, indefinitely. A device whose public IP oscillates (for example behind a load balancer, a dual-WAN setup, or a flapping CGNAT assignment) produces a continuous stream of notifications.Steps to reproduce
estimated_location_enabled = True).last_ip = A, where A resolves via WHOIS to location A. An estimated location is created ("created" notification).last_ip = B, where B resolves to a different location B. Estimated location updates to B ("updated" notification).last_ip = Aagain. Estimated location updates back to A ("updated" notification).Expected behavior
A device oscillating between the same small set of IPs/locations should not generate an unbounded stream of "updated" notifications. Returning to a location the device recently had should be deduplicated or debounced.
Actual behavior
One
estimated_location_infonotification (levelinfo, "updated successfully") is generated for everylast_ipchange that resolves to different coordinates, with no throttling.Root cause analysis
Every existing dedup/throttle layer compares only the new WHOIS result against the device's currently stored estimated location. None of them track oscillation history or apply any time-based debounce, so an A -> B -> A -> B sequence satisfies the "something changed" guard on every flap:
whois_fetched_handlerskips the task only when neitheraddressnorcoordinateschanged in the WHOIS record. On a flap between different locations both change, so the task always runs. (openwisp_controller/geo/estimated_location/handlers.py:55-61)_create_or_update_estimated_locationbuildsupdate_fieldsby diffing the incoming WHOIS values against the storedLocation. On A -> B -> A -> B the incoming coordinates always differ from what is stored, soupdate_fieldsis always non-empty and the notification fires. (openwisp_controller/geo/estimated_location/service.py:119-135)whois_lookup_skipped_handlerstill triggers the task, which reaches the same update path and notifies. (openwisp_controller/geo/estimated_location/handlers.py:66-81)Note on test coverage
The existing test
test_unchanged_whois_data_no_location_recreation(openwisp_controller/geo/estimated_location/tests/tests.py:692-731) only covers flapping to the same IP / identical WHOIS data, whereupdate_fieldsis empty and no notification fires. The different-location flap case has no coverage.Environment