Skip to content

ACOMMONS-164 Improve IP classification and allow querying without reparsing - #571

Merged
lijun-chen-sonarsource merged 16 commits into
masterfrom
lc/ACOMMONS-164
Oct 22, 2026
Merged

lijun-chen-sonarsource merged 16 commits into
masterfrom
lc/ACOMMONS-164

Conversation

@lijun-chen-sonarsource

@lijun-chen-sonarsource lijun-chen-sonarsource commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Expose parse(String) returning an immutable ParsedIp, so analyzers can
distinguish invalid input and query multiple classifications without reparsing.
Existing public static predicates remain available.

  • Support mixed IPv6 notation and consistently classify mapped and translated
    addresses by their embedded IPv4 address.
  • Delegate numeric parsing to InetAddress.getByName, with lexical guards
    to prevent DNS lookup. Strip IPv6 zone suffixes to avoid interface lookup.
    Reject leading-zero decimal octets because some consumers interpret them
    as octal, while the JDK interprets them as decimal.
  • Recognize IPv4 and IPv6 multicast independently of reserved-address
    classification.
  • Provide a shared helper for analyzers implementing S1313 to determine
    whether an IP address is allowed to be hardcoded.

Summary by Gitar

  • Multicast:
    • Added ParsedIp.isMulticast covering IPv4 224.0.0.0/4 and IPv6 ff00::/8, included in isS1313Exempt
  • Parsing:
    • Added IpAddressClassifier.parse with guarded numeric parsing that rejects ambiguous leading-zero octets
  • Breaking:
    • Removed the package-private Classification enum and isInternetRoutable

This will update automatically on new commits.

Let callers parse an address once and query multiple predicates on the immutable result. Keep public static predicates as compatibility wrappers and migrate tests from the package-private classification API.
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

ACOMMONS-164

Use the standard library to parse IPv4 and mixed hexadecimal/decimal IPv6 spellings. Guard numeric inputs against DNS lookup, require four-component IPv4 and ASCII CIDR prefixes, and restore the native IPv6 value of JDK-converted mapped addresses.
… payload

Apply IPv4 classification consistently to dotted and pure-hex mapped and historical translated addresses. Project only ranges wholly contained within either family, retain native CIDR prefix semantics, and document translated payload classification as an explicit policy.
Classify the base IPv6 address independently of its interface selector. Accept named, numeric, and empty zones without interface lookup, preserve CIDR prefixes, and reject IPv4 zones.
Expose multicast as an independent classification category for ranges wholly contained in 224.0.0.0/4 or ff00::/8. Keep reserved-range classification unchanged.
Give analyzers a common suppression policy for loopback, any-address, broadcast, documentation, and multicast ranges. Private and link-local addresses remain reportable; callers can parse once and query the policy on the result.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great improvements, thanks @lijun-chen-sonarsource! 👍

Please update the PR title to be something more descriptive and see my minor nits about name of isS1313Exempt & test coverage, otherwise this looks good to go.

"fc99:1234::42, true",
"fc00::1, true",
"fc00::/7, true",
"::ffff:10.0.0.1, true",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this into its own category (as this is not a v6 unique local), feel free to add other RFC1918 addresses.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ec34bdd

