IPcheck: unit + integration tests; fix exempt-address crash, rehash, and 16-bit/unsigned arithmetic bugs - #102
Open
MrIron-no wants to merge 2 commits into
Open
IPcheck: unit + integration tests; fix exempt-address crash, rehash, and 16-bit/unsigned arithmetic bugs#102MrIron-no wants to merge 2 commits into
MrIron-no wants to merge 2 commits into
Conversation
…ic bugs
Found by the new IPcheck unit and integration tests.
- Exempt addresses (IPCheck { except ... }) were accepted without being
recorded, but the client was still marked IPChecked, so
IPcheck_connect_succeeded() reported a stale entry and
IPcheck_disconnect() decremented a count it never incremented. With an
entry present for the address (clients connected before the exemption,
or remote users), the third exempt disconnect tripped
"Assertion failure at IPcheck.c:665: entry->connected > 0" and aborted
the server; with asserts off the count wrapped and Client-block maxlinks
stopped working. Remote exempt clients were flagged the same way.
IPcheck_local_connect() now returns IPCHECK_REFUSED / IPCHECK_COUNTED /
IPCHECK_EXEMPT and callers mark the client IPChecked only when it was
counted; ip_registry_check_remote() sets the flag only after the invalid
and exempt early-outs; the post-hooks (connect_succeeded, connect_fail)
are guarded by IsIPChecked() like IPcheck_disconnect() already was.
- Removing the IPCheck block from the config and rehashing left the old
exemptions in force: IPcheck_clear_config() was only called while
parsing an IPCheck block. Call it from read_configuration_file().
- CONNECTED_SINCE() subtracted two 16-bit timestamps in int, so it went
negative for up to 65536 s after CurrentTime crossed a multiple of 65536
(every 18.2 hours): the clone period never reset, entries did not expire
and free-target regeneration underflowed. Reduce modulo 2^16.
- With no free targets left, `CurrentTime - (TARGET_DELAY * free_targets
- 1)` was computed in unsigned int, giving CurrentTime - 4294967295 on
64-bit time_t instead of CurrentTime + 1: a client returning from an
address that had exhausted its targets got a full set instead of none.
- The remote-connect overflow guard refused the client but left the
connected counter wrapped to zero.
ircd/test/ipcheck_t.c (make check) drives ircd/IPcheck.c through its public API with a fake clock and feature values: clone limit and period (including refused attempts restarting the period), address independence, boot grace (IPCHECK_CLONE_DELAY), connect_fail() undo, disconnect accounting and the reset on last disconnect, exemptions (result code, no flag, no interference with an existing entry, cleared config), remote vs. burst introductions, IPv6 /64 keying and the /48 limit, IPv4 canonical form, free-target inheritance / pinning / regeneration / long-connection bonus, the expiry pass, the 16-bit clock wrap and the connected-counter overflow guard. tests/ipcheck/ (docker): - test_ipcheck_limits.py on the limits server, driving the limits with SET (PRIV_SET granted by rehash): registry notice contents, throttle ERROR before any input, recovery after the period, refused attempts restarting the period, slot release on disconnect, boot grace, IPCheck except block via rehash (and its removal), Client-block maxlinks enforced from the registry. - test_ipcheck_remote.py on the hub: a P10-introduced user with the test host's address counts toward (and is released from) the address, one with another address does not. P10Server.introduce_user() gains an ip parameter for this.
Contributor
Author
|
Regression run over the suites that share the touched paths ( The failure is Also confirmed after the fixes: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds comprehensive tests for
ircd/IPcheck.c(there were none) and fixes the five bugs they surfaced. Two commits: fixes (74307e5) and tests (2d57779).Bugs fixed (
74307e5)IPCheck { except ... }addresses are accepted without being recorded, but the client was still markedIPChecked, soIPcheck_connect_succeeded()reported a stale entry andIPcheck_disconnect()decremented a count it never incremented. With an entry present for the address (clients connected before the exemption, or remote users) the third exempt disconnect hitAssertion failure at IPcheck.c:665: "entry->connected > 0"and aborted the server (reproduced in the docker harness:ircu-limits exited 134); with asserts off the counter wraps and Client-blockmaxlinksstops working. Remote exempt clients were flagged the same way.IPcheck_local_connect()now returnsIPCHECK_REFUSED/IPCHECK_COUNTED/IPCHECK_EXEMPT; callers (s_bsd.c,websocket.c,s_auth.c) mark the clientIPCheckedonly when counted;ip_registry_check_remote()sets the flag only after the invalid/exempt early-outs;connect_succeeded/connect_failcall sites are guarded byIsIPChecked()asIPcheck_disconnect()already was.IPCheckblock (IPcheck_clear_config()was only called while parsing one). Now called fromread_configuration_file().CONNECTED_SINCE()went negative for up to 65536 s afterCurrentTimecrossed a multiple of 65536 (every 18.2 h): clone period never reset, entries never expired, free-target regeneration underflowed. Reduced modulo 2^16.CurrentTime - (TARGET_DELAY * free_targets - 1)was evaluated inunsigned int, yieldingCurrentTime - 4294967295on 64-bittime_tinstead ofCurrentTime + 1.connectedwrapped to 0.Behaviour changes worth noting: exempt clients no longer receive the (stale)
on N ca M(L) ...notice at all; clients reconnecting from an address that exhausted its targets now get none, as the comments inip_registry_disconnect()intend.Tests (
2d57779)ircd/test/ipcheck_t.c(make check): fake clock + feature values; clone limit/period (incl. refused attempts restarting the period), address independence, boot grace,connect_failundo, disconnect accounting and reset-on-last-disconnect, exemptions (result code, no flag, existing entry untouched, config clear), remote vs. burst, IPv6 /64 keying and /48 limit, IPv4 canonical form, free-target inheritance/pinning/regeneration/bonus, expiry pass, clock wrap, counter overflow.tests/ipcheck/test_ipcheck_limits.py(limits server,SET-driven): registry notice contents, throttleERRORbefore any input, recovery after the period, refused-attempt period restart, slot release, boot grace,IPCheckexcept block via rehash and its removal, Client-blockmaxlinksenforced from the registry.tests/ipcheck/test_ipcheck_remote.py(hub): a P10-introduced user with the test host's address counts toward and is released from that address; another address does not.P10Server.introduce_user()gainsip=.Verification
make -C ircd/test check: 7/7tests/ipcheck/: 10/10 (docker)class_limits,pr_websocket,cidr_glines,pr69_exempt_throttle: running at PR time; result will be posted as a comment.