Onionr/onionr/onionrsockets.py

137 lines
4.7 KiB
Python
Raw Normal View History

'''
Onionr - P2P Anonymous Storage Network
Onionr Socket interface
'''
'''
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/>.
'''
2018-09-15 16:13:03 +00:00
import stem.control
import socket, selectors, socks, config
import onionrexceptions, time, onionrchat
2018-09-15 01:05:25 +00:00
from dependencies import secrets
2018-09-17 05:02:16 +00:00
sel = selectors.DefaultSelector()
2018-09-15 01:05:25 +00:00
class OnionrSockets:
2018-09-20 05:13:26 +00:00
def __init__(self, coreInst, socketInfo):
2018-09-15 01:05:25 +00:00
'''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
self._core = coreInst
2018-09-15 04:48:48 +00:00
self.socketInfo = socketInfo
2018-09-15 01:05:25 +00:00
# Make sure socketInfo provides all necessary values
2018-09-15 16:13:03 +00:00
for i in ('peer', 'address', 'create', 'port'):
2018-09-15 01:05:25 +00:00
try:
socketInfo[i]
except KeyError:
raise ValueError('Must provide peer, address, and create in socketInfo dict argument')
2018-09-15 04:48:48 +00:00
2018-09-15 16:13:03 +00:00
self.isServer = socketInfo['create'] # if we are the one creating the service
2018-09-15 04:48:48 +00:00
2018-09-15 16:13:03 +00:00
self.remotePeer = socketInfo['peer']
self.socketPort = socketInfo['port']
2018-09-15 04:48:48 +00:00
self.serverAddress = socketInfo['address']
2018-09-17 05:02:16 +00:00
self.connected = False
2018-09-15 16:13:03 +00:00
2018-09-20 05:13:26 +00:00
self.readData = []
2018-09-20 17:04:58 +00:00
self.sendData = 0
2018-09-20 05:13:26 +00:00
2018-09-20 17:04:58 +00:00
def startConn():
2018-09-15 16:13:03 +00:00
if self.isServer:
self.createServer()
else:
self.connectServer()
2018-09-15 04:48:48 +00:00
def createServer(self):
2018-09-15 16:13:03 +00:00
# Create our HS and advertise it via a block
dataID = uuid.uuid4().hex
ourAddress = ''
ourPort = 1337
ourInternalPort = 1338
# Setup the empheral HS
with stem.control.Controller.from_port() as controller:
controller.authenticate()
socketHS = controller.create_ephemeral_hidden_service({ourPort: ourInternalPort}, await_publication = True)
ourAddress = socketHS.service_id
2018-09-17 05:02:16 +00:00
# Advertise the server
meta = {'address': ourAddress, 'port': ourPort}
self._core.insertBlock(dataID, header='openSocket', encryptType='asym', asymPeer=self.remotePeer, sign=True, meta=meta)
# 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)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
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
2018-09-17 05:02:16 +00:00
def _read(self, conn, mask):
data = conn.recv(1024)
2018-09-17 05:02:16 +00:00
if data:
data = data.decode()
2018-09-20 05:13:26 +00:00
self.readData.append(data)
2018-09-17 05:02:16 +00:00
else:
sel.unregister(conn)
conn.close()
2018-09-20 05:13:26 +00:00
def sendData(self, data):
try:
data = data.encode()
except AttributeError:
pass
self.sendData = data
def readData(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)
2018-09-20 05:13:26 +00:00
if self.sendData != 0:
s.send(self.sendData)
self.sendData = 0
return