����JFIF��x�x����'403WebShell
403Webshell
Server IP : 78.140.185.180  /  Your IP : 216.73.216.82
Web Server : LiteSpeed
System : Linux cpanel13.v.fozzy.com 4.18.0-513.11.1.lve.el8.x86_64 #1 SMP Thu Jan 18 16:21:02 UTC 2024 x86_64
User : builderbox ( 1072)
PHP Version : 7.3.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /opt/cloudlinux/venv/lib64/python3.11/site-packages/cl_plus/utils/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/cloudlinux/venv/lib64/python3.11/site-packages/cl_plus/utils//web_server_helper.py
# coding=utf-8
#
# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2020 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENCE.TXT
#

import logging
import glob
import os
from traceback import format_exc
from lxml import etree  # NOQA
from clcommon.utils import run_command, ExternalProgramFailed, grep, is_litespeed_running
from clcommon.cpapi import get_apache_ports_list, get_apache_connections_number, get_apache_max_request_workers


class WebServerHelper:
    """
    Helper class for apache/Litespeed collector.
    """
    APACHE_NAME = 'httpd'
    LITESPEED_NAME = 'litespeed'

    def __init__(self, _logger: logging.Logger):
        self._logger = _logger
        self._web_ports_list = []
        self._is_apache = False
        self._is_litespeed = False
        self._netstat_bin = '/bin/netstat'
        self._no_server_message = 'There is no server working at 80 port'
        self._lsws_config = '/usr/local/lsws/conf/httpd_config.xml'
        self._is_server_absent_logged = False
        self.detect_active_server()

    def get_total_connections(self):
        """
        Get web server total connections (from web server config)
        :return: tuple (max_req_num, message)
            max_req_num - Maximum request apache workers number or 0 if error
            message - OK/Error text
        """
        if self._is_apache:
            return get_apache_max_request_workers()
        elif self._is_litespeed:
            return self._get_ls_total_connections()
        else:
            return 0, self._no_server_message

    def get_current_connections_number(self):
        """
        Retrieves web server's current connections number from system netstat utility
        :return: tuple (conn_num, message)
            conn_num - current connections number
            message - OK/Error text
        """
        # Read apache ports list. Litespeed uses apache's config, so this method works for both servers
        _httpd_ports_list = get_apache_ports_list()
        if self._is_litespeed:
            port_offset, message = self._get_ls_apache_port_offset()
            if message == "OK":
                _httpd_ports_list = [port + port_offset for port in _httpd_ports_list]
            else:
                return 0, message
        return self._get_current_connections_number_from_netstat(_httpd_ports_list)

    def get_connections_number(self):
        """
        Retrieves web server connections number (from apache's mod_status or analog mechanism)
        :return: tuple (conn_num, message)
            conn_num - current connections number, 0 if error
            message - OK/Error text
        """
        if self._is_apache:
            return get_apache_connections_number()
        elif self._is_litespeed:
            return self._get_ls_get_connections_number()
        else:
            return 0, self._no_server_message

    def detect_active_server(self):
        """
        Determine is httpd/Litespeed running
        :return: True/False running/not running
        """
        main_server_name = self._get_main_web_server_name()
        if not main_server_name:
            # Apache/Litespeed not working
            self._is_apache = False
            self._is_litespeed = False
            if not self._is_server_absent_logged:
                self._logger.info("Apache/Litespeed collector: Apache or Litespeed stopped or absent, collector will not work")
                self._is_server_absent_logged = True
            return False
        self._is_server_absent_logged = False
        self._web_ports_list = get_apache_ports_list()
        # Both httpd and litespeed working, select by port
        if main_server_name == self.LITESPEED_NAME:
            if not self._is_litespeed:
                self._logger.info("Apache/Litespeed collector: Using Litespeed")
            self._is_litespeed = True
            self._is_apache = False
        elif main_server_name == self.APACHE_NAME:
            if not self._is_apache:
                self._logger.info("Apache/Litespeed collector: Using Apache")
            self._is_apache = True
            self._is_litespeed = False
        return self._is_apache or self._is_litespeed

    def _get_current_connections_number_from_netstat(self, ports_list):
        """
        Retrieves web server's current connections number from system netstat utility
        :param ports_list: Port list to search
        :return: tuple (conn_num, message)
            conn_num - current connections number
            message - OK/Error text
        """
        # Build grep line, for example ':80|:443'
        _grep_ports_line = '|'.join([':{}'.format(val) for val in ports_list])
        # /bin/netstat -nt | egrep ':80|:443' | wc -l
        try:
            # /bin/netstat -nt
            cmd_list = [self._netstat_bin, '-nt']
            std_out = run_command(cmd_list)
            std_out_list = std_out.split('\n')
            out_list = list(grep(_grep_ports_line, match_any_position=True, multiple_search=True,
                                 data_from_file=std_out_list))
            return len(out_list), 'OK'
        except ExternalProgramFailed:
            return 0, format_exc()

    def _get_ls_total_connections(self):
        """
        Retrieve litespeed total connection number (from config)
        :return: tuple (max_conn, message)
            max_conn - Litespeed's total connection number or 0 if error
            message - OK/Trace
        """
        try:
            # grep "maxConnections" /usr/local/lsws/conf/httpd_config.xml
            # XML path httpServerConfig/tuning/maxConnections
            with open(self._lsws_config) as f:
                x = etree.parse(f).getroot()
                element_list = x.xpath("tuning/maxConnections")
                max_conn = element_list[0].text
                return int(max_conn), "OK"
        except (OSError, IOError, IndexError, ValueError, etree.XMLSyntaxError, etree.XMLSchemaParseError,
                etree.XMLSchemaError):
            return 0, format_exc()

    def _get_ls_get_connections_number(self):
        """
        Retrieve litespeed connections number (from LS statistics)
        :return: tuple (max_conn, message)
            max_conn - Litespeed's connections number or 0 if error
            message - OK/Trace
        """
        try:
            con_num = 0
            # ls -la /tmp/lshttpd/.rtr*
            ls_status_files_list = glob.glob('/tmp/lshttpd/.rtreport*')
            # ['/tmp/lshttpd/.rtreport.2', '/tmp/lshttpd/.rtreport']
            for ls_filename in ls_status_files_list:
                if not os.path.isfile(os.path.realpath(ls_filename)):
                    self._logger.warning('Skipping %s, because symlink does not point to real file',
                                         ls_filename)
                    continue
                con_num += self._get_connections_num_from_ls_temp_file(ls_filename)
            return con_num, "OK"
        except (OSError, IOError, ValueError):
            return 0, format_exc()

    @staticmethod
    def _get_connections_num_from_ls_temp_file(ls_temp_filename: str):
        """
        Retrieve connections number from litespeed's plain text answer
        :param ls_temp_filename: string with litespeed;s answer
        :return: tuple (conn_num, message)
            conn_num - current connections number, 0 if error
        """
        with open(ls_temp_filename, 'r') as content_file:
            content = content_file.read()
        # content example:
        # VERSION: LiteSpeed Web Server/Enterprise/5.4.9
        # UPTIME: 1 day 17:41:40
        # BPS_IN: 0, BPS_OUT: 0, SSL_BPS_IN: 0, SSL_BPS_OUT: 0
        # MAXCONN: 10000, MAXSSL_CONN: 10000, PLAINCONN: 0, AVAILCONN: 9999, IDLECONN: 0, SSLCONN: 1, AVAILSSL: 9999
        # REQ_RATE []: REQ_PROCESSING: 1, REQ_PER_SEC: 0.0, TOT_REQS: 54997, PUB_CACHE_HITS_PER_SEC: 0.0, TOTAL_PUB_CACHE_HITS: 0, PRIVATE_CACHE_HITS_PER_SEC: 0.0, TOTAL_PRIVATE_CACHE_HITS: 0, STATIC_HITS_PER_SEC: 0.0, TOTAL_STATIC_HITS: 50018
        # REQ_RATE [_AdminVHost]: REQ_PROCESSING: 1, REQ_PER_SEC: 0.0, TOT_REQS: 4989, PUB_CACHE_HITS_PER_SEC: 0.0, TOTAL_PUB_CACHE_HITS: 0, PRIVATE_CACHE_HITS_PER_SEC: 0.0, TOTAL_PRIVATE_CACHE_HITS: 0, STATIC_HITS_PER_SEC: 0.0, TOTAL_STATIC_HITS: 10
        # BLOCKED_IP:
        # EOF
        # Extract and return TOT_REQS metric value
        lines_list = content.split('\n')
        empty_rrate_lines = list(grep('REQ_RATE []:', fixed_string=True, match_any_position=False,
                                      multiple_search=True, data_from_file=lines_list))
        for line in empty_rrate_lines:
            line = line.strip()
            # line example:
            # REQ_RATE []: REQ_PROCESSING: 0, REQ_PER_SEC: 0.0, TOT_REQS: 50448, ....
            l_parts = line.split(',')
            # Search 'TOT_REQS' parameter
            for l_part in l_parts:
                # l_part example: ' REQ_PER_SEC: 0.0'
                l_part = l_part.strip()
                if l_part.startswith('TOT_REQS:'):
                    return int(l_part.replace('TOT_REQS:', '').strip())
        return 0

    def _get_main_web_server_name(self):
        """
        Detects main web server (httpd or litespeed)
        :return: Name - Main server name: 'litespeed', 'httpd', None
        """
        if is_litespeed_running():
            return self.LITESPEED_NAME
        try:
            # /sbin/service httpd status
            # retcode != 0 - litespeed/httpd not running
            #         == 0 - litespeed/httpd running
            # if 'litespeed' present in stdout - this is litespeed
            # else                             - httpd
            returncode, _, _ = run_command(['/sbin/service', 'httpd', 'status'], return_full_output=True)
            if returncode != 0:
                return None
            return self.APACHE_NAME
        except ExternalProgramFailed:
            pass
        return None

    def _get_ls_apache_port_offset(self):
        """
        Get Apache port offset for Litespeed
        There are several cases to handle:
         - port is defined in config
           <apachePortOffset>1234</apachePortOffset> => offset = 1234
         - parameter is absent in config => offset = 0
         - parameter is empty => offset = 0
         - errors while reading config => offset = 0
        """
        offset = 0
        try:
            # grep "apachePortOffset" /usr/local/lsws/conf/httpd_config.xml
            # XML path httpServerConfig/apachePortOffset
            with open(self._lsws_config) as f:
                x = etree.parse(f).getroot()
                element_list = x.xpath("apachePortOffset")
                if element_list:
                    offset = element_list[0].text or 0
                return int(offset), "OK"
        except (OSError,
                IOError,
                IndexError,
                ValueError,
                etree.XMLSyntaxError,
                etree.XMLSchemaParseError,
                etree.XMLSchemaError):
            return 0, format_exc()

Youez - 2016 - github.com/yon3zu
LinuXploit