1
0
mirror of https://github.com/dkmstr/openuds.git synced 2024-12-23 17:34:17 +03:00

fixed tunnel to allow sending to broker connection stats on termination

This commit is contained in:
Adolfo Gómez García 2021-01-25 11:12:10 +01:00
parent c796f5aaac
commit 50660d92e5
4 changed files with 53 additions and 24 deletions

View File

@ -11,7 +11,7 @@
# * Redistributions in binary form must reproduce the above copyright notice, # * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation # this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution. # and/or other materials provided with the distribution.
# * Neither the name of Virtual Cable S.L. nor the names of its contributors # * Neither the name of Virtual Cable S.L.U. nor the names of its contributors
# may be used to endorse or promote products derived from this software # may be used to endorse or promote products derived from this software
# without specific prior written permission. # without specific prior written permission.
# #
@ -31,9 +31,9 @@
""" """
import logging import logging
import typing import typing
from uds.models.user_service import UserService
from uds import models from uds import models
from uds.core import managers
from uds.REST import Handler from uds.REST import Handler
from uds.REST import AccessDenied from uds.REST import AccessDenied
from uds.core.auths.auth import isTrustedSource from uds.core.auths.auth import isTrustedSource
@ -42,6 +42,7 @@ from uds.core.util.stats import events
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
MAX_SESSION_LENGTH = 60*60*24*7
# Enclosed methods under /tunnel path # Enclosed methods under /tunnel path
class Tunnel(Handler): class Tunnel(Handler):
@ -56,12 +57,12 @@ class Tunnel(Handler):
Processes get requests, currently none Processes get requests, currently none
""" """
logger.debug( logger.debug(
'Tunnel parameters for GET: %s from %s', self._args, self._request.ip 'Tunnel parameters for GET: %s (%s) from %s', self._args, self._params, self._request.ip
) )
if ( if (
not isTrustedSource(self._request.ip) not isTrustedSource(self._request.ip)
or len(self._args) > 2 or len(self._args) != 2
or len(self._args[0]) != 48 or len(self._args[0]) != 48
): ):
# Invalid requests # Invalid requests
@ -69,16 +70,22 @@ class Tunnel(Handler):
# Try to get ticket from DB # Try to get ticket from DB
try: try:
user, userService, host, port, _ = models.TicketStore.get_for_tunnel( user, userService, host, port, extra = models.TicketStore.get_for_tunnel(
self._args[0] self._args[0]
) )
start = len(self._args) == 2 # Start requests include source IP request
if net.ipToLong(self._args[1][:32]) == 0:
raise Exception('Invalid from IP')
data = {} data = {}
if start: if self._args[1][:4] == 'stop':
sent, recv = self._params['sent'], self._params['recv']
# Ensures extra exists...
extra = extra or {}
now = models.getSqlDatetimeAsUnix()
totalTime = now - extra.get('b', now-1)
msg = f'User {user.name} stopped tunnel {extra.get("t", "")[:8]}... to {host}:{port}: s:{sent}/r:{recv}/t:{totalTime}.'
log.doLog(user.manager, log.INFO, msg)
log.doLog(userService, log.INFO, msg)
else:
if net.ipToLong(self._args[1][:32]) == 0:
raise Exception('Invalid from IP')
events.addEvent( events.addEvent(
userService.deployed_service, userService.deployed_service,
events.ET_TUNNEL_ACCESS, events.ET_TUNNEL_ACCESS,
@ -87,10 +94,22 @@ class Tunnel(Handler):
dstip=host, dstip=host,
uniqueid=userService.unique_id, uniqueid=userService.unique_id,
) )
msg = f'User {user.name} started tunnel to {host}:{port} from {self._args[1]}.' msg = f'User {user.name} started tunnel {self._args[0][:8]}... to {host}:{port} from {self._args[1]}.'
log.doLog(user.manager, log.INFO, msg) log.doLog(user.manager, log.INFO, msg)
log.doLog(userService, log.INFO, msg) log.doLog(userService, log.INFO, msg)
data = {'host': host, 'port': port} # Generate new, notify only, ticket
rstr = managers.cryptoManager().randomString(length=8)
notifyTicket = models.TicketStore.create_for_tunnel(
userService=userService,
port=port,
host=host,
extra={'t': self._args[0], 'b': models.getSqlDatetimeAsUnix()},
validity=MAX_SESSION_LENGTH)
data = {
'host': host,
'port': port,
'notify': notifyTicket
}
return data return data
except Exception as e: except Exception as e:

