mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-22 15:08:12 -05:00
Fix compiling of IpCondition related to IPv6 address. Fix #67.
This commit is contained in:
parent
045d852739
commit
df9fbc4958
@ -250,7 +250,7 @@ module.exports = exports =
|
||||
if parts.length > 1
|
||||
addr = @parseIp parts[0]
|
||||
prefixLen = parseInt(parts[1])
|
||||
if addr and prefixLen
|
||||
if addr and not isNaN(prefixLen)
|
||||
cache.ip =
|
||||
conditionType: 'IpCondition'
|
||||
ip: parts[0]
|
||||
@ -265,11 +265,7 @@ module.exports = exports =
|
||||
serverRegex = null
|
||||
if serverIp?
|
||||
if serverIp.regularExpressionString?
|
||||
# TODO(felis): IPv6 regex is not fully supported by the ipv6
|
||||
# module. Even simple addresses like ::1 will fail. Shall we
|
||||
# implement that instead?
|
||||
regexStr = serverIp.regularExpressionString(true)
|
||||
console.log(regexStr)
|
||||
serverRegex = '\\[' + regexStr + '\\]'
|
||||
else
|
||||
server = @normalizeIp serverIp
|
||||
@ -292,7 +288,7 @@ module.exports = exports =
|
||||
match: (condition, request, cache) ->
|
||||
cache = cache.analyzed
|
||||
return false if cache.scheme? and cache.scheme != request.scheme
|
||||
return false if cache.ip? and @match cache.ip, request
|
||||
return false if cache.ip? and not @match cache.ip, request
|
||||
if cache.host?
|
||||
if cache.host == '<local>'
|
||||
return request.host in @localHosts
|
||||
@ -381,7 +377,7 @@ module.exports = exports =
|
||||
mask = if cache.addr.v4
|
||||
new IP.v4.Address('255.255.255.255/' + cache.addr.subnetMask)
|
||||
else
|
||||
new IP.v6.Address(@ipv6Max + cache.addr.subnetMask)
|
||||
new IP.v6.Address(@ipv6Max + '/' + cache.addr.subnetMask)
|
||||
cache.mask = @normalizeIp mask.startAddress()
|
||||
cache
|
||||
match: (condition, request, cache) ->
|
||||
@ -392,7 +388,7 @@ module.exports = exports =
|
||||
return addr.isInSubnet cache.addr
|
||||
compile: (condition, cache) ->
|
||||
cache = cache.analyzed
|
||||
new U2.AST_Call(
|
||||
isInNetCall = new U2.AST_Call(
|
||||
expression: new U2.AST_SymbolRef name: 'isInNet'
|
||||
args: [
|
||||
new U2.AST_SymbolRef name: 'host'
|
||||
@ -400,6 +396,39 @@ module.exports = exports =
|
||||
new U2.AST_String value: cache.mask
|
||||
]
|
||||
)
|
||||
if cache.addr.v4 then isInNetCall else
|
||||
isInNetExCall = new U2.AST_Call(
|
||||
expression: new U2.AST_SymbolRef name: 'isInNetEx'
|
||||
args: [
|
||||
new U2.AST_SymbolRef name: 'host'
|
||||
new U2.AST_String value: cache.addr.address
|
||||
]
|
||||
)
|
||||
alternative = if cache.addr.subnetMask > 0 then isInNetCall else
|
||||
# ::/0 ==> Just detect whether address is IPv6 (containing colons).
|
||||
new U2.AST_Binary(
|
||||
left: new U2.AST_Call(
|
||||
expression: new U2.AST_Dot(
|
||||
expression: new U2.AST_SymbolRef name: 'host'
|
||||
property: 'indexOf'
|
||||
)
|
||||
args: [new U2.AST_String value: ':']
|
||||
)
|
||||
operator: '>='
|
||||
right: new U2.AST_Number value: 0
|
||||
)
|
||||
new U2.AST_Conditional(
|
||||
condition: new U2.AST_Binary(
|
||||
left: new U2.AST_UnaryPrefix(
|
||||
operator: 'typeof'
|
||||
expression: new U2.AST_SymbolRef name: 'isInNetEx'
|
||||
)
|
||||
operator: '==='
|
||||
right: new U2.AST_String value: 'function'
|
||||
)
|
||||
consequent: isInNetExCall
|
||||
alternative: alternative
|
||||
)
|
||||
'HostLevelsCondition':
|
||||
tag: (condition) -> condition.minValue + '~' + condition.maxValue
|
||||
analyze: (condition) -> '.'.charCodeAt 0
|
||||
|
@ -175,16 +175,95 @@ describe 'Conditions', ->
|
||||
pattern: 'http://127.0.0.1:8080'
|
||||
testCond(cond, 'http://127.0.0.1:8080/', 'match')
|
||||
testCond(cond, 'http://127.0.0.2:8080/', not 'match')
|
||||
# TODO(felis): Not yet supported. See the code for BypassCondition.
|
||||
it 'should correctly support IPv6 canonicalization', ->
|
||||
cond =
|
||||
conditionType: 'BypassCondition'
|
||||
pattern: 'http://[0:0::1]:8080'
|
||||
result = Conditions.analyze(cond)
|
||||
console.log(result.analyzed)
|
||||
testCond(cond, 'http://[::1]:8080/', 'match')
|
||||
testCond(cond, 'http://[1::1]:8080/', not 'match')
|
||||
|
||||
it 'should parse IPv4 CIDR notation', ->
|
||||
cond =
|
||||
conditionType: 'BypassCondition'
|
||||
pattern: '192.168.0.0/16'
|
||||
result = Conditions.analyze(cond).analyzed
|
||||
should.exist(result.ip)
|
||||
result.ip.should.eql({
|
||||
conditionType: 'IpCondition'
|
||||
ip: '192.168.0.0'
|
||||
prefixLength: 16
|
||||
})
|
||||
|
||||
it 'should parse IPv6 CIDR notation', ->
|
||||
cond =
|
||||
conditionType: 'BypassCondition'
|
||||
pattern: 'fefe:13::abc/33'
|
||||
result = Conditions.analyze(cond).analyzed
|
||||
should.exist(result.ip)
|
||||
result.ip.should.eql({
|
||||
conditionType: 'IpCondition'
|
||||
ip: 'fefe:13::abc'
|
||||
prefixLength: 33
|
||||
})
|
||||
|
||||
it 'should parse IPv6 CIDR notation with zero prefixLength', ->
|
||||
cond =
|
||||
conditionType: 'BypassCondition'
|
||||
pattern: '::/0'
|
||||
result = Conditions.analyze(cond).analyzed
|
||||
should.exist(result.ip)
|
||||
result.ip.should.eql({
|
||||
conditionType: 'IpCondition'
|
||||
ip: '::'
|
||||
prefixLength: 0
|
||||
})
|
||||
|
||||
describe 'IpCondition', ->
|
||||
# IpCondition requires isInNetEx or isInNet function provided by the PAC
|
||||
# runner, which is not available in the unit test. So We can't use testCond
|
||||
# here.
|
||||
it 'should support IPv4 subnet', ->
|
||||
cond =
|
||||
conditionType: "IpCondition"
|
||||
ip: '192.168.1.1'
|
||||
prefixLength: 16
|
||||
request = Conditions.requestFromUrl('http://192.168.4.4/')
|
||||
Conditions.match(cond, request).should.be.true
|
||||
compiled = Conditions.compile(cond).print_to_string()
|
||||
compiled.should.equal('isInNet(host,"192.168.1.1","255.255.0.0")')
|
||||
it 'should support IPv6 subnet', ->
|
||||
cond =
|
||||
conditionType: "IpCondition"
|
||||
ip: 'fefe:13::abc'
|
||||
prefixLength: 33
|
||||
|
||||
request = Conditions.requestFromUrl('http://[fefe:13::def]/')
|
||||
Conditions.match(cond, request).should.be.true
|
||||
|
||||
compiled = Conditions.compile(cond).print_to_string()
|
||||
compiled_args = compiled.substr(compiled.lastIndexOf('('))
|
||||
compiled_args.should.eql('(host,"fefe:13::abc","ffff:ffff:8000::")')
|
||||
it 'should support IPv6 subnet with zero prefixLength', ->
|
||||
cond =
|
||||
conditionType: "IpCondition"
|
||||
ip: '::'
|
||||
prefixLength: 0
|
||||
|
||||
request = Conditions.requestFromUrl('http://[fefe:13::def]/')
|
||||
Conditions.match(cond, request).should.be.true
|
||||
|
||||
compiled = Conditions.compile(cond).print_to_string()
|
||||
compiled.indexOf('indexOf(').should.be.above(0)
|
||||
it 'should not match domain name to IP subnet', ->
|
||||
cond =
|
||||
conditionType: "IpCondition"
|
||||
ip: '::'
|
||||
prefixLength: 0
|
||||
|
||||
request = Conditions.requestFromUrl('http://www.example.com/')
|
||||
Conditions.match(cond, request).should.be.false
|
||||
|
||||
describe 'KeywordCondition', ->
|
||||
cond =
|
||||
conditionType: 'KeywordCondition'
|
||||
|
Loading…
Reference in New Issue
Block a user