work on sockets
parent
d3f4e912f9
commit
4e8f7e2761
|
@ -108,6 +108,8 @@ class OnionrCommunicatorDaemon:
|
|||
cleanupTimer.count = (cleanupTimer.frequency - 60)
|
||||
announceTimer.count = (cleanupTimer.frequency - 60)
|
||||
|
||||
self.socketServer = onionrsockets.OnionrSocketServer(self._core)
|
||||
|
||||
# Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking
|
||||
try:
|
||||
while not self.shutdown:
|
||||
|
@ -467,31 +469,15 @@ class OnionrCommunicatorDaemon:
|
|||
elif cmd[0] == 'uploadBlock':
|
||||
self.blockToUpload = cmd[1]
|
||||
threading.Thread(target=self.uploadBlock).start()
|
||||
elif cmd[0] == 'startSocket':
|
||||
# Create a socket or connect to one.
|
||||
# The socket handler (such as the plugin or app using it) is specified in startData['reason]
|
||||
startData = json.loads(cmd[1])
|
||||
threading.Thread(target=self.startSocket, args=(startData,)).start()
|
||||
elif cmd[0] == 'addSocket':
|
||||
socketInfo = json.loads(cmd[1])
|
||||
if socketInfo['reason'] in ('chat'):
|
||||
onionrsockets.OnionrSocketClient(self._core, socketInfo['peer'])
|
||||
else:
|
||||
logger.info('Recieved daemonQueue command:' + cmd[0])
|
||||
|
||||
self.decrementThreadCount('daemonCommands')
|
||||
|
||||
def startSocket(self, startData):
|
||||
# Start a socket client
|
||||
mySocket = onionrsockets.OnionrSockets(self._core, startData)
|
||||
self.sockets[mySocket.socketID] = mySocket
|
||||
|
||||
sockProgram = '' # Function for socket handler (application)
|
||||
|
||||
if startData['reason'] == 'chat':
|
||||
sockProgram = onionrchat.OnionrChat
|
||||
else:
|
||||
del self.sockets[mySocket.socketID] # Delete socket if we have no handler for it
|
||||
|
||||
threading.Thread(target=sockProgram, args=(self, mySocket.socketID)).start()
|
||||
mySocket.startConn()
|
||||
|
||||
def uploadBlock(self):
|
||||
'''Upload our block to a few peers'''
|
||||
# when inserting a block, we try to upload it to a few peers to add some deniability
|
||||
|
|
|
@ -18,121 +18,68 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
'''
|
||||
import stem.control
|
||||
import socket, selectors, socks, config, uuid
|
||||
import onionrexceptions, time, onionrchat
|
||||
import socks, config, uuid
|
||||
import onionrexceptions, time, requests
|
||||
from dependencies import secrets
|
||||
sel = selectors.DefaultSelector()
|
||||
from flask import request, Response, abort
|
||||
|
||||
class OnionrSockets:
|
||||
def __init__(self, coreInst, socketInfo):
|
||||
'''Create a new Socket object. This interface is named a bit misleadingly
|
||||
and does not actually forward network requests.
|
||||
|
||||
Accepts coreInst, an instance of Onionr core library, and socketInfo, a dict with these values:
|
||||
'peer': peer master public key
|
||||
'address': string, if we're connecting to a socket, this is the address we connect to. Not applicable if we're creating our own
|
||||
create: bool
|
||||
'''
|
||||
self.socketID = secrets.token_hex(32) # Generate an ID for this socket
|
||||
class OnionrSocketServer:
|
||||
def __init__(self, coreInst):
|
||||
self.sockets = {} # pubkey: tor address
|
||||
self.connPool = {}
|
||||
self.bindPort = 1337
|
||||
self._core = coreInst
|
||||
self.socketInfo = socketInfo
|
||||
self.responseData = {}
|
||||
self.killSocket = False
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
# Make sure socketInfo provides all necessary values
|
||||
for i in ('peer', 'address', 'create', 'port'):
|
||||
try:
|
||||
socketInfo[i]
|
||||
except KeyError:
|
||||
raise ValueError('Must provide peer, address, and create in socketInfo dict argument')
|
||||
http_server = WSGIServer((socket.service_id, bindPort), app)
|
||||
http_server.serve_forever()
|
||||
|
||||
self.isServer = socketInfo['create'] # if we are the one creating the service
|
||||
@app.route('/dc/', methods=['POST'])
|
||||
def acceptConn(self):
|
||||
data = request.form['data']
|
||||
data = self._core._utils.bytesTorStr(data)
|
||||
|
||||
self.remotePeer = socketInfo['peer']
|
||||
self.socketPort = socketInfo['port']
|
||||
self.serverAddress = socketInfo['address']
|
||||
self.connected = False
|
||||
|
||||
self.readData = []
|
||||
self.sendData = 0
|
||||
config.reload()
|
||||
|
||||
def startConn(self):
|
||||
if self.isServer:
|
||||
self.createServer()
|
||||
if request.host in self.connPool:
|
||||
self.connPool[request.host].append(data)
|
||||
else:
|
||||
self.connectServer()
|
||||
self.connPool[request.host] = [data]
|
||||
|
||||
def createServer(self):
|
||||
# Create our HS and advertise it via a block
|
||||
dataID = uuid.uuid4().hex
|
||||
ourAddress = ''
|
||||
ourPort = 1337
|
||||
ourInternalPort = 1338
|
||||
retData = self.responseData[request.host]
|
||||
|
||||
# Setup the empheral HS
|
||||
self.responseData[request.host] = ''
|
||||
|
||||
return retData
|
||||
|
||||
def setResponseData(self, host, data):
|
||||
self.responseData[host] = data
|
||||
|
||||
def addSocket(self, peer):
|
||||
bindPort = 1337
|
||||
with stem.control.Controller.from_port(port=config.get('tor.controlPort')) as controller:
|
||||
controller.authenticate(config.get('tor.controlpassword'))
|
||||
socketHS = controller.create_ephemeral_hidden_service({ourPort: ourInternalPort}, await_publication = True)
|
||||
ourAddress = socketHS.service_id
|
||||
|
||||
# Advertise the server
|
||||
meta = {'address': ourAddress, 'port': ourPort}
|
||||
self._core.insertBlock(dataID, header='openSocket', encryptType='asym', asymPeer=self.remotePeer, sign=True, meta=meta)
|
||||
socket = controller.create_ephemeral_hidden_service({80: bindPort}, await_publication = True)
|
||||
self.sockets[peer] = socket.service_id
|
||||
|
||||
# Build the socket server
|
||||
sock = socket.socket()
|
||||
sock.bind(('127.0.0.1', ourInternalPort))
|
||||
sock.listen(100)
|
||||
sock.setblocking(False)
|
||||
sel.register(sock, selectors.EVENT_READ, self._accept)
|
||||
self.responseData[socket.service_id] = ''
|
||||
|
||||
while True:
|
||||
events = sel.select()
|
||||
for key, mask in events:
|
||||
callback = key.data
|
||||
callback(key.fileobj, mask)
|
||||
self._core.insertBlock(uuid.uuid4(), header='startSocket', sign=True, encryptType='asym', asymPeer=peer, meta={})
|
||||
|
||||
while not self.killSocket:
|
||||
time.sleep(3)
|
||||
return
|
||||
|
||||
def _accept(self, sock, mask):
|
||||
# Just accept the connection and pass it to our handler
|
||||
conn, addr = sock.accept()
|
||||
conn.setblocking(False)
|
||||
sel.register(conn, selectors.EVENT_READ, self._read)
|
||||
self.connected = True
|
||||
class OnionrSocketClient:
|
||||
def __init__(self, coreInst):
|
||||
self.sockets = {} # pubkey: tor address
|
||||
self.connPool = {}
|
||||
self.bindPort = 1337
|
||||
self._core = coreInst
|
||||
self.response = ''
|
||||
self.request = ''
|
||||
self.connected = False
|
||||
|
||||
def _read(self, conn, mask):
|
||||
data = conn.recv(1024)
|
||||
if data:
|
||||
data = data.decode()
|
||||
self.readData.append(data)
|
||||
else:
|
||||
sel.unregister(conn)
|
||||
conn.close()
|
||||
|
||||
def addSendData(self, data):
|
||||
try:
|
||||
data = data.encode()
|
||||
except AttributeError:
|
||||
pass
|
||||
self.sendData = data
|
||||
|
||||
def getReadData(self):
|
||||
try:
|
||||
data = self.readData.pop(0)
|
||||
except IndexError:
|
||||
data = ''
|
||||
return data
|
||||
|
||||
def connectServer(self):
|
||||
# Set the Tor proxy
|
||||
socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', config.get('tor.socksport'), rdns=True)
|
||||
socket.socket = socks.socksocket
|
||||
remoteSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
with remoteSocket as s:
|
||||
s.connect((self.serverAddress, self.port))
|
||||
data = s.recv(1024)
|
||||
if self.sendData != 0:
|
||||
s.send(self.sendData)
|
||||
self.sendData = 0
|
||||
return
|
||||
def getResponse(self, peer):
|
||||
self._core._utils.doPostRequest(self.)
|
|
@ -91,7 +91,7 @@ def on_processBlocks(api):
|
|||
raise ValueError("Missing socket reason")
|
||||
|
||||
socketInfo = json.dumps({'peer': api.data['signer'], 'address': address, 'port': port, 'create': False, 'reason': reason})
|
||||
api.get_core().daemonQueueAdd('startSocket', socketInfo)
|
||||
api.get_core().daemonQueueAdd('addSocket', socketInfo)
|
||||
|
||||
def on_init(api, data = None):
|
||||
|
||||
|
|
Loading…
Reference in New Issue