# Copyright 2016 Splunk, Inc. # # Licensed under the Apache License, Version 2.0 (the 'License'): you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. ''' Net utilities. ''' import inspect import itertools import re import socket from functools import wraps from . import ip_math __all__ = ['resolve_hostname'] def resolve_hostname(addr): '''Try to resolve an IP to a host name and returns None on common failures. :param addr: IP address to resolve. :type addr: ``string`` :returns: Host name if success else None. :rtype: ``string`` :raises ValueError: If `addr` is not a valid address ''' if ip_math.is_valid_ip(addr): try: name, _, _ = socket.gethostbyaddr(addr) return name except socket.gaierror: # [Errno 8] nodename nor servname provided, or not known pass except socket.herror: # [Errno 1] Unknown host pass except socket.timeout: # Timeout. pass return None else: raise ValueError('Invalid ip address.') def is_valid_hostname(hostname): '''Validate a host name. :param hostname: host name to validate. :type hostname: ``string`` :returns: True if is valid else False :rtype: ``bool`` ''' if len(hostname) > 255: return False if hostname[-1:] == '.': hostname = hostname[:-1] allowed = re.compile('(?!-)[A-Z\d-]{1,63}(?<!-)$', re.IGNORECASE) return all(allowed.match(x) for x in hostname.split('.')) def is_valid_port(port): '''Validate a port. :param port: port to validate. :type port: ``(string, int)`` :returns: True if is valid else False :rtype: ``bool`` ''' try: return 0 < int(port) <= 65535 except ValueError: return False def is_valid_scheme(scheme): '''Validate a scheme. :param scheme: scheme to validate. :type scheme: ``string`` :returns: True if is valid else False :rtype: ``bool`` ''' return scheme.lower() in ('http', 'https') def check_css_params(**validators): '''A decorator for validating arguments for function with specified validating function which returns True or False. :param validators: argument and it's validation function :raises ValueError: If validation fails. ''' def decorator(f): @wraps(f) def wrapper(*args, **kwargs): arg_spec = inspect.getargspec(f) actual_args = dict(list(zip(arg_spec.args, args)) + list(kwargs.items())) dfs = arg_spec.defaults optional = dict(list(zip(arg_spec.args[-len(dfs):], dfs))) if dfs else {} for arg, func in list(validators.items()): if arg not in actual_args: continue value = actual_args[arg] if arg in optional and optional[arg] == value: continue if not func(value): raise ValueError( 'Illegal argument: {}={}'.format(arg, value)) return f(*args, **kwargs) return wrapper return decorator