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,
# this list of conditions and the following disclaimer in the documentation
# 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
# without specific prior written permission.
#
@ -31,9 +31,9 @@
"""
import logging
import typing
from uds.models.user_service import UserService
from uds import models
from uds.core import managers
from uds.REST import Handler
from uds.REST import AccessDenied
from uds.core.auths.auth import isTrustedSource
@ -42,6 +42,7 @@ from uds.core.util.stats import events
logger = logging.getLogger(__name__)
MAX_SESSION_LENGTH = 60*60*24*7
# Enclosed methods under /tunnel path
class Tunnel(Handler):
@ -56,12 +57,12 @@ class Tunnel(Handler):
Processes get requests, currently none
"""
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 (
not isTrustedSource(self._request.ip)
or len(self._args) > 2
or len(self._args) != 2
or len(self._args[0]) != 48
):
# Invalid requests
@ -69,16 +70,22 @@ class Tunnel(Handler):
# Try to get ticket from DB
try:
user, userService, host, port, _ = models.TicketStore.get_for_tunnel(
user, userService, host, port, extra = models.TicketStore.get_for_tunnel(
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 = {}
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(
userService.deployed_service,
events.ET_TUNNEL_ACCESS,
@ -87,10 +94,22 @@ class Tunnel(Handler):
dstip=host,
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(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
except Exception as e:

View File

@ -57,4 +57,4 @@ COMMAND_LENGTH = 4
COMMAND_OPEN = b'OPEN'
COMMAND_TEST = b'TEST'
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.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
def getFromUds(
cfg: config.ConfigurationType, ticket: bytes,
@ -70,16 +83,12 @@ class Proxy:
continue # Correctus
raise Exception(f'TICKET INVALID (char {i} at pos {n})')
try:
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}')
return Proxy._getUdsUrl(cfg, ticket, address[0])
@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
async def doProxy(source, destination, counter: stats.StatsSingleCounter) -> None:
@ -194,6 +203,7 @@ class Proxy:
logger.debug('PROXIES READY')
logger.debug('Proxies finalized: %s', grp.exceptions)
await curio.run_in_thread(Proxy.notifyEndToUds, self.cfg, result['notify'].encode(), counter)
except Exception as e:
if consts.DEBUG:

View File

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