Correctly handle CIDR notation in BypassCondition.

This commit is contained in:
FelisCatus 2014-11-07 17:25:15 +08:00
parent 51be2b9ff2
commit 6c8b478d1a
3 changed files with 51 additions and 43 deletions

View File

@ -17,7 +17,7 @@
"minifyify": "^4.1.1" "minifyify": "^4.1.1"
}, },
"dependencies": { "dependencies": {
"ipv6": "^3.1.1", "ipv6": "beaugunderson/javascript-ipv6",
"uglify-js": "^2.4.15" "uglify-js": "^2.4.15"
}, },
"browser": { "browser": {

View File

@ -143,6 +143,7 @@ module.exports = exports =
return addr return addr
normalizeIp: (addr) -> normalizeIp: (addr) ->
return (addr.correctForm ? addr.canonicalForm).call(addr) return (addr.correctForm ? addr.canonicalForm).call(addr)
ipv6Max: new IP.v6.Address('::/0').endAddress().canonicalForm()
localHosts: ["127.0.0.1", "[::1]", "localhost"] localHosts: ["127.0.0.1", "[::1]", "localhost"]
@ -247,43 +248,46 @@ module.exports = exports =
parts = server.split '/' parts = server.split '/'
if parts.length > 1 if parts.length > 1
cache.ip = addr = @parseIp parts[0]
conditionType: 'IpCondition' prefixLen = parseInt(parts[1])
ip: parts[0] if addr and prefixLen
prefixLength: parseInt parts[1] cache.ip =
else conditionType: 'IpCondition'
if server.charCodeAt(server.length - 1) != ']'.charCodeAt(0) ip: parts[0]
pos = server.lastIndexOf(':') prefixLength: prefixLen
if pos >= 0 return cache
matchPort = server.substring(pos + 1) if server.charCodeAt(server.length - 1) != ']'.charCodeAt(0)
server = server.substring(0, pos) pos = server.lastIndexOf(':')
serverIp = @parseIp server if pos >= 0
serverRegex = null matchPort = server.substring(pos + 1)
if serverIp? server = server.substring(0, pos)
if serverIp.regularExpressionString? serverIp = @parseIp server
# TODO(felis): IPv6 regex is not fully supported by the ipv6 serverRegex = null
# module. Even simple addresses like ::1 will fail. Shall we if serverIp?
# implement that instead? if serverIp.regularExpressionString?
regexStr = serverIp.regularExpressionString() # TODO(felis): IPv6 regex is not fully supported by the ipv6
regexStr = regexStr.substring 2, regexStr.length - 2 # module. Even simple addresses like ::1 will fail. Shall we
serverRegex = '\\[' + regexStr + '\\]' # implement that instead?
else regexStr = serverIp.regularExpressionString(true)
server = @normalizeIp serverIp console.log(regexStr)
else if server.charCodeAt(0) == '.'.charCodeAt(0) serverRegex = '\\[' + regexStr + '\\]'
server = '*' + server else
if matchPort server = @normalizeIp serverIp
if not serverRegex? else if server.charCodeAt(0) == '.'.charCodeAt(0)
serverRegex = shExp2RegExp(server) server = '*' + server
serverRegex = serverRegex.substring(1, serverRegex.length - 1) if matchPort
scheme = cache.scheme ? '[^:]+' if not serverRegex?
cache.url = @safeRegex('^' + scheme + ':\\/\\/' + serverRegex + serverRegex = shExp2RegExp(server)
':' + matchPort + '\\/') serverRegex = serverRegex.substring(1, serverRegex.length - 1)
else if server != '*' scheme = cache.scheme ? '[^:]+'
if serverRegex cache.url = @safeRegex('^' + scheme + ':\\/\\/' + serverRegex +
serverRegex = '^' + serverRegex + '$' ':' + matchPort + '\\/')
else else if server != '*'
serverRegex = shExp2RegExp server, trimAsterisk: true if serverRegex
cache.host = @safeRegex(serverRegex) serverRegex = '^' + serverRegex + '$'
else
serverRegex = shExp2RegExp server, trimAsterisk: true
cache.host = @safeRegex(serverRegex)
return cache return cache
match: (condition, request, cache) -> match: (condition, request, cache) ->
cache = cache.analyzed cache = cache.analyzed
@ -374,10 +378,14 @@ module.exports = exports =
if not cache.addr? if not cache.addr?
throw new Error "Invalid IP address #{addr}" throw new Error "Invalid IP address #{addr}"
cache.normalized = @normalizeIp cache.addr cache.normalized = @normalizeIp cache.addr
cache.mask = @normalizeIp cache.addr.startAddress() 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)
cache.mask = @normalizeIp mask.startAddress()
cache cache
match: (condition, request, cache) -> match: (condition, request, cache) ->
addr = @parseIp addr addr = @parseIp request.host
return false if not addr? return false if not addr?
cache = cache.analyzed cache = cache.analyzed
return false if addr.v4 != cache.addr.v4 return false if addr.v4 != cache.addr.v4

View File

@ -167,12 +167,12 @@ describe 'Conditions', ->
testCond(cond, 'http://127.0.0.1:8080/', 'match') testCond(cond, 'http://127.0.0.1:8080/', 'match')
testCond(cond, 'http://127.0.0.2:8080/', not 'match') testCond(cond, 'http://127.0.0.2:8080/', not 'match')
# TODO(felis): Not yet supported. See the code for BypassCondition. # TODO(felis): Not yet supported. See the code for BypassCondition.
it.skip 'should correctly support IPv6 canonicalization', -> it 'should correctly support IPv6 canonicalization', ->
cond = cond =
conditionType: 'BypassCondition' conditionType: 'BypassCondition'
pattern: 'http://[0:0::1]:8080' pattern: 'http://[0:0::1]:8080'
Conditions.analyze(cond) result = Conditions.analyze(cond)
cond._analyzed().url.should.equal '999' console.log(result.analyzed)
testCond(cond, 'http://[::1]:8080/', 'match') testCond(cond, 'http://[::1]:8080/', 'match')
testCond(cond, 'http://[1::1]:8080/', not 'match') testCond(cond, 'http://[1::1]:8080/', not 'match')