/**
* True if the literal is the IPv4 limited-broadcast address {@code 255.255.255.255} (or {@code /32}).
* IPv6 has no broadcast equivalent, so every IPv6 literal returns false.
* IPv6 literals return false except mapped and translated addresses, which use the IPv4 payload classification.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Payload classification? 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

39aae00 now uses "embedded IPv4". Payload was indeed confusing.

@lijun-chen-sonarsource lijun-chen-sonarsource changed the title ACOMMONS-164 Improvements to IpAddressClassifier ACOMMONS-164 Improve IP classification and allow querying without reparsing Oct 19, 2026
@sonarqube-next

Copy link
Copy Markdown

@gitar-bot

gitar-bot Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Code Review ✅ Approved 2 closed / 2 findings

🟡 Medium risk · Reworking IP parsing and address classifications could cause analyzers to misclassify literals, missing security findings or flagging benign addresses.

Adds parse(String) returning an immutable ParsedIp so analyzers can classify IPs without reparsing, and removes the package-private Classification enum and isInternetRoutable. Changes requested: the renamed isAllowedToBeHardcoded() drops the multicast exemption, which breaks the sonar-php S1313 migration (it still calls isS1313Exempt() and expects ff02::1 to be Compliant) once this is released. Leading-zero IPv4 octets are now parsed as decimal, resolving the S6329 miss.

✅ 2 closed
✅ Security: Leading-zero IPv4 octets now parsed as decimal, so S6329 misses them

📄 commons/src/main/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifier.java:70 📄 commons/src/main/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifier.java:335-338 📄 commons/src/main/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifier.java:368 📄 commons/src/main/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifier.java:44-49 📄 commons/src/main/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifier.java:108 📄 commons/src/test/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifierTest.java:240 📄 commons/src/test/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifierTest.java:326
The old parseIpv4Address rejected octets with a leading zero on purpose ("0177.0.0.1", "010.0.0.1"), and a test locked that in. Those literals came back UNPARSEABLE, so the S6329 example (!isReserved(literal)) still flagged them on the safe side. The new path rewrites the literal as "::ffff:" + literal and hands it to the JDK's embedded-IPv4 parser, which reads each octet as decimal. Now "010.0.0.1" parses as 10.0.0.1, so isReserved and isPrivate return true and S6329 stays silent. On inet_aton-style resolvers (glibc, curl, many language runtimes) that literal means 8.0.0.1, a public address. In the same way, "0177.0.0.1" is now treated as public 177.0.0.1 even though those resolvers send it to loopback 127.0.0.1. The PR deleted the guard and its test cases, and even asserts parseIpv4SingleAddress("0177.0.0.1") == 177.0.0.1. That breaks the class's stated rule that a literal is classified only when its meaning is unambiguous. The fix is to restore the rejection of multi-digit octets that start with '0', both for plain IPv4 and for the dotted tail of mixed IPv6 notation, so ambiguous literals stay unparseable.

Closed: Cross-PR: sonar-php S1313 migration won't compile and multicast test fails

📄 commons/src/main/java/org/sonarsource/analyzer/commons/appsec/IpAddressClassifier.java:309-317
Breaks when this PR is released and SonarSource/sonar-php#1848 bumps its sonar-commons pin to that release.

How

  1. HardCodedIpAddressCheck.java:69 on SONARPHP-1927 S1313 Adopt IpAddressClassifier for hardcoded-IP filtering in sonar-php sonar-php#1848 calls ParsedIp.isS1313Exempt().
  2. In this PR that method is renamed to isAllowedToBeHardcoded() (IpAddressClassifier.java:315), and isS1313Exempt no longer exists, so sonar-php fails to compile.
  3. This PR also removes isMulticast() from the exemption (IpAddressClassifier.java:316). The PHP test resource HardCodedIpAddressCheck.php still expects "ff02::1" to be Compliant, so that test fails even after the method name is updated.

Fix

Compared 42337cb with SonarSource/sonar-php#1848 at 7a7c449

Verification Rules 1/1 met Repos 5 inspected · PRs 1 inspected

Functional validation No results

Rules 1 passed 2 not applicable

✅ Repository license compliance

Broader impact Repos 5 inspected PRs 1 inspected
Cross-repo 5 repositories inspected 0 open impacts

SonarSource/sonar-java Inspected
SonarSource/SonarJS Inspected
SonarSource/sonar-dotnet Inspected
SonarSource/sonar-python Inspected
SonarSource/sonar-php Inspected

Cross-PR 1 PR inspected 0 open impacts

PR 1848: SONARPHP-1927 S1313 Adopt IpAddressClassifier for hardcoded-IP filtering in sonar-php Inspected

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@lijun-chen-sonarsource
lijun-chen-sonarsource merged commit e7ed02c into master Oct 22, 2026
14 checks passed
@lijun-chen-sonarsource
lijun-chen-sonarsource deleted the lc/ACOMMONS-164 branch October 22, 2026 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants