work on lan transport, added service discovery logic
This commit is contained in:
		
							parent
							
								
									a8290e2ac3
								
							
						
					
					
						commit
						7bb95c3b87
					
				
					 9 changed files with 223 additions and 0 deletions
				
			
		
							
								
								
									
										38
									
								
								src/lan/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/lan/__init__.py
									
										
									
									
									
										Normal 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() | ||||||
|  | 
 | ||||||
							
								
								
									
										23
									
								
								src/lan/client/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/lan/client/__init__.py
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										65
									
								
								src/lan/discover.py
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										19
									
								
								src/lan/getip.py
									
										
									
									
									
										Normal 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) | ||||||
|  | 
 | ||||||
							
								
								
									
										18
									
								
								src/lan/server/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/lan/server/__init__.py
									
										
									
									
									
										Normal 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/>. | ||||||
|  | """ | ||||||
|  | @ -36,6 +36,7 @@ from utils.bettersleep import better_sleep | ||||||
| from netcontroller.torcontrol.onionservicecreator import create_onion_service | from netcontroller.torcontrol.onionservicecreator import create_onion_service | ||||||
| from .quotes import QUOTE | from .quotes import QUOTE | ||||||
| from utils.boxprint import bordered | from utils.boxprint import bordered | ||||||
|  | from lan import LANManager | ||||||
| """ | """ | ||||||
|     This program is free software: you can redistribute it and/or modify |     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 |     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('init', threaded=False) | ||||||
|     events.event('daemon_start') |     events.event('daemon_start') | ||||||
|  |     LANManager(shared_state).start() | ||||||
|     communicator.startCommunicator(shared_state) |     communicator.startCommunicator(shared_state) | ||||||
| 
 | 
 | ||||||
|     clean_ephemeral_services() |     clean_ephemeral_services() | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								tests/integration-tests/test_lan_discover.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								tests/integration-tests/test_lan_discover.py
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										23
									
								
								tests/test_get_lan_ips.py
									
										
									
									
									
										Normal 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() | ||||||
							
								
								
									
										0
									
								
								tests/test_lan_server_thread.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								tests/test_lan_server_thread.py
									
										
									
									
									
										Normal file
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue