Support IP/CIDR rules conversion from SwitchyOmega#541
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates SwitchyOmega rule import handling so Ip: conditions are converted into SmartProxy regex host rules using existing CIDR utilities, with regression coverage for IPv4/IPv6 cases.
Changes:
- Reworks SwitchyOmega
IpConditionparsing/compilation to useUtils.ipCidrNotationToRegExp. - Adds IPv6 normalization regression coverage for exact and bracketed host forms.
- Fixes a Chrome PAC path to use the matched subscription rule when forcing proxy selection.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/lib/RuleImporterSwitchy.js |
Converts SwitchyOmega IP conditions to regex-backed host rules. |
src/lib/Utils.ts |
Adjusts IPv6 host normalization for bracketed hosts with ports. |
src/tests/RuleImporter.test.ts |
Adds SwitchyOmega Ip: import regression tests. |
src/tests/Utils.ipCidr.test.ts |
Adds IPv6 normalization regression test coverage. |
src/core/ProxyEngineChrome.ts |
Corrects subscription matched-rule usage in AlwaysEnabled bypass handling. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (type == 'host') { | ||
| newRule.importedRuleType = CompiledProxyRuleType.RegexHost; | ||
| newRule.normalizeIpHostMatch = compiled.normalizeIpHostMatch == true; |
| @@ -2437,15 +2437,6 @@ export class settingsPage { | |||
| username: username, | |||
| password: password, | |||
| backupFilename: backupFilename, | |||
| if (ipv6.indexOf('.') >= 0) | ||
| return null; | ||
|
|
||
| const parts = ipv6.split('::'); | ||
| if (parts.length > 2) | ||
| return null; | ||
|
|
||
| const left = parts[0] ? parts[0].split(':').filter(Boolean) : []; | ||
| const right = parts[1] ? parts[1].split(':').filter(Boolean) : []; | ||
| const missing = 8 - (left.length + right.length); | ||
| if (missing < 0) |
| regex = Utils.ipCidrNotationToRegExp(cache.addr.addressMinusSuffix, cache.addr.subnetMask.toString()); | ||
| if (regex == null) { | ||
| throw new Error("Invalid IP address " + addr); | ||
| } | ||
| cache.regex = regex; |
| prefixMatch = address.match(/\/(\d+)$/); | ||
| if (prefixMatch) { | ||
| subnetMask = parseInt(prefixMatch[1], 10); | ||
| address = address.substring(0, address.length - prefixMatch[0].length); | ||
| } | ||
| addressIsBracketed = address.charCodeAt(0) === '['.charCodeAt(0); | ||
| if (addressIsBracketed) { | ||
| if (!/^\[[^\]]+\]$/.test(address)) { | ||
| return null; | ||
| } | ||
| address = address.substring(1, address.length - 1); | ||
| } else if (address.indexOf('[') >= 0 || address.indexOf(']') >= 0) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
If an imported ip is 'bracketed', like [172.16.0.0/12], the prefixMatch regex //(\d+)$/ will return null because the string ends with a bracket ], not a digit.
As a result, the code skips stripping the subnet suffix here, later strips the brackets, and eventually passes "172.16.0.0/12" with a wrong default subnetMask to Utils.ipCidrNotationToRegExp.
To fix this, the bracket-stripping logic should execute before the prefixMatch slicing.
There was a problem hiding this comment.
yeah thanks I got this PR is kinda messed up, i'll try another one
Summary
This change fixes SwitchyOmega
Ip:rule imports so they are converted into SmartProxy internal regex host rules correctly.Previously, SwitchyOmega IP conditions were not making it through the importer because the importer still depended on the old SwitchyOmega-style
IPaddress classes, which are not available in this code path. As a result,IpConditionrules could not be compiled into the internal regex representation that SmartProxy expects.This PR removes that dependency from the importer path and reuses the existing CIDR-to-regex utilities already implemented in the project.
What changed
IpConditioncompiles directly into internalRegexHostrules.IP.v4.Address/IP.v6.Addresspath with the existingUtils.ipCidrNotationToRegExplogic.2001:db8::1could be misinterpreted as an address with a port and lose their final segment during normalization.Ip:rules, including compressed and expanded IPv6 forms.Why this approach
The project already has a CIDR-to-regex implementation and already treats internal IP/CIDR rules as regex host rules. Reusing that logic keeps behavior consistent across manual rules, imported rules, and runtime matching, while avoiding an extra dependency and avoiding duplicate subnet logic.
Behavior before
SwitchyOmega rules like the following were not imported correctly:
Behavior after
These rules are now parsed and compiled into SmartProxy internal
RegexHostrules and can participate in the normal subscription/import matching flow.Test coverage
Added or updated tests to verify:
Ip:rules are converted into internal regex host rules/8,/12, and/16Validation
Verified with: