Skip to content

Commit e89fc57

Browse files
committed
Add manual connection with IPv6 addresses
This adds the ability to connect be connected from IPv6 addresses. This also fixes the way IP addresses are validated on input. Still currently broken: QR code connection
1 parent 463ac61 commit e89fc57

File tree

4 files changed

+50
-21
lines changed

4 files changed

+50
-21
lines changed

src/remote_registration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ def RequestCertificate(self, request, context):
301301

302302
def RegisterService(self, reg:warp_pb2.ServiceRegistration, context):
303303
logging.debug("Received manual registration from " + reg.service_id)
304-
self.service_registration_handler(reg, reg.ip, reg.auth_port)
304+
self.service_registration_handler(reg)
305305
return warp_pb2.ServiceRegistration(service_id=prefs.get_connect_id(),
306306
ip=self.ip_info.ip4_address,
307307
port=prefs.get_port(),

src/server.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import pkg_resources
1010
from concurrent import futures
1111
import time
12+
import ipaddress
13+
import urllib
1214

1315
from gi.repository import GObject, GLib
1416

@@ -272,13 +274,18 @@ def add_service(self, zeroconf, _type, name):
272274

273275
@misc._async
274276
def register_with_host(self, host:str):
275-
p = re.compile(r'(warpinator://)?(\d{1,3}(\.\d{1,3}){3}):(\d{1,6})/?$')
276-
m = p.match(host)
277-
if not m:
277+
278+
try:
279+
if not host.startswith("warpinator://"):
280+
host = "warpinator://%s" % host
281+
url = urllib.parse.urlparse(host)
282+
ipaddress.ip_address(url.hostname) # validate IPv4/IPv6 address
283+
except ValueError as e:
278284
logging.info("User tried to connect to invalid address %s" % host)
279285
self.idle_emit("manual-connect-result", True, False, "Invalid address")
280286
return
281-
host = "%s:%s" % (m.group(2), m.group(4))
287+
288+
host = url.netloc
282289
logging.info("Registering with " + host)
283290
with grpc.insecure_channel(host) as channel:
284291
future = grpc.channel_ready_future(channel)
@@ -288,30 +295,41 @@ def register_with_host(self, host:str):
288295
reg = stub.RegisterService(warp_pb2.ServiceRegistration(service_id=self.service_ident,
289296
ip=self.ip_info.ip4_address, port=self.port,
290297
hostname=util.get_hostname(), api_version=int(config.RPC_API_VERSION),
291-
auth_port=self.auth_port),
292-
timeout=5, ipv6=self.ip_info.ip6_address)
293-
ip = m.group(2)
294-
auth_port = int(m.group(4))
295-
self.handle_manual_service_registration(reg, ip, auth_port, True)
298+
auth_port=self.auth_port, ipv6=self.ip_info.ip6_address),
299+
timeout=5)
300+
self.handle_manual_service_registration(reg, True)
296301
except Exception as e:
297302
future.cancel()
298303
logging.critical("Could not register with %s, err %s" % (host, e))
299304
self.idle_emit("manual-connect-result", True, False, "Could not connect to remote")
300305

