diff --git a/server/src/uds/REST/methods/actor.py b/server/src/uds/REST/methods/actor.py index f8945f1b..71d027aa 100644 --- a/server/src/uds/REST/methods/actor.py +++ b/server/src/uds/REST/methods/actor.py @@ -224,6 +224,7 @@ class Actor(Handler): try: res = service.getInstance().osmanager().process(service, message, data, options={'scramble': False}) except Exception as e: + logger.exception("Exception processing from OS Manager") return Actor.result(six.text_type(e), ERR_OSMANAGER_ERROR) return Actor.result(res) diff --git a/server/src/uds/REST/methods/client.py b/server/src/uds/REST/methods/client.py index 384cb1ec..6060d6c7 100644 --- a/server/src/uds/REST/methods/client.py +++ b/server/src/uds/REST/methods/client.py @@ -98,7 +98,7 @@ class Client(Handler): logger.debug("Client args for GET: {0}".format(self._args)) if len(self._args) == 0: # Gets version - url = self._request.build_absolute_uri(reverse('ClientDownload')) + url = self._request.build_absolute_uri(reverse('uds.web.views.client_downloads')) return Client.result({ 'availableVersion': CLIENT_VERSION, 'requiredVersion': REQUIRED_CLIENT_VERSION, diff --git a/server/src/uds/core/managers/UserServiceManager.py b/server/src/uds/core/managers/UserServiceManager.py index d891a871..08ec541c 100644 --- a/server/src/uds/core/managers/UserServiceManager.py +++ b/server/src/uds/core/managers/UserServiceManager.py @@ -51,7 +51,7 @@ import requests import json import logging -__updated__ = '2017-01-19' +__updated__ = '2017-01-20' logger = logging.getLogger(__name__) @@ -360,7 +360,10 @@ class UserServiceManager(object): UserServiceOpChecker.makeUnique(uService, ui, state) return False - def notifyPreconnect(self, uService, userName, protocol, proxy=None): + def notifyPreconnect(self, uService, userName, protocol): + + proxy = uService.deployed_service.proxy + url = uService.getCommsUrl() if url is None: logger.debug('No notification is made because agent does not supports notifications') @@ -371,25 +374,22 @@ class UserServiceManager(object): try: data = {'user': userName, 'protocol': protocol} if proxy is not None: - data = { - 'data': data, - 'url': url - } - - url = proxy.url - - r = requests.post(url, - data=json.dumps(data), - headers={'content-type': 'application/json'}, - verify=False, - timeout=2) + proxy.doProxyRequest(url=url, data=data, timeout=2) + else: + r = requests.post(url, + data=json.dumps(data), + headers={'content-type': 'application/json'}, + verify=False, + timeout=2) r = json.loads(r.content) logger.debug('Sent pre connection to client using {}: {}'.format(url, r)) # In fact we ignore result right now except Exception as e: logger.info('preConnection failed: {}. Check connection on destination machine: {}'.format(e, url)) - def checkUuid(self, uService, proxy=None): + def checkUuid(self, uService): + + proxy = uService.deployed_service.proxy url = uService.getCommsUrl() @@ -404,13 +404,7 @@ class UserServiceManager(object): try: if proxy is not None: - r = requests.post( - proxy.url, - data=json.dumps({'url': url}), - headers={'content-type': 'application/json'}, - verify=False, - timeout=5 - ) + proxy.doProxyRequest(url=url, data=None, timeout=5) else: r = requests.get( url, @@ -431,10 +425,12 @@ class UserServiceManager(object): return True - def sendScript(self, uService, script, proxy=None): + def sendScript(self, uService, script): ''' If allowed, send script to user service ''' + proxy = uService.deployed_service.proxy + # logger.debug('Senging script: {}'.format(script)) url = uService.getCommsUrl() if url is None: @@ -445,20 +441,15 @@ class UserServiceManager(object): try: data = {'script': script} if proxy is not None: - data = { - 'data': data, - 'url': url - } - - url = proxy.url - - r = requests.post( - url, - data=json.dumps(data), - headers={'content-type': 'application/json'}, - verify=False, - timeout=5 - ) + proxy.doProxyRequest(url=url, data=data, timeout=5) + else: + r = requests.post( + url, + data=json.dumps(data), + headers={'content-type': 'application/json'}, + verify=False, + timeout=5 + ) r = json.loads(r.content) logger.debug('Sent script to client using {}: {}'.format(url, r)) # In fact we ignore result right now diff --git a/server/src/uds/core/transports/BaseTransport.py b/server/src/uds/core/transports/BaseTransport.py index fa869693..34ad95ce 100644 --- a/server/src/uds/core/transports/BaseTransport.py +++ b/server/src/uds/core/transports/BaseTransport.py @@ -42,7 +42,7 @@ from uds.core.util import connection import six import logging -__updated__ = '2017-01-19' +__updated__ = '2017-01-20' logger = logging.getLogger(__name__) @@ -108,10 +108,13 @@ class Transport(Module): ''' pass - def testServer(self, userService, ip, port): + def testServer(self, userService, ip, port, timeout=4): # TODO: Add Proxy support here # GET URL = proxy.../testService?ip=xxxxx&port=yyy&timeout=zzzz - return connection.testServer(ip, six.text_type(port)) + proxy = userService.deployed_service.proxy + if proxy is not None: + return proxy.doTestServer(ip, port, timeout) + return connection.testServer(ip, six.text_type(port), timeout) def isAvailableFor(self, userService, ip): diff --git a/server/src/uds/models/Proxy.py b/server/src/uds/models/Proxy.py index 180fb511..5b5c806a 100644 --- a/server/src/uds/models/Proxy.py +++ b/server/src/uds/models/Proxy.py @@ -37,9 +37,9 @@ from django.db import models from uds.models.UUIDModel import UUIDModel from uds.models.Tag import TaggingMixin -from uds.models.Util import getSqlDatetime -from django.db.models import signals +import requests +import json import logging logger = logging.getLogger(__name__) @@ -63,5 +63,49 @@ class Proxy(UUIDModel, TaggingMixin): db_table = 'uds_proxies' app_label = 'uds' + @property + def url(self): + return 'http{}://{}:{}'.format('s' if self.ssl is True else '', self.host, self.port) + + @property + def proxyRequestUrl(self): + return self.url + "/proxyRequest" + + @property + def testServerUrl(self): + return self.url + "/testServer" + + def doProxyRequest(self, url, data=None, timeout=5): + d = { + 'url': url + } + if data is not None: + d['data'] = data + + return requests.post( + self.proxyRequestUrl, + data=json.dumps(d), + headers={'content-type': 'application/json'}, + verify=False, + timeout=timeout + ) + + + def doTestServer(self, ip, port, timeout=5): + try: + url = self.testServerUrl + '?host={}&port={}&timeout={}'.format(ip, port, timeout) + r = requests.get( + url, + timeout=timeout + 1 + ) + if r.status_code == 302: # Proxy returns "Found" for a success test + return True + # Else returns 404 + except Exception: + logger.exception("Getting service state through proxy") + + return False + + def __unicode__(self): return 'Proxy {} on {}:{} '.format(self.name, self.host, self.port) diff --git a/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py b/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py index e09ffe02..e7728ad9 100644 --- a/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py +++ b/server/src/uds/osmanagers/LinuxOsManager/LinuxOsManager.py @@ -145,6 +145,12 @@ class LinuxOsManager(osmanagers.OSManager): notifyReady = False doRemove = False state = userService.os_state + if msg in ('ready', 'ip'): + if not isinstance(data, dict): # Old actors, previous to 2.5, convert it information.. + data = { + 'ips': [v.split('=') for v in data.split(',')], + 'hostname': userService.friendly_name + } # Old "info" state, will be removed in a near future if msg == "info": @@ -166,11 +172,6 @@ class LinuxOsManager(osmanagers.OSManager): doRemove = True elif msg == "ip": # This ocurss on main loop inside machine, so userService is usable - if not isinstance(data, dict): # Old actors, previous to 2.5, convert it information.. - data = { - 'ips': [v.split('=') for v in data.split(',')], - 'hostname': userService.friendly_name - } state = State.USABLE self.notifyIp(userService.unique_id, userService, data) elif msg == "ready": diff --git a/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py b/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py index 8ea1f87a..2346236a 100644 --- a/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py +++ b/server/src/uds/osmanagers/WindowsOsManager/WindowsOsManager.py @@ -149,6 +149,14 @@ class WindowsOsManager(osmanagers.OSManager): * msg = ready, data = None, Informs machine ready to be used ''' logger.info("Invoked WindowsOsManager for {0} with params: {1},{2}".format(userService, msg, data)) + + if msg in ('ready', 'ip'): + if not isinstance(data, dict): # Old actors, previous to 2.5, convert it information.. + data = { + 'ips': [v.split('=') for v in data.split(',')], + 'hostname': userService.friendly_name + } + # We get from storage the name for this userService. If no name, we try to assign a new one ret = "ok" notifyReady = False @@ -179,11 +187,6 @@ class WindowsOsManager(osmanagers.OSManager): doRemove = True elif msg == "ip": # This ocurss on main loop inside machine, so userService is usable - if not isinstance(data, dict): # Old actors, previous to 2.5 - data = { - 'ips': [v.split('=') for v in data.split(',')], - 'hostname': userService.friendly_name - } state = State.USABLE self.notifyIp(userService.unique_id, userService, data) elif msg == "ready": diff --git a/udsProxy/daemonize.txt b/udsProxy/daemonize.txt new file mode 100644 index 00000000..6587a987 --- /dev/null +++ b/udsProxy/daemonize.txt @@ -0,0 +1 @@ +sudo daemonize -p /var/run/udsproxy.pid -l /var/lock/subsys/udsproxy -u nobody /home/dkmaster/projects/uds/openuds/udsProxy/bin/udsproxy diff --git a/udsProxy/src/uds/udsProxy/udsProxy.go b/udsProxy/src/uds/udsproxy/udsproxy.go similarity index 63% rename from udsProxy/src/uds/udsProxy/udsProxy.go rename to udsProxy/src/uds/udsproxy/udsproxy.go index 59b3a0f7..af4299df 100644 --- a/udsProxy/src/uds/udsProxy/udsProxy.go +++ b/udsProxy/src/uds/udsproxy/udsproxy.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "crypto/tls" "encoding/json" "errors" "fmt" @@ -9,6 +10,8 @@ import ( "log" "net" "net/http" + "os" + "os/signal" "strconv" "strings" "time" @@ -19,21 +22,26 @@ import ( const configFilename = "/etc/udsproxy.cfg" var config struct { - Server string // Server Type, "http" or "https" - Port string // Server port - SSLCertificateFile string // Certificate file - SSLCertificateKeyFile string // Certificate key - Broker string // Broker address - UseSSL bool // If use https for connecting with broker: Warning, certificate must be valid on Broker + Server string // Server Type, "http" or "https" + Port string // Server port + SSLCertificateFile string // Certificate file + SSLCertificateKeyFile string // Certificate key + Broker string // Broker address + AllowFrom []string // Allow BROKER requests from this IPS + UseSSL bool // If use https for connecting with broker: Warning, certificate must be valid on Broker + IgnoreCertificates bool // If true, will ignore certificates (when requesting) } func validOrigin(w http.ResponseWriter, r *http.Request) error { - if strings.Split(r.RemoteAddr, ":")[0] != config.Broker { - w.WriteHeader(http.StatusForbidden) - fmt.Fprintf(w, "Access denied") - return errors.New("Invalid Origin") + ip := strings.Split(r.RemoteAddr, ":")[0] + for _, v := range config.AllowFrom { + if v == ip { + return nil + } } - return nil + w.WriteHeader(http.StatusForbidden) + fmt.Fprintf(w, "Access denied") + return errors.New("Invalid Origin") } // Test service @@ -43,8 +51,8 @@ func testService(w http.ResponseWriter, r *http.Request) { } r.ParseForm() - ip, port, timeOutStr := r.FormValue("ip"), r.FormValue("port"), r.FormValue("timeout") - if ip == "" || port == "" { + host, port, timeOutStr := r.FormValue("host"), r.FormValue("port"), r.FormValue("timeout") + if host == "" || port == "" { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "Invalid arguments") return @@ -55,8 +63,8 @@ func testService(w http.ResponseWriter, r *http.Request) { timeOut, _ := strconv.Atoi(timeOutStr) - fmt.Println("Args: ", ip, port) - con, err := net.DialTimeout("tcp", ip+":"+port, time.Duration(timeOut)*time.Second) + fmt.Println("Args: ", host, port) + con, err := net.DialTimeout("tcp", host+":"+port, time.Duration(timeOut)*time.Second) if err == nil { con.Close() @@ -86,7 +94,7 @@ func proxyRequest(w http.ResponseWriter, r *http.Request) { if err := dec.Decode(&body); err != nil { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "Error in Json: %s", err) - log.Fatal(err) + log.Printf("Error decoding json: %s", err) return } @@ -104,24 +112,36 @@ func proxyRequest(w http.ResponseWriter, r *http.Request) { if err != nil { w.WriteHeader(http.StatusBadRequest) fmt.Fprintf(w, "Error building request: %s", err) + log.Printf("Error building request: %s", err) return } req.Header.Set("Content-Type", "application/json") + // Ignore Certificate + tr := &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: config.IgnoreCertificates}, + } + client := &http.Client{ - Timeout: time.Duration(5) * time.Second, + Timeout: time.Duration(5) * time.Second, + Transport: tr, } resp, err := client.Do(req) if err != nil { w.WriteHeader(http.StatusInternalServerError) + log.Printf("The connection failed %s", err) fmt.Fprintf(w, "Error in POST: %s", err) return } + defer resp.Body.Close() // Ensures closes response w.WriteHeader(resp.StatusCode) b, _ := ioutil.ReadAll(resp.Body) + + log.Printf("Response: %d, %s", resp.StatusCode, b) + w.Write(b) } @@ -145,7 +165,7 @@ func main() { cfg, err := ini.Load(configFilename) if err != nil { - log.Fatal(err) + log.Fatal(err) // Fatal calss exit } // Default config values config.Port = "9090" @@ -153,13 +173,26 @@ func main() { // Read config cfg.MapTo(&config) - log.Printf("Broker address: %s", config.Broker) + log.Printf("Broker: %s", config.Broker) log.Printf("Server type: %s", config.Server) log.Printf("Server port: %s", config.Port) + log.Printf("Allow Access from: %s", config.AllowFrom) + + // Handle signals + // we make a buffered channel to do not loose signal + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, os.Kill) + go func() { + for range c { + fmt.Print("Got Ending signal") + os.Exit(0) + } + }() http.HandleFunc("/actor", actor) // set router for "actor" requests - http.HandleFunc("/testService", testService) // test service + http.HandleFunc("/testServer", testService) // test service http.HandleFunc("/proxyRequest", proxyRequest) // Proxy request from broker to service + if config.Server == "https" { err = http.ListenAndServeTLS(":"+config.Port, config.SSLCertificateFile, config.SSLCertificateKeyFile, nil) // set listen port } else { @@ -167,8 +200,7 @@ func main() { } if err != nil { - log.Fatal("ListenAndServe: ", err) - return + log.Fatal("ListenAndServe: ", err) // Fatal calls exit } } diff --git a/udsProxy/udsproxy.cfg b/udsProxy/udsproxy.cfg new file mode 100644 index 00000000..f85b64ff --- /dev/null +++ b/udsProxy/udsproxy.cfg @@ -0,0 +1,9 @@ +Server = http +Port = 9090 +SSLCertificateFile = /etc/ssl/certs/ssl-cert-snakeoil.pem +SSLCertificateKeyFile = /etc/ssl/private/ssl-cert-snakeoil.key + +IgnoreCertificates = True + +Broker = https://172.27.0.1:8000 +AllowFrom = 172.27.0.1, 127.27.0.8