Only work for the first refresh...

This commit is contained in:
nicolargo 2022-08-07 17:43:11 +02:00
parent 712cd67581
commit 296c3fd2a0
4 changed files with 135 additions and 12 deletions

View File

@ -175,6 +175,17 @@ tx_critical=90
[ip]
disable=False
public_refresh_interval=300
public_ip_disabled=False
# Configuration for the Censys online service
# Need to create an aacount: https://censys.io/login
censys_url=https://search.censys.io/api
# Get your own credential here: https://search.censys.io/account/api
# Enter and uncomment the following lines to use your credentials
censys_username=13718bd6-b0c4-4c21-ae63-2d13da0b2dd8
censys_password=hnjdSOukHM84tgx1Oo9Zzv4Pmz2E5bXH
# List of fields to be displayed in user interface (comma separated)
censys_fields=location:continent,location:country,autonomous_system:name
[connections]
# Display additional information about TCP connections

View File

@ -17,12 +17,29 @@ file under the ``[ip]`` section:
.. code-block:: ini
[ip]
public_refresh_interval=240
public_refresh_interval=300
public_ip_disabled=True
**NOTE:** Setting low values for `public_refresh_interval` will result in frequent
HTTP requests to the IP detection servers. Recommended range: 120-600 seconds
If the Censys options are configured, the public IP address is also analysed (with the same interval)
and additional information is displayed.
.. code-block:: ini
[ip]
public_refresh_interval=300
public_ip_disabled=True
censys_url=https://search.censys.io/api
# Get your own credential here: https://search.censys.io/account/api
censys_username=CENSYS_API_ID
censys_password=CENSYS_API_SECRET
# List of fields to be displayed in user interface (comma separated)
censys_fields=location:continent,location:country,autonomous_system:name
**Note:** Access to the Censys Search API need an account (https://censys.io/login).
**Connected**:
.. image:: ../_static/connected.png

View File

@ -31,7 +31,7 @@ if PY3:
from statistics import mean
from xmlrpc.client import Fault, ProtocolError, ServerProxy, Transport, Server
from xmlrpc.server import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
from urllib.request import urlopen
from urllib.request import Request, urlopen, base64
from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
@ -126,7 +126,7 @@ else:
from ConfigParser import SafeConfigParser as ConfigParser, NoOptionError, NoSectionError
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer
from xmlrpclib import Fault, ProtocolError, ServerProxy, Transport, Server
from urllib2 import urlopen, HTTPError, URLError
from urllib2 import Request, urlopen, HTTPError, URLError, base64
from urlparse import urlparse
# Correct issue #1025 by monkey path the xmlrpc lib

View File

@ -10,6 +10,7 @@
"""IP plugin."""
import threading
import urllib
from json import loads
from glances.compat import iterkeys, urlopen, queue
@ -65,6 +66,13 @@ class Plugin(GlancesPlugin):
public_ip_disabled = self.get_conf_value("public_ip_disabled", default=self._default_public_ip_disabled)
self.public_ip_disabled = True if public_ip_disabled == ["True"] else False
# For the Censys options (see issue #2105)
self.public_info = ""
self.censys_url = self.get_conf_value("censys_url", default=[None])[0]
self.censys_username = self.get_conf_value("censys_username", default=[None])[0]
self.censys_password = self.get_conf_value("censys_password", default=[None])[0]
self.censys_fields = self.get_conf_value("censys_fields", default=[None])
@GlancesPlugin._check_decorator
@GlancesPlugin._log_result_decorator
def update(self):
@ -77,30 +85,53 @@ class Plugin(GlancesPlugin):
if self.input_method == 'local' and not import_error_tag:
# Update stats using the netifaces lib
# Start with the default IP gateway
try:
default_gw = netifaces.gateways()['default'][netifaces.AF_INET]
except (KeyError, AttributeError) as e:
logger.debug("Cannot grab the default gateway ({})".format(e))
logger.debug("Cannot grab default gateway IP address ({})".format(e))
return {}
else:
stats['gateway'] = default_gw[0]
# Then the private IP address
try:
address = netifaces.ifaddresses(default_gw[1])[netifaces.AF_INET][0]['addr']
mask = netifaces.ifaddresses(default_gw[1])[netifaces.AF_INET][0]['netmask']
time_since_update = getTimeSinceLastUpdate('public-ip')
if not self.public_ip_disabled and (
self.stats.get('address') != address or time_since_update > self.public_address_refresh_interval
):
self.public_address = PublicIpAddress().get()
except (KeyError, AttributeError) as e:
logger.debug("Cannot grab IP information: {}".format(e))
logger.debug("Cannot grab private IP address ({})".format(e))
return {}
else:
stats['address'] = address
stats['mask'] = mask
stats['mask_cidr'] = self.ip_to_cidr(stats['mask'])
stats['gateway'] = default_gw[0]
# Continue with the public IP address
time_since_update = getTimeSinceLastUpdate('public-ip')
try:
if not self.public_ip_disabled and (
self.stats.get('address') != address
or time_since_update > self.public_address_refresh_interval
):
self.public_address = PublicIpAddress().get()
except (KeyError, AttributeError) as e:
logger.debug("Cannot grab public IP address ({})".format(e))
else:
stats['public_address'] = self.public_address
# Finally the Censys information
if (
self.public_address
and not self.public_ip_disabled
and (self.stats.get('address') != address
or time_since_update > self.public_address_refresh_interval)
):
self.public_info = PublicIpInfo(self.public_address,
self.censys_url,
self.censys_username,
self.censys_password).get()
stats['public_info'] = self.public_info
elif self.input_method == 'snmp':
# Not implemented yet
pass
@ -151,6 +182,14 @@ class Plugin(GlancesPlugin):
msg = ' Pub '
ret.append(self.curse_add_line(msg, 'TITLE'))
ret.append(self.curse_add_line(msg_pub))
if 'public_info' in self.stats:
for f in self.censys_fields:
field = f.split(':')
if len(field) == 1 and field[0] in self.stats['public_info']:
msg = '{}'.format(self.stats['public_info'][field[0]])
elif len(field) == 2 and field[0] in self.stats['public_info'] and field[1] in self.stats['public_info'][field[0]]:
msg = '{}'.format(self.stats['public_info'][field[0]][field[1]])
ret.append(self.curse_add_line(msg))
return ret
@ -211,3 +250,59 @@ class PublicIpAddress(object):
queue_target.put(loads(response)[key])
except ValueError:
queue_target.put(None)
class PublicIpInfo(object):
"""Get public IP information from Censys online service."""
def __init__(self, ip, url, username, password, timeout=2):
"""Init the class."""
self.ip = ip
self.url = url
self.username = username
self.password = password
self.timeout = timeout
def get(self):
"""Return the public IP information returned by one of the online service."""
q = queue.Queue()
t = threading.Thread(target=self._get_ip_public_info, args=(q,
self.ip,
self.url,
self.username,
self.password))
t.daemon = True
t.start()
timer = Timer(self.timeout)
info = None
while not timer.finished() and info is None:
if q.qsize() > 0:
info = q.get()
if info is None:
return None
return info
def _get_ip_public_info(self, queue_target, ip, url, username, password):
"""Request the url service and put the result in the queue_target."""
request_url = "{}/v2/hosts/{}".format(url, ip)
try:
# Python 3 code only
# https://stackoverflow.com/questions/24635064/how-to-use-urllib-with-username-password-authentication-in-python-3/24648149#24648149
request = urllib.request.Request(request_url)
base64string = urllib.request.base64.b64encode(bytes('%s:%s' % (username, password), 'ascii'))
request.add_header("Authorization", "Basic %s" % base64string.decode('utf-8'))
result = urllib.request.urlopen(request)
response = result.read()
except Exception as e:
logger.debug("IP plugin - Cannot open URL {} ({})".format(request_url, e))
queue_target.put(None)
else:
try:
queue_target.put(loads(response)['result'])
except (ValueError, KeyError) as e:
logger.debug("IP plugin - Cannot get result field from {} ({})".format(request_url, e))
queue_target.put(None)