301-
def handle_manual_service_registration(self, reg, ip, auth_port, initiated_here=False):
306+
def handle_manual_service_registration(self, reg, initiated_here=False):
307+
ip4_addr = None
308+
ip6_addr = None
309+
try:
310+
ip4_addr = ipaddress.ip_address(reg.ip)
311+
except ValueError:
312+
pass
313+
try:
314+
ip6_addr = ipaddress.ip_address(reg.ipv6)
315+
except ValueError:
316+
pass
302317
if reg.service_id in self.remote_machines.keys():
303318
# Machine already known -> update
304319
machine = self.remote_machines[reg.service_id]
305320
if machine.status == RemoteStatus.ONLINE:
306-
logging.debug("Host %s:%d was already connected" % (ip, auth_port))
321+
logging.debug("Host %s:%d was already connected" % (machine.ip_info, reg.auth_port))
307322
self.idle_emit("manual-connect-result", initiated_here, True, "Already connected")
308323
return
309-
if self.remote_registrar.register(machine.ident, machine.hostname, machine.ip_info, machine.port, auth_port, machine.api_version) == util.CertProcessingResult.FAILURE or self.server_thread_keepalive.is_set():
310-
logging.debug("Registration of static machine failed, ignoring remote %s (%s:%d) auth %d" % (reg.hostname, ip, reg.port, auth_port))
324+
if self.remote_registrar.register(machine.ident, machine.hostname, machine.ip_info, machine.port, reg.auth_port, machine.api_version) == util.CertProcessingResult.FAILURE or self.server_thread_keepalive.is_set():
325+
logging.debug("Registration of static machine failed, ignoring remote %s (%s:%d) auth %d" % (reg.hostname, machine.ip_info, reg.port, reg.auth_port))
311326
self.idle_emit("manual-connect-result", initiated_here, False, "Authentication failed")
312327
return
313328
machine.hostname = reg.hostname
314-
machine.ip_info.ip4_address = ip
329+
if isinstance(ip4_addr, ipaddress.IPv4Address):
330+
machine.ip_info.ip4_address = str(ip4_addr)
331+
if isinstance(ip6_addr, ipaddress.IPv6Address):
332+
machine.ip_info.ip6_address = str(ip6_addr)
315333
machine.port = reg.port
316334
machine.api_version = str(reg.api_version)
317335

@@ -321,11 +339,14 @@ def handle_manual_service_registration(self, reg, ip, auth_port, initiated_here=
321339
logging.debug("Adding new static machine (manual connection)")
322340
display_hostname = self.ensure_unique_hostname(reg.hostname)
323341
ip_info = util.RemoteInterfaceInfo([])
324-
ip_info.ip4_address = ip
342+
if isinstance(ip4_addr, ipaddress.IPv4Address):
343+
ip_info.ip4_address = str(ip4_addr)
344+
if isinstance(ip6_addr, ipaddress.IPv6Address):
345+
ip_info.ip6_address = str(ip6_addr)
325346
machine = remote.RemoteMachine(reg.service_id, reg.hostname, display_hostname, ip_info, reg.port, self.service_ident, str(reg.api_version))
326-
if self.remote_registrar.register(machine.ident, machine.hostname, machine.ip_info, machine.port, auth_port, machine.api_version) == util.CertProcessingResult.FAILURE or self.server_thread_keepalive.is_set():
347+
if self.remote_registrar.register(machine.ident, machine.hostname, machine.ip_info, machine.port, reg.auth_port, machine.api_version) == util.CertProcessingResult.FAILURE or self.server_thread_keepalive.is_set():
327348
logging.debug("Registration of static machine failed, ignoring remote %s (%s:%d) auth %d"
328-
% (machine.hostname, machine.ip_info.ip4_address, machine.port, auth_port))
349+
% (machine.hostname, machine.ip_info.ip4_address, machine.port, reg.auth_port))
329350
self.idle_emit("manual-connect-result", initiated_here, False, "Authentication failed")
330351
return
331352
self.remote_machines[machine.ident] = machine

src/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def __eq__(self, other):
223223

224224
if self.ip4_address is not None:
225225
return self.ip4_address == other.ip4_address
226-
if self.ip6_address == other.ip6_address:
226+
if self.ip6_address is not None:
227227
return self.ip6_address == other.ip6_address
228228
return False
229229

src/warpinator.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import qrcode
1212
from io import BytesIO
1313
import re
14+
import ipaddress
15+
import urllib
1416

1517
import gi
1618
gi.require_version('Gtk', '3.0')
@@ -1255,8 +1257,14 @@ def on_connection_result(self, result, msg):
12551257

12561258
def validate_address(self, entry):
12571259
address = entry.get_text()
1258-
m = self.ip_validator_re.match(address)
1259-
self.connect_button.set_sensitive(m is not None)
1260+
try:
1261+
if not address.startswith("warpinator://"):
1262+
address = "warpinator://%s" % address
1263+
url = urllib.parse.urlparse(address)
1264+
ipaddress.ip_address(url.hostname) # validate IPv4/IPv6 address
1265+
self.connect_button.set_sensitive(True)
1266+
except:
1267+
self.connect_button.set_sensitive(False)
12601268

12611269
class WarpApplication(Gtk.Application):
12621270
def __init__(self, testing=False):

0 commit comments

Comments
 (0)