implement primitive probing of the rendezvous server's public IP and provide it to LAN clients
This commit is contained in:
parent
32ecd8074c
commit
4f64b7be53
|
@ -1,9 +1,9 @@
|
||||||
import asyncdispatch, asyncnet, os, strformat, strutils, tables
|
import asyncdispatch, asyncnet, os, sequtils, strformat, strutils, tables
|
||||||
from net import IpAddress, Port, `$`
|
from nativesockets import htonl
|
||||||
|
from net import IpAddress, Port, getPrimaryIPAddr, parseIpAddress, `$`
|
||||||
|
import ../../asyncutils
|
||||||
import ../../message
|
import ../../message
|
||||||
|
import ../../network_interface
|
||||||
# TODO: we need to find out our own external IP and return it to clients who
|
|
||||||
# connect from our LAN
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Client = object
|
Client = object
|
||||||
|
@ -25,12 +25,49 @@ type
|
||||||
recipient: string
|
recipient: string
|
||||||
data: string
|
data: string
|
||||||
|
|
||||||
|
proc isPrivateIp(ip: IpAddress): bool =
|
||||||
|
const ranges: array[5, tuple[first: IpAddress, last: IpAddress]] =
|
||||||
|
[(parseIpAddress("10.0.0.0"), parseIpAddress("10.255.255.255")),
|
||||||
|
(parseIpAddress("172.16.0.0"), parseIpAddress("172.31.255.255")),
|
||||||
|
(parseIpAddress("192.168.0.0"), parseIpAddress("192.168.255.255")),
|
||||||
|
(parseIpAddress("169.254.0.0"), parseIpAddress("169.254.255.255")),
|
||||||
|
(parseIpAddress("127.0.0.0"), parseIpAddress("127.255.255.255"))]
|
||||||
|
for r in ranges:
|
||||||
|
let ipScalar = htonl(cast[uint32](ip.address_v4))
|
||||||
|
if ipScalar > htonl(cast[uint32](r.first.address_v4)) and
|
||||||
|
ipScalar < htonl(cast[uint32](r.last.address_v4)):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc isInNetwork(ip: IpAddress, iface: NetworkInterface): bool =
|
||||||
|
let ipScalar = htonl(cast[uint32](ip.address_v4))
|
||||||
|
let ifaceIpScalar = htonl(cast[uint32](iface.ipAddress.address_v4))
|
||||||
|
let netmaskScalar = htonl(cast[uint32](iface.netmask.address_v4))
|
||||||
|
(ipScalar and netmaskScalar) == (ifaceIpScalar and netmaskScalar)
|
||||||
|
|
||||||
|
proc probePublicIp(): Future[IpAddress] {.async.} =
|
||||||
|
let output = await asyncExecCmd("ping -R -c 1 -s 1 -n 193.0.14.129")
|
||||||
|
let ipLines = output.splitLines()
|
||||||
|
.filter(proc(l: string): bool = l.startsWith("\t") or l.startsWith("RR:"))
|
||||||
|
.map(proc(l: string): string = l.strip(true, false, {'R', ':', '\t', ' '}))
|
||||||
|
for line in ipLines:
|
||||||
|
let ipAddr = parseIpAddress(line)
|
||||||
|
if not isPrivateIp(ipAddr):
|
||||||
|
return ipAddr
|
||||||
|
block:
|
||||||
|
raise newException(OSError, "cannot probe public IP address")
|
||||||
|
|
||||||
proc removeClient(clients: TableRef[string, Client], peerId: string) =
|
proc removeClient(clients: TableRef[string, Client], peerId: string) =
|
||||||
if peerId.len > 0: clients.del(peerId)
|
if peerId.len > 0: clients.del(peerId)
|
||||||
|
|
||||||
proc processClient(client: AsyncSocket, clients: TableRef[string, Client]) {.async.} =
|
proc processClient(client: AsyncSocket,
|
||||||
let (address, port) = client.getPeerAddr
|
clients: TableRef[string, Client]) {.async.} =
|
||||||
await client.send(&"notify-endpoint|{address}|{port.int}\n")
|
let (address, port) = client.getPeerAddr()
|
||||||
|
var ipAddr = parseIpAddress(address)
|
||||||
|
if ipAddr.isPrivateIp() and
|
||||||
|
ipAddr.isInNetwork(fromIpAddress(getPrimaryIPAddr(ipAddr))):
|
||||||
|
ipAddr = await probePublicIp()
|
||||||
|
await client.send(&"notify-endpoint|{ipAddr}|{port.int}\n")
|
||||||
var id = ""
|
var id = ""
|
||||||
var peerId = ""
|
var peerId = ""
|
||||||
while true:
|
while true:
|
||||||
|
|
Loading…
Reference in New Issue