work on sockets
This commit is contained in:
parent
d3f4e912f9
commit
4e8f7e2761
@ -108,6 +108,8 @@ class OnionrCommunicatorDaemon:
|
|||||||
cleanupTimer.count = (cleanupTimer.frequency - 60)
|
cleanupTimer.count = (cleanupTimer.frequency - 60)
|
||||||
announceTimer.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
|
# Main daemon loop, mainly for calling timers, don't do any complex operations here to avoid locking
|
||||||
try:
|
try:
|
||||||
while not self.shutdown:
|
while not self.shutdown:
|
||||||
@ -467,31 +469,15 @@ class OnionrCommunicatorDaemon:
|
|||||||
elif cmd[0] == 'uploadBlock':
|
elif cmd[0] == 'uploadBlock':
|
||||||
self.blockToUpload = cmd[1]
|
self.blockToUpload = cmd[1]
|
||||||
threading.Thread(target=self.uploadBlock).start()
|
threading.Thread(target=self.uploadBlock).start()
|
||||||
elif cmd[0] == 'startSocket':
|
elif cmd[0] == 'addSocket':
|
||||||
# Create a socket or connect to one.
|
socketInfo = json.loads(cmd[1])
|
||||||
# The socket handler (such as the plugin or app using it) is specified in startData['reason]
|
if socketInfo['reason'] in ('chat'):
|
||||||
startData = json.loads(cmd[1])
|
onionrsockets.OnionrSocketClient(self._core, socketInfo['peer'])
|
||||||
threading.Thread(target=self.startSocket, args=(startData,)).start()
|
|
||||||
else:
|
else:
|
||||||
logger.info('Recieved daemonQueue command:' + cmd[0])
|
logger.info('Recieved daemonQueue command:' + cmd[0])
|
||||||
|
|
||||||
self.decrementThreadCount('daemonCommands')
|
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):
|
def uploadBlock(self):
|
||||||
'''Upload our block to a few peers'''
|
'''Upload our block to a few peers'''
|
||||||
# when inserting a block, we try to upload it to a few peers to add some deniability
|
# 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/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
'''
|
'''
|
||||||
import stem.control
|
import stem.control
|
||||||
import socket, selectors, socks, config, uuid
|
import socks, config, uuid
|
||||||
import onionrexceptions, time, onionrchat
|
import onionrexceptions, time, requests
|
||||||
from dependencies import secrets
|
from dependencies import secrets
|
||||||
sel = selectors.DefaultSelector()
|
from flask import request, Response, abort
|
||||||
|
|
||||||
class OnionrSockets:
|
class OnionrSocketServer:
|
||||||
def __init__(self, coreInst, socketInfo):
|
def __init__(self, coreInst):
|
||||||
'''Create a new Socket object. This interface is named a bit misleadingly
|
self.sockets = {} # pubkey: tor address
|
||||||
and does not actually forward network requests.
|
self.connPool = {}
|
||||||
|
self.bindPort = 1337
|
||||||
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
|
|
||||||
self._core = coreInst
|
self._core = coreInst
|
||||||
self.socketInfo = socketInfo
|
self.responseData = {}
|
||||||
|
self.killSocket = False
|
||||||
|
app = flask.Flask(__name__)
|
||||||
|
|
||||||
# Make sure socketInfo provides all necessary values
|
http_server = WSGIServer((socket.service_id, bindPort), app)
|
||||||
for i in ('peer', 'address', 'create', 'port'):
|
http_server.serve_forever()
|
||||||
try:
|
|
||||||
socketInfo[i]
|
|
||||||
except KeyError:
|
|
||||||
raise ValueError('Must provide peer, address, and create in socketInfo dict argument')
|
|
||||||
|
|
||||||
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']
|
if request.host in self.connPool:
|
||||||
self.socketPort = socketInfo['port']
|
self.connPool[request.host].append(data)
|
||||||
self.serverAddress = socketInfo['address']
|
|
||||||
self.connected = False
|
|
||||||
|
|
||||||
self.readData = []
|
|
||||||
self.sendData = 0
|
|
||||||
config.reload()
|
|
||||||
|
|
||||||
def startConn(self):
|
|
||||||
if self.isServer:
|
|
||||||
self.createServer()
|
|
||||||
else:
|
else:
|
||||||
self.connectServer()
|
self.connPool[request.host] = [data]
|
||||||
|
|
||||||
def createServer(self):
|
retData = self.responseData[request.host]
|
||||||
# Create our HS and advertise it via a block
|
|
||||||
dataID = uuid.uuid4().hex
|
|
||||||
ourAddress = ''
|
|
||||||
ourPort = 1337
|
|
||||||
ourInternalPort = 1338
|
|
||||||
|
|
||||||
# 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:
|
with stem.control.Controller.from_port(port=config.get('tor.controlPort')) as controller:
|
||||||
controller.authenticate(config.get('tor.controlpassword'))
|
controller.authenticate(config.get('tor.controlpassword'))
|
||||||
socketHS = controller.create_ephemeral_hidden_service({ourPort: ourInternalPort}, await_publication = True)
|
|
||||||
ourAddress = socketHS.service_id
|
|
||||||
|
|
||||||
# Advertise the server
|
socket = controller.create_ephemeral_hidden_service({80: bindPort}, await_publication = True)
|
||||||
meta = {'address': ourAddress, 'port': ourPort}
|
self.sockets[peer] = socket.service_id
|
||||||
self._core.insertBlock(dataID, header='openSocket', encryptType='asym', asymPeer=self.remotePeer, sign=True, meta=meta)
|
|
||||||
|
|
||||||
# Build the socket server
|
self.responseData[socket.service_id] = ''
|
||||||
sock = socket.socket()
|
|
||||||
sock.bind(('127.0.0.1', ourInternalPort))
|
|
||||||
sock.listen(100)
|
|
||||||
sock.setblocking(False)
|
|
||||||
sel.register(sock, selectors.EVENT_READ, self._accept)
|
|
||||||
|
|
||||||
while True:
|
self._core.insertBlock(uuid.uuid4(), header='startSocket', sign=True, encryptType='asym', asymPeer=peer, meta={})
|
||||||
events = sel.select()
|
|
||||||
for key, mask in events:
|
|
||||||
callback = key.data
|
|
||||||
callback(key.fileobj, mask)
|
|
||||||
|
|
||||||
|
while not self.killSocket:
|
||||||
|
time.sleep(3)
|
||||||
return
|
return
|
||||||
|
|
||||||
def _accept(self, sock, mask):
|
class OnionrSocketClient:
|
||||||
# Just accept the connection and pass it to our handler
|
def __init__(self, coreInst):
|
||||||
conn, addr = sock.accept()
|
self.sockets = {} # pubkey: tor address
|
||||||
conn.setblocking(False)
|
self.connPool = {}
|
||||||
sel.register(conn, selectors.EVENT_READ, self._read)
|
self.bindPort = 1337
|
||||||
self.connected = True
|
self._core = coreInst
|
||||||
|
self.response = ''
|
||||||
|
self.request = ''
|
||||||
|
self.connected = False
|
||||||
|
|
||||||
def _read(self, conn, mask):
|
def getResponse(self, peer):
|
||||||
data = conn.recv(1024)
|
self._core._utils.doPostRequest(self.)
|
||||||
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
|
|
@ -91,7 +91,7 @@ def on_processBlocks(api):
|
|||||||
raise ValueError("Missing socket reason")
|
raise ValueError("Missing socket reason")
|
||||||
|
|
||||||
socketInfo = json.dumps({'peer': api.data['signer'], 'address': address, 'port': port, 'create': False, 'reason': 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):
|
def on_init(api, data = None):
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user