move Port -> uint16 conversions to a wrapper proc

master
Christian Ulrich 2020-11-18 19:32:31 +01:00
parent e814df7a67
commit 81a39f32c1
No known key found for this signature in database
GPG Key ID: 8241BE099775A097
1 changed files with 22 additions and 21 deletions

View File

@ -9,7 +9,7 @@ const RandomPortCount = 10000
proc min(a, b: uint16): uint16 = proc min(a, b: uint16): uint16 =
min(a.int32, b.int32).uint16 min(a.int32, b.int32).uint16
proc toUint16(p: Port): uint16 = uint16(p) proc toUInt16(p: Port): uint16 = uint16(p)
proc toPort(u: uint16): Port = Port(u) proc toPort(u: uint16): Port = Port(u)
@ -31,31 +31,29 @@ proc subtractOffset(port: uint16, offset: uint16, minValue = 1024'u16,
return maxValue - offset + distanceToMinValue + 1 return maxValue - offset + distanceToMinValue + 1
return port - offset return port - offset
proc predictPortRange*(localPort: Port, probedPorts: seq[Port]): seq[Port] = proc predictPortRange*(localPort: uint16, probedPorts: seq[uint16]): seq[uint16] =
if probedPorts.len == 0: if probedPorts.len == 0:
# No probed ports, so our only guess can be that the NAT is a cone-type NAT # No probed ports, so our only guess can be that the NAT is a cone-type NAT
# and the port mapping preserves the local Port. # and the port mapping preserves the local Port.
return @[localPort] return @[localPort]
let localPortUint = localPort.uint16
let probedPortsUint = probedPorts.map(toUint16)
if probedPorts.len == 1: if probedPorts.len == 1:
# Only one server was used for probing, so we cannot know if the NAT is # Only one server was used for probing, so we cannot know if the NAT is
# symmetric or not. We are trying the probed port (assuming cone-type NAT) # symmetric or not. We are trying the probed port (assuming cone-type NAT)
# and the next port in a progressive sequence if applicable (assuming # and the next port in a progressive sequence if applicable (assuming
# symmetric NAT with progressive port mapping). # symmetric NAT with progressive port mapping).
result.add(probedPorts[0]) result.add(probedPorts[0])
if probedPortsUint[0] > localPortUint: if probedPorts[0] > localPort:
let offset = probedPortsUint[0] - localPortUint let offset = probedPorts[0] - localPort
result.add(Port(probedPortsUint[0].addOffset(offset))) result.add(probedPorts[0].addOffset(offset))
elif probedPortsUint[0] < localPortUint: elif probedPorts[0] < localPort:
let offset = localPortUint - probedPortsUint[0] let offset = localPort - probedPorts[0]
result.add(Port(probedPortsUint[0].subtractOffset(offset))) result.add(probedPorts[0].subtractOffset(offset))
return return
let deduplicatedPorts = probedPortsUint.deduplicate() let deduplicatedPorts = probedPorts.deduplicate()
if deduplicatedPorts.len() == 1: if deduplicatedPorts.len() == 1:
# It looks like the NAT is a cone-type NAT. # It looks like the NAT is a cone-type NAT.
return deduplicatedPorts.map(toPort) return deduplicatedPorts
let probedPortsSorted = probedPortsUint.sorted() let probedPortsSorted = probedPorts.sorted()
let minPort = probedPortsSorted[probedPortsSorted.minIndex()] let minPort = probedPortsSorted[probedPortsSorted.minIndex()]
let maxPort = probedPortsSorted[probedPortsSorted.maxIndex()] let maxPort = probedPortsSorted[probedPortsSorted.maxIndex()]
var minDistance = uint16.high() var minDistance = uint16.high()
@ -66,21 +64,21 @@ proc predictPortRange*(localPort: Port, probedPorts: seq[Port]): seq[Port] =
minDistance = min(minDistance, distance) minDistance = min(minDistance, distance)
maxDistance = max(maxDistance, distance) maxDistance = max(maxDistance, distance)
if maxDistance < 10: if maxDistance < 10:
if probedPortsUint.isSorted(Ascending): if probedPorts.isSorted(Ascending):
# assume symmetric NAT with positive-progressive port mapping # assume symmetric NAT with positive-progressive port mapping
if minDistance == maxDistance: if minDistance == maxDistance:
return @[Port(maxPort.addOffset(maxDistance))] return @[maxPort.addOffset(maxDistance)]
else: else:
for i in countup(0'u16, maxDistance): for i in countup(0'u16, maxDistance):
result.add(Port(minPort.addOffset(i))) result.add(minPort.addOffset(i))
return return
if probedPortsUint.isSorted(Descending): if probedPorts.isSorted(Descending):
# assume symmetric NAT with negative-progressive port mapping # assume symmetric NAT with negative-progressive port mapping
if minDistance == maxDistance: if minDistance == maxDistance:
return @[Port(minPort.subtractOffset(maxDistance))] return @[minPort.subtractOffset(maxDistance)]
else: else:
for i in countup(0'u16, maxDistance): for i in countup(0'u16, maxDistance):
result.add(Port(maxPort.subtractOffset(i))) result.add(maxPort.subtractOffset(i))
return return
# assume symmetric NAT with random port mapping # assume symmetric NAT with random port mapping
randomize() randomize()
@ -88,9 +86,12 @@ proc predictPortRange*(localPort: Port, probedPorts: seq[Port]): seq[Port] =
maxPort + 1000'u16 maxPort + 1000'u16
else: else:
uint16.high - RandomPortCount uint16.high - RandomPortCount
result = newSeq[Port](RandomPortCount) result = newSeq[uint16](RandomPortCount)
for i in 0'u16 .. RandomPortCount - 1'u16: for i in 0'u16 .. RandomPortCount - 1'u16:
result[i] = Port(first + i) result[i] = first + i
proc predictPortRange*(localPort: Port, probedPorts: seq[Port]): seq[Port] =
predictPortRange(localPort.uint16, probedPorts.map(toUInt16)).map(toPort)
suite "port prediction tests": suite "port prediction tests":
test "single port": test "single port":