View File

@ -57,4 +57,4 @@ COMMAND_LENGTH = 4
COMMAND_OPEN = b'OPEN' COMMAND_OPEN = b'OPEN'
COMMAND_TEST = b'TEST' COMMAND_TEST = b'TEST'
COMMAND_STAT = b'STAT' # full stats COMMAND_STAT = b'STAT' # full stats
COMMAND_INFO = b'INFO' # Basic stats COMMAND_INFO = b'INFO' # Basic stats, currently same as FULL

View File

@ -52,6 +52,19 @@ class Proxy:
self.cfg = cfg self.cfg = cfg
self.ns = ns self.ns = ns
@staticmethod
def _getUdsUrl(cfg: config.ConfigurationType, ticket: bytes, msg: str) -> typing.MutableMapping[str, typing.Any]:
try:
url = cfg.uds_server + '/' + ticket.decode() + '/' + msg
r = requests.get(url, headers={'content-type': 'application/json'})
if not r.ok:
raise Exception(r.content)
return r.json()
except Exception as e:
raise Exception(f'TICKET COMMS ERROR: {e!s}')
@staticmethod @staticmethod
def getFromUds( def getFromUds(
cfg: config.ConfigurationType, ticket: bytes, cfg: config.ConfigurationType, ticket: bytes,
@ -70,16 +83,12 @@ class Proxy:
continue # Correctus continue # Correctus
raise Exception(f'TICKET INVALID (char {i} at pos {n})') raise Exception(f'TICKET INVALID (char {i} at pos {n})')
try: return Proxy._getUdsUrl(cfg, ticket, address[0])
url = cfg.uds_server + '/' + ticket.decode() + '/' + address[0]
r = requests.get(url, headers={'content-type': 'application/json'})
if not r.ok:
raise Exception(r.content)
return r.json()
except Exception as e:
raise Exception(f'TICKET COMMS ERROR: {e!s}')
@staticmethod
def notifyEndToUds(cfg: config.ConfigurationType, ticket: bytes, counter: stats.Stats) -> None:
msg = f'stop?sent={counter.sent}&recv={counter.recv}'
Proxy._getUdsUrl(cfg, ticket, msg) # Ignore results
@staticmethod @staticmethod
async def doProxy(source, destination, counter: stats.StatsSingleCounter) -> None: async def doProxy(source, destination, counter: stats.StatsSingleCounter) -> None:
@ -194,6 +203,7 @@ class Proxy:
logger.debug('PROXIES READY') logger.debug('PROXIES READY')
logger.debug('Proxies finalized: %s', grp.exceptions) logger.debug('Proxies finalized: %s', grp.exceptions)
await curio.run_in_thread(Proxy.notifyEndToUds, self.cfg, result['notify'].encode(), counter)
except Exception as e: except Exception as e:
if consts.DEBUG: if consts.DEBUG:

View File

@ -4,7 +4,7 @@
# pidfile = /tmp/udstunnel.pid # pidfile = /tmp/udstunnel.pid
# Log level, valid are DEBUG, INFO, WARN, ERROR. Defaults to ERROR # Log level, valid are DEBUG, INFO, WARN, ERROR. Defaults to ERROR
loglevel = INFO loglevel = DEBUG
# Log file, Defaults to stdout # Log file, Defaults to stdout
# logfile = /tmp/tunnel.log # logfile = /tmp/tunnel.log