#!/usr/bin/python2

from subprocess import check_output
import json
import sys
import re

COLLECTOR_VERSION_KEY = "collector_version"
COLLECTOR_VERSION = 1

def is_valid_ipv4(ip):
    """Validates IPv4 addresses.
    """
    pattern = re.compile(r"""
        ^
        (?:
          # Dotted variants:
          (?:
            # Decimal 1-255 (no leading 0's)
            [3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
          |
            0x0*[0-9a-f]{1,2}  # Hexadecimal 0x0 - 0xFF (possible leading 0's)
          |
            0+[1-3]?[0-7]{0,2} # Octal 0 - 0377 (possible leading 0's)
          )
          (?:                  # Repeat 0-3 times, separated by a dot
            \.
            (?:
              [3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
            |
              0x0*[0-9a-f]{1,2}
            |
              0+[1-3]?[0-7]{0,2}
            )
          ){0,3}
        |
          0x0*[0-9a-f]{1,8}    # Hexadecimal notation, 0x0 - 0xffffffff
        |
          0+[0-3]?[0-7]{0,10}  # Octal notation, 0 - 037777777777
        |
          # Decimal notation, 1-4294967295:
          429496729[0-5]|42949672[0-8]\d|4294967[01]\d\d|429496[0-6]\d{3}|
          42949[0-5]\d{4}|4294[0-8]\d{5}|429[0-3]\d{6}|42[0-8]\d{7}|
          4[01]\d{8}|[1-3]\d{0,9}|[4-9]\d{0,8}
        )
        $
    """, re.VERBOSE | re.IGNORECASE)
    return pattern.match(ip) is not None

def is_valid_ipv6(ip):
    """Validates IPv6 addresses.
    """
    pattern = re.compile(r"""
        ^
        \s*                         # Leading whitespace
        (?!.*::.*::)                # Only a single whildcard allowed
        (?:(?!:)|:(?=:))            # Colon iff it would be part of a wildcard
        (?:                         # Repeat 6 times:
            [0-9a-f]{0,4}           #   A group of at most four hexadecimal digits
            (?:(?<=::)|(?<!::):)    #   Colon unless preceeded by wildcard
        ){6}                        #
        (?:                         # Either
            [0-9a-f]{0,4}           #   Another group
            (?:(?<=::)|(?<!::):)    #   Colon unless preceeded by wildcard
            [0-9a-f]{0,4}           #   Last group
            (?: (?<=::)             #   Colon iff preceeded by exacly one colon
             |  (?<!:)              #
             |  (?<=:) (?<!::) :    #
             )                      # OR
         |                          #   A v4 address with NO leading zeros 
            (?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
            (?: \.
                (?:25[0-4]|2[0-4]\d|1\d\d|[1-9]?\d)
            ){3}
        )
        \s*                         # Trailing whitespace
        $
    """, re.VERBOSE | re.IGNORECASE | re.DOTALL)
    return pattern.match(ip) is not None

def is_valid_ip(ip):
    """Validates IP addresses.
    """
    return is_valid_ipv4(ip) or is_valid_ipv6(ip)

def execWebAPI(api, version, method, **kwargs):
    cmd = ["/usr/syno/bin/synowebapi", "--exec"]
    cmd.append("api=" + api)
    cmd.append("version=" + str(version))
    cmd.append("method=" + method)
    for key, val in kwargs.items():
        cmd.append('{0}={1}'.format(key, json.dumps(val)))
    try:
        with open('/dev/null', 'w') as null_fp:
            raw_resp = check_output(cmd, stderr=null_fp)
        return json.loads(raw_resp)
    except Exception as e:
        return False

def blacklist_get():
    output = {
        "deny_single_ip": 0
    }

    j_blacklist = execWebAPI('SYNO.Core.Security.AutoBlock.Rules', 1, 'list', offset=0, limit=-1, type='deny')
    if not j_blacklist:
        return output

    try:
        blacklist = j_blacklist['data']['ip_info']
        output['deny_single_ip'] = len(blacklist)
    except Exception as e:
        pass

    return output

def whitelist_get():
    output = {
        "allow_single_ip": 0,
        "allow_domain": 0,
        "allow_subnet": 0,
        "allow_iprange": 0
    }

    j_whilelist = execWebAPI('SYNO.Core.Security.AutoBlock.Rules', 1, 'list', offset=0, limit=-1, type='allow')
    if not j_whilelist:
        return output

    try:
        whilelist = j_whilelist['data']['ip_info']
        for r in whilelist:
            ip = r['ip'];
            if '~' in ip:
                output['allow_iprange'] += 1
            elif '/' in ip:
                output['allow_subnet'] += 1
            elif is_valid_ipv4(ip):
                output['allow_single_ip'] += 1
            else:
                output['allow_domain'] += 1
    except Exception as e:
        pass

    return output

def setting_get():
    output = {
        "enable": False,
        "attempts": 0,
        "expire_day": 0,
        "within_mins": 0
    }

    j_setting = execWebAPI('SYNO.Core.Security.AutoBlock', 1, 'get')
    if not j_setting:
        return output

    try:
        output['enable'] = j_setting['data']['enable']
        output['attempts'] = j_setting['data']['attempts']
        output['expire_day'] = j_setting['data']['expire_day']
        output['within_mins'] = j_setting['data']['within_mins']
    except Exception as e:
        pass

    return output

def main():
    ''' Result output
    {
        "setting":
        {
            "enable": Boolean,
            "attempts": Int,
            "expire_day": Int,
            "within_mins": Int
        },
        "blacklist":
        {
            "deny_single_ip": Int
        },
        "whitelist":
        {
            "allow_single_ip": Int,
            "allow_domain": Int,
            "allow_subnet": Int,
            "allow_iprange": Int
        },
        COLLECTOR_VERSION_KEY: COLLECTOR_VERSION
    }
    '''
    result = {
        COLLECTOR_VERSION_KEY: COLLECTOR_VERSION,
        'setting': {
            "enable": False,
            "attempts": 0,
            "expire_day": 0,
            "within_mins": 0
        },
        'blacklist': {
            "deny_single_ip": 0
        },
        'whitelist': {
            "allow_single_ip": 0,
            "allow_domain": 0,
            "allow_subnet": 0,
            "allow_iprange": 0
        }
    }

    result['setting'] = setting_get()
    result['blacklist'] = blacklist_get()
    result['whitelist'] = whitelist_get()
    sys.stdout.write(json.dumps(result))

if __name__ == '__main__':
    main()
