def __init__(self): self.host = getenv("HOST_ADDRESS") self.port = 443 self.key = getenv("FAUXAPI_KEY") self.secret = getenv("FAUXAPI_SECRET") try: PfsenseFauxapi(f"{self.host}:{self.port}", self.key, self.secret) except PfsenseFauxapiException as e: print(f"error: {str(e)}") else: self.pfapi = PfsenseFauxapi(f"{self.host}:{self.port}", self.key, self.secret)
def main(): print('Starting PfSense Parental Control App') print('Finding LAN devices') devices = find_devices() print('Finding Rule Overides') overrides = get_overrides() print('Finding blocked users') blocked = find_blocked(devices, overrides) print('Resolving IP addresses') blocked_ip = [[build_descr(b), devices.get(b['MAC'])] for b in blocked] print("Configuring Faux API") api = PfsenseFauxapi(PFSENSE_HOST, apikey, apisecret) api.proto = 'http' print("Requesting config") current_block_rules, default_rules = get_rules(api) current_block_ip = dict( (r['descr'], r['source']['address']) for r in current_block_rules) new_rules = build_new_rules(blocked_ip, current_block_ip) new_patch = create_filter_rule_patch(new_rules + default_rules) pprint.pprint(new_patch) print("patching") api.config_patch(new_patch) api.function_call({ 'function': 'filter_configure_sync', 'args': [False], 'includes': ['shaper.inc'], })
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._fapi = PfsenseFauxapi( self.config['api_host'], self.config['key'], self.config['secret'], )
def update(self): """Check the current state of the rule in pfSense""" import pprint, sys from PfsenseFauxapi.PfsenseFauxapi import PfsenseFauxapi _LOGGER.debug("Getting pfSense current rule state for %s", self._rule_name) try: # Setup connection with devices/cloud FauxapiLib = PfsenseFauxapi(self._host, self._api_key, self._access_token, debug=True) # Get the current set of filters filters = FauxapiLib.config_get('filter') for rule in filters['rule']: if (rule.get('tracker') == self._tracker_id): _LOGGER.debug( "Found rule with tracker %s, updating state.", self._tracker_id) if ('disabled' in rule): self._state = False else: self._state = True except: _LOGGER.error( "Problem retrieving rule set from pfSense host: %s. Likely due to API key or secret.", self._host)
def __init__(self, fauxapi_host, fauxapi_apikey, fauxapi_apisecret, debug=False): self.FauxapiLib = PfsenseFauxapi(fauxapi_host, fauxapi_apikey, fauxapi_apisecret, debug)
def test_config_get(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "b905cb4ef8db8", "action": "config_get", "message": "ok", "data": { "config": {"version": "18.9", "lastchange": "", "system": {}} }}' response = fauxapi.config_get() assert response['version'] == '18.9'
def test_fauxapi_not_installed(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 404 with pytest.raises(Exception) as exception_info: fauxapi.config_get() assert 'Unable to find FauxAPI on target host' in str(exception_info.value)
def setup_platform(hass, config, add_entities, discovery_info=None): """Initialize the platform""" """Setup the pfSense Rules platform.""" import pprint, sys from PfsenseFauxapi.PfsenseFauxapi import PfsenseFauxapi # Assign configuration variables. The configuration check takes care they are # present. host = config.get(CONF_HOST) api_key = config.get(CONF_API_KEY) access_token = config.get(CONF_ACCESS_TOKEN) rule_prefix = config.get(CONF_RULE_FILTER) _LOGGER.debug( "Connecting to pfSense firewall to collect rules to add as switches.") try: FauxapiLib = PfsenseFauxapi(host, api_key, access_token, debug=True) # Get the current set of filters filters = FauxapiLib.config_get('filter') _LOGGER.debug("Found %s rules in pfSense", len(filters['rule'])) if rule_prefix: _LOGGER.debug("Filter for rules starting with %s being applied", rule_prefix) rules = [] # Iterate through and find rules i = 0 for rule in filters['rule']: tracker = rule.get('tracker') if tracker == None: _LOGGER.warning("Skipping rule (no tracker_id): " + rule['descr']) else: if rule_prefix: if (rule['descr'].startswith(rule_prefix)): _LOGGER.debug("Found rule %s", rule['descr']) new_rule = pfSense('pfsense_' + rule['descr'], rule['descr'], tracker, host, api_key, access_token) rules.append(new_rule) else: _LOGGER.debug("Found rule %s", rule['descr']) new_rule = pfSense('pfsense_' + rule['descr'], rule['descr'], tracker, host, api_key, access_token) rules.append(new_rule) i = i + 1 # Add devices add_entities(rules) except Exception as e: _LOGGER.error( "Problem getting rule set from pfSense host: %s. Likely due to API key or secret. More Info:" + str(e), host)
def test_send_event(mock_requests_post): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_post.return_value.status_code = 200 mock_requests_post.return_value.text = '{"callid": "5c8dc64e73efc", "action": "send_event", "message": "ok"}' response = fauxapi.send_event(None) assert response['action'] == 'send_event' assert response['message'] == 'ok'
def test_function_call(mock_requests_post): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_post.return_value.status_code = 200 mock_requests_post.return_value.text = '{"callid": "5c8dc7cda6948", "action": "function_call", "message": "ok", "data": {"return": {}}}' response = fauxapi.function_call(None) assert response['action'] == 'function_call' assert response['message'] == 'ok'
def __init__(self, config_file): """Program to send pfSense information collected from FauxAPI to InfluxDB""" self.config = configparser.ConfigParser() self.config.read(config_file) self.fauxapi = PfsenseFauxapi(self.config['FAUXAPI']['APIHost'], self.config['FAUXAPI']['APIKey'], self.config['FAUXAPI']['APISecret']) self.influx_client = InfluxDBClient(host=self.config['INFLUXDB']['InfluxDBHost'], port=self.config['INFLUXDB']['Port'], username=self.config['INFLUXDB']['Username'], password=self.config['INFLUXDB']['Password'], database=self.config['INFLUXDB']['Database']) self.pfSense_config = self.fauxapi.config_get() self.pfSense_host = self.pfSense_config['system']['hostname'] + "." + self.pfSense_config['system']['domain']
def test_config_reload(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dbe9a6331e", "action": "config_reload", "message": "ok"}' response = fauxapi.config_reload() assert response['action'] == 'config_reload' assert response['message'] == 'ok'
def test_system_stats(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dc51dabd44", "action": "system_stats", "message": "ok", "data": {"stats": {}}}' response = fauxapi.system_stats() assert response['action'] == 'system_stats' assert response['message'] == 'ok' assert response['data'] is not None
def test_config_backup_list(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dc4987c3f8", "action": "config_backup_list", "message": "ok", "data": {"backup_files": []}}' response = fauxapi.config_backup_list() assert response['action'] == 'config_backup_list' assert response['message'] == 'ok' assert response['data'] is not None
def test_config_backup(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dc46901d7f", "action": "config_backup", "message": "ok", "data": {"backup_config_file": "/cf/conf/backup/config-1552794729.xml"}}' response = fauxapi.config_backup() assert response['action'] == 'config_backup' assert response['message'] == 'ok' assert response['data'] is not None
def test_config_patch(mock_requests_post): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_post.return_value.status_code = 200 mock_requests_post.return_value.text = '{"callid": "5c8dbe47090f8", "action": "config_patch", "message": "ok", "data": {"do_backup": true, "do_reload": true, "previous_config_file": "/cf/conf/backup/config-1552793159.xml"}}' response = fauxapi.config_patch(config={}) assert response['action'] == 'config_patch' assert response['message'] == 'ok' assert response['data'] is not None
def test_system_info(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5ed39b838c8f6", "action": "system_info", "message": "ok", "data": {"info": "foobar"}}' response = fauxapi.system_info() assert response['action'] == 'system_info' assert response['message'] == 'ok' assert response['data'] is not None
def test_alias_update_urltables(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dc7720e65a", "action": "alias_update_urltables", "message": "ok", "data": {"updates": []}}' response = fauxapi.alias_update_urltables() assert response['action'] == 'alias_update_urltables' assert response['message'] == 'ok' assert response['data'] is not None
def test_rule_get(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dc731b54e2", "action": "rule_get", "message": "ok", "data": {"rules": []}}' response = fauxapi.rule_get() assert response['action'] == 'rule_get' assert response['message'] == 'ok' assert response['data'] is not None
def test_gateway_status(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dc6227ec06", "action": "gateway_status", "message": "ok", "data": {"gateway_status": {}}}' response = fauxapi.gateway_status() assert response['action'] == 'gateway_status' assert response['message'] == 'ok' assert response['data'] is not None
def test_interface_stats(mock_requests_get): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) mock_requests_get.return_value.status_code = 200 mock_requests_get.return_value.text = '{"callid": "5c8dc5d40c07a", "action": "interface_stats", "message": "ok", "data": {"stats": {}}}' response = fauxapi.interface_stats(None) assert response['action'] == 'interface_stats' assert response['message'] == 'ok' assert response['data'] is not None
def set_rule_state(self, action): """Setup the pfSense Rules platform.""" import pprint, sys from PfsenseFauxapi.PfsenseFauxapi import PfsenseFauxapi _LOGGER.debug("Connecting to pfSense firewall to change rule states.") try: # Setup connection with devices/cloud FauxapiLib = PfsenseFauxapi(self._host, self._api_key, self._access_token, debug=True) # Get the current set of filters filters = FauxapiLib.config_get('filter') except: _LOGGER.error( "Problem retrieving rule set from pfSense host: %s. Likely due to API key or secret.", self._host) i = 0 for rule in filters['rule']: if (rule.get('tracker') == self._tracker_id): _LOGGER.info("Found rule changing state rule: %s", self._rule_name) if (action == True): if ('disabled' in rule): del filters['rule'][i]['disabled'] _LOGGER.debug( "Rule %s enabled in config (this has not been pushed back to firewall yet!)", self._rule_name) elif (action == False): filters['rule'][i]['disabled'] = "" _LOGGER.debug( "Rule %s disabled in config (this has not been pushed back to firewall yet!)", self._rule_name) i = i + 1 try: _LOGGER.debug("Sending updated rule set to pfSense firewall") # Push the config back to pfSense filters = FauxapiLib.config_set(filters, 'filter') _LOGGER.debug( "Reloading the config on pfSense firewall to accept rule changes" ) # Reload the config FauxapiLib.send_event("filter reload") except: _LOGGER.error( "Problem sending & reloading rule set from pfSense host: %s. Likely due to API key or secret.", self._host)
def build_faux_api_connection(): # First some URL formatting that I worked on to allow for custom port numbers in your # pfsense server's web configurator URL host_raw = grab_fields_from_file(".pfsense_ip_and_port", "ip") fauxapi_host = "{}:{}".format(host_raw[0], host_raw[1].strip()) # Grab the key and secret from the user created file key_secret = grab_fields_from_file(".pfsense_key_and_secret", "key") # Return callable function to interact with pfsense server try: return PfsenseFauxapi(fauxapi_host, key_secret[0], key_secret[1].strip(), debug=False) except: raise Exception( "Unable to read data files to build connection to the FauxAPI instance or data found was incorrect." )
from PfsenseFauxapi.PfsenseFauxapi import PfsenseFauxapi app = Flask(__name__) CORS(app) _, conf_file = sys.argv with open(conf_file, 'r') as infile: conf = json.load(infile) PFSENSE_HOST = conf['PFSENSE_HOST'] apikey = conf['FAUXAPI_APIKEY'] apisecret = conf['FAUXAPI_APISECRET'] api = PfsenseFauxapi(PFSENSE_HOST, apikey, apisecret) api.proto = 'http' # Serving the web site @app.route('/') def index(): return send_file(os.path.join('build', 'index.html')) @app.route('/<path:path>') def root_files(path): # send_static_file will guess the correct MIME type return send_file(os.path.join('build', path)) @app.route('/static/css/<path:path>') def css_files(path): # send_static_file will guess the correct MIME type
def test_version_exist(): fauxapi = PfsenseFauxapi(host=None, apikey=None, apisecret=None) assert fauxapi.version is not None
print(' $ ' + sys.argv[0] + ' <host> | jq .') print() sys.exit(1) # check args and env exist if(len(sys.argv) != 2) or not os.getenv('FAUXAPI_APIKEY') or not os.getenv('FAUXAPI_APISECRET'): usage() # config fauxapi_host=sys.argv[1] fauxapi_apikey=os.getenv('FAUXAPI_APIKEY') fauxapi_apisecret=os.getenv('FAUXAPI_APISECRET') FauxapiLib = PfsenseFauxapi(fauxapi_host, fauxapi_apikey, fauxapi_apisecret, debug=False) # config get the full configuration and simply print to console # ============================================================================= config = FauxapiLib.config_get() print(json.dumps( config )) # config set the full configuration # ============================================================================= # NB: nothing amazing is happening here, we are simply writing back the same (full) configuration again, the developer # most likely wants to make changes to `config` before calling the config_set function again here print(json.dumps( FauxapiLib.config_set(config)