work on sockets

master
Kevin Froman 2018-09-20 23:47:40 -05:00
parent d3f4e912f9
commit 4e8f7e2761
4 changed files with 56 additions and 123 deletions

View File

@ -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

View File

@ -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

View File

@ -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):