2017-06-09 20:41:33 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import base64
|
|
|
|
import logging
|
|
|
|
import os
|
|
|
|
import socket
|
2017-06-11 07:55:53 +02:00
|
|
|
import time
|
2017-06-09 20:41:33 +02:00
|
|
|
|
2021-08-02 19:05:23 +02:00
|
|
|
from .util import I2PThread, pub_from_priv
|
2017-06-09 20:41:33 +02:00
|
|
|
|
|
|
|
|
2021-08-02 19:05:23 +02:00
|
|
|
class I2PController(I2PThread):
|
2021-03-09 15:40:59 +01:00
|
|
|
def __init__(self, state, host='127.0.0.1', port=7656, dest_priv=b''):
|
2023-07-30 00:05:08 +02:00
|
|
|
super().__init__(state, name='I2P Controller')
|
2017-06-09 20:41:33 +02:00
|
|
|
|
|
|
|
self.host = host
|
|
|
|
self.port = port
|
|
|
|
self.nick = b'MiNode_' + base64.b16encode(os.urandom(4)).lower()
|
|
|
|
|
2017-08-23 18:29:07 +02:00
|
|
|
while True:
|
2023-08-10 02:52:16 +02:00
|
|
|
if state.shutting_down:
|
|
|
|
return
|
2017-08-23 18:29:07 +02:00
|
|
|
try:
|
|
|
|
self.s = socket.create_connection((self.host, self.port))
|
|
|
|
break
|
|
|
|
except ConnectionRefusedError:
|
2021-03-08 16:06:07 +01:00
|
|
|
logging.error(
|
|
|
|
'Error while connecting to I2P SAM bridge. Retrying.')
|
2017-08-23 18:29:07 +02:00
|
|
|
time.sleep(10)
|
2017-06-09 20:41:33 +02:00
|
|
|
|
|
|
|
self.version_reply = []
|
|
|
|
|
|
|
|
self.init_connection()
|
|
|
|
|
|
|
|
if dest_priv:
|
|
|
|
self.dest_priv = dest_priv
|
|
|
|
self.dest_pub = pub_from_priv(dest_priv)
|
|
|
|
else:
|
|
|
|
self.dest_priv = b''
|
|
|
|
self.dest_pub = b''
|
|
|
|
self.generate_destination()
|
|
|
|
|
|
|
|
self.create_session()
|
|
|
|
|
|
|
|
def init_connection(self):
|
|
|
|
self._send(b'HELLO VERSION MIN=3.0 MAX=3.3\n')
|
|
|
|
self.version_reply = self._receive_line().split()
|
|
|
|
assert b'RESULT=OK' in self.version_reply
|
|
|
|
|
|
|
|
def generate_destination(self):
|
|
|
|
if b'VERSION=3.0' in self.version_reply:
|
|
|
|
# We will now receive old DSA_SHA1 destination :(
|
|
|
|
self._send(b'DEST GENERATE\n')
|
|
|
|
else:
|
|
|
|
self._send(b'DEST GENERATE SIGNATURE_TYPE=EdDSA_SHA512_Ed25519\n')
|
|
|
|
|
|
|
|
reply = self._receive_line().split()
|
|
|
|
for par in reply:
|
|
|
|
if par.startswith(b'PUB='):
|
|
|
|
self.dest_pub = par.replace(b'PUB=', b'')
|
|
|
|
if par.startswith(b'PRIV='):
|
|
|
|
self.dest_priv = par.replace(b'PRIV=', b'')
|
|
|
|
assert self.dest_priv
|
|
|
|
|
|
|
|
def create_session(self):
|
2021-03-09 15:40:59 +01:00
|
|
|
self._send(
|
|
|
|
b'SESSION CREATE STYLE=STREAM ID=' + self.nick
|
|
|
|
+ b' inbound.length=' + str(self.state.i2p_tunnel_length).encode()
|
|
|
|
+ b' outbound.length=' + str(self.state.i2p_tunnel_length).encode()
|
|
|
|
+ b' DESTINATION=' + self.dest_priv + b'\n')
|
2017-06-09 20:41:33 +02:00
|
|
|
reply = self._receive_line().split()
|
2017-06-11 07:55:53 +02:00
|
|
|
if b'RESULT=OK' not in reply:
|
|
|
|
logging.warning(reply)
|
2021-03-08 16:06:07 +01:00
|
|
|
logging.warning(
|
|
|
|
'We could not create I2P session, retrying in 5 seconds.')
|
2017-06-11 07:55:53 +02:00
|
|
|
time.sleep(5)
|
|
|
|
self.create_session()
|
2017-06-09 20:41:33 +02:00
|
|
|
|
|
|
|
def run(self):
|
|
|
|
self.s.settimeout(1)
|
|
|
|
while True:
|
2021-03-09 15:40:59 +01:00
|
|
|
if not self.state.shutting_down:
|
2017-06-09 20:41:33 +02:00
|
|
|
try:
|
|
|
|
msg = self._receive_line().split(b' ')
|
|
|
|
if msg[0] == b'PING':
|
|
|
|
self._send(b'PONG ' + msg[1] + b'\n')
|
|
|
|
except socket.timeout:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
logging.debug('Shutting down I2P Controller')
|
|
|
|
self.s.close()
|
|
|
|
break
|