work on lan transport, added service discovery logic

This commit is contained in:
Kevin Froman 2020-03-11 04:46:42 -05:00
parent a8290e2ac3
commit 7bb95c3b87
9 changed files with 223 additions and 0 deletions

38
src/lan/__init__.py Normal file
View File

@ -0,0 +1,38 @@
"""Onionr - Private P2P Communication.
LAN manager
"""
from typing import TYPE_CHECKING
from threading import Thread
if TYPE_CHECKING:
from toomanyobjs import TooMany
from . import server
from .client import Client
from .discover import learn_services, advertise_service
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
class LANManager:
"""Initialize and start/top LAN transport threads."""
def __init__(self, too_many: "TooMany"):
self.too_many = too_many
def start(self):
Thread(target=learn_services, daemon=True).start()
Thread(target=advertise_service, daemon=True).start()

View File

@ -0,0 +1,23 @@
"""Onionr - Private P2P Communication.
LAN transport client thread
"""
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
class Client:
def __init__(self):
return

65
src/lan/discover.py Normal file
View File

@ -0,0 +1,65 @@
"""Onionr - Private P2P Communication.
Discover and publish private-network
"""
import socket
import struct
from .getip import lan_ips
from utils.bettersleep import better_sleep
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
MCAST_GRP = '224.13.3.7'
MCAST_PORT = 1337
IS_ALL_GROUPS = True
ANNOUNCE_LOOP_SLEEP = 30
def learn_services():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
# on this port, receives ALL multicast groups
sock.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
sock.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
rec_data = sock.recv(1024)
print('reced_data', rec_data)
sock.shutdown()
sock.close()
def advertise_service():
# regarding socket.IP_MULTICAST_TTL
# ---------------------------------
# for all packets sent, after three hops on the network the packet will not
# be re-sent/broadcast (see https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html)
MULTICAST_TTL = 3
ips = '-'.join(lan_ips)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
while True:
sock.sendto(f"onionr-{ips}".encode('utf-8'), (MCAST_GRP, MCAST_PORT))
better_sleep(ANNOUNCE_LOOP_SLEEP)
sock.shutdown()
sock.close()

19
src/lan/getip.py Normal file
View File

@ -0,0 +1,19 @@
from ipaddress import IPv4Address
from ifaddr import get_adapters
lan_ips = []
for adapter in get_adapters():
for ip in adapter.ips:
ip = ip.ip
try:
ip = IPv4Address(ip)
if not ip.is_private or ip.is_loopback:
raise ValueError
except ValueError:
# Raised if not ipv4 or not link local
continue
else:
lan_ips.append(ip.exploded)

View File

@ -0,0 +1,18 @@
"""Onionr - Private P2P Communication.
LAN transport server thread
"""
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""

View File

@ -36,6 +36,7 @@ from utils.bettersleep import better_sleep
from netcontroller.torcontrol.onionservicecreator import create_onion_service
from .quotes import QUOTE
from utils.boxprint import bordered
from lan import LANManager
"""
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -162,6 +163,7 @@ def daemon():
events.event('init', threaded=False)
events.event('daemon_start')
LANManager(shared_state).start()
communicator.startCommunicator(shared_state)
clean_ephemeral_services()

View File

@ -0,0 +1,35 @@
from unittest.mock import patch
import sys, os
sys.path.append(".")
sys.path.append("src/")
import unittest, uuid
TEST_DIR = 'testdata/%s-%s' % (uuid.uuid4(), os.path.basename(__file__)) + '/'
print("Test directory:", TEST_DIR)
os.environ["ONIONR_HOME"] = TEST_DIR
from utils import createdirs
from onionrcommands import parser
import onionrsetup as setup
from netcontroller.torcontrol import customtorrc
from utils import createdirs
from onionrsetup import setup_config, setup_default_plugins
from coredb import blockmetadb
from etc.onionrvalues import BLOCK_EXPORT_FILE_EXT
from threading import Thread
createdirs.create_dirs()
setup_config()
setup_default_plugins()
import config
from filepaths import export_location
class OnionrTests(unittest.TestCase):
def test_lan_discover(self):
testargs = ['onionr.py', 'start']
with patch.object(sys, 'argv', testargs):
try:
Thread(target=parser.register, daemon=True).start()
except SystemExit:
pass
unittest.main()

23
tests/test_get_lan_ips.py Normal file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env python3
import sys, os
sys.path.append(".")
sys.path.append("src/")
import uuid
import ipaddress
TEST_DIR = 'testdata/%s-%s' % (uuid.uuid4(), os.path.basename(__file__)) + '/'
print("Test directory:", TEST_DIR)
os.environ["ONIONR_HOME"] = TEST_DIR
import unittest
from lan.getip import lan_ips
class TestGetLanIps(unittest.TestCase):
def test_get_lan_ips(self):
self.assertGreater(len(lan_ips), 0)
for ip in lan_ips:
ip = ipaddress.IPv4Address(ip)
if not ip.is_private or ip.is_multicast or ip.is_reserved:
raise ValueError
unittest.main()

View File