#!/usr/bin/env python3 # # Copyright (C) 2018-2019 Maurice van der Pot <griffon26@kfk4ever.com> # # This file is part of taserver # # taserver is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # taserver is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with taserver. If not, see <http://www.gnu.org/licenses/>. # from gevent import socket from ipaddress import IPv4Address from typing import Optional import urllib.request as urlreq def _get_local_ip(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: # doesn't even have to be reachable s.connect(('10.255.255.255', 1)) ip = s.getsockname()[0] except: ip = '127.0.0.1' finally: s.close() return IPv4Address(ip) class IPAddressPair: def __init__(self, external_ip: Optional[IPv4Address], internal_ip: Optional[IPv4Address]): assert external_ip is not None or internal_ip is not None assert external_ip is None or external_ip.is_global assert internal_ip is None or internal_ip.is_private self.external_ip = external_ip self.internal_ip = internal_ip def validate_against_detected_address(self, detected_ip: IPv4Address): assert detected_ip == self.external_ip or detected_ip == self.internal_ip def get_address_seen_from(self, source_address_pair): if self.internal_ip is None: return self.external_ip elif (self.external_ip is None or source_address_pair.external_ip is None or self.external_ip == source_address_pair.external_ip): return self.internal_ip else: return self.external_ip def __str__(self): return '%s/%s' % (self.external_ip, self.internal_ip) @staticmethod def detect(): detection_error = None try: external_ip = IPv4Address(urlreq.urlopen('http://ipv4.icanhazip.com/').read().decode('utf8').strip()) except Exception as e: external_ip = None detection_error = str(e) if external_ip: assert external_ip.is_global internal_ip = _get_local_ip() if internal_ip == external_ip: internal_ip = None else: assert internal_ip.is_private return IPAddressPair(external_ip, internal_ip), detection_error