+
+
+
+
-
{# Edit dialog #}
+
+
+
@@ -380,21 +404,27 @@
-
-
- -
-
- {{ lang._('After changing settings, please remember to apply them with the button below') }}
-
- - -
-
+ {{ partial("layout_partials/base_form",['fields':formGeoIPSettings,'id':'frm_GeopIPSettings'])}}
+
+
+
+
+
+
+ +
+ {{ lang._('After changing settings, please remember to apply them with the button below') }}
+
+
+ +
diff --git a/src/opnsense/scripts/filter/download_geoip.py b/src/opnsense/scripts/filter/download_geoip.py
index 570902f88..90436885a 100755
--- a/src/opnsense/scripts/filter/download_geoip.py
+++ b/src/opnsense/scripts/filter/download_geoip.py
@@ -32,4 +32,4 @@
from lib.geoip import download_geolite
# output files and lines processed
-print ('%d files written, with a total number of %d lines' % download_geolite())
+print ('%(file_count)d files written, with a total number of %(address_count)d lines' % download_geolite())
diff --git a/src/opnsense/scripts/filter/lib/alias.py b/src/opnsense/scripts/filter/lib/alias.py
index afba6dcf0..eaf3b4d32 100755
--- a/src/opnsense/scripts/filter/lib/alias.py
+++ b/src/opnsense/scripts/filter/lib/alias.py
@@ -172,7 +172,7 @@ class Alias(object):
if (time.time() - fstat.st_mtime) < (86400 - 90):
do_update = False
if do_update:
- syslog.syslog(syslog.LOG_ERR, 'geoip updated (files: %s lines: %s)' % geoip.download_geolite())
+ syslog.syslog(syslog.LOG_ERR, 'geoip updated (files: %(file_count)d lines: %(address_count)d)' % geoip.download_geolite())
for proto in self._proto.split(','):
geoip_filename = "/usr/local/share/GeoIP/alias/%s-%s" % (geoitem, proto)
diff --git a/src/opnsense/scripts/filter/lib/geoip.py b/src/opnsense/scripts/filter/lib/geoip.py
index 4c95b98bd..aea36ea1f 100755
--- a/src/opnsense/scripts/filter/lib/geoip.py
+++ b/src/opnsense/scripts/filter/lib/geoip.py
@@ -27,6 +27,7 @@
download maxmind GeoLite2 Free database into easy to use alias files [-] located
in /usr/local/share/GeoIP/alias
"""
+import datetime
import tempfile
import subprocess
import os
@@ -34,52 +35,65 @@ import sys
import ujson
import requests
import zipfile
+from configparser import ConfigParser
+
def download_geolite():
# define geoip download location
- url = 'https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country-CSV.zip'
+ updater_conf='/usr/local/etc/filter_geoip.conf'
+ stats_output = '/usr/local/share/GeoIP/alias.stats'
+ url = None
+ if os.path.exists(updater_conf):
+ cnf = ConfigParser()
+ cnf.read(updater_conf)
+ if cnf.has_section('settings') and cnf.has_option('settings', 'url'):
+ url = cnf.get('settings', 'url').strip()
- address_count = 0
- file_count = 0
- # flush data from remote url to temp file and unpack from there
- with tempfile.NamedTemporaryFile() as tmp_stream:
- r = requests.get(url)
- if r.status_code == 200:
- tmp_stream.write(r.content)
- tmp_stream.seek(0)
- with zipfile.ZipFile(tmp_stream, mode='r', compression=zipfile.ZIP_DEFLATED) as zf:
- # fetch zip file contents
- file_handles = dict()
- for item in zf.infolist():
- if item.file_size > 0:
- file_handles[os.path.basename(item.filename)] = item
- # only process geo ip data when archive contains country definitions
- if 'GeoLite2-Country-Locations-en.csv' in file_handles:
- country_codes = dict()
- # parse geoname_id to country code map
- for line in zf.open(file_handles['GeoLite2-Country-Locations-en.csv']).read().decode().split('\n'):
- parts = line.split(',')
- if len(parts) > 4 and len(parts[4]) >= 1 and len(parts[4]) <= 3:
- country_codes[parts[0]] = parts[4]
- # process all details into files per country / protocol
- for proto in ['IPv4', 'IPv6']:
- if 'GeoLite2-Country-Blocks-%s.csv' % proto in file_handles:
- output_handles = dict()
- country_blocks = zf.open(file_handles['GeoLite2-Country-Blocks-%s.csv' % proto]).read()
- for line in country_blocks.decode().split('\n'):
- parts = line.split(',')
- if len(parts) > 3 and parts[1] in country_codes:
- country_code = country_codes[parts[1]]
- if country_code not in output_handles:
- if not os.path.exists('/usr/local/share/GeoIP/alias'):
- os.makedirs('/usr/local/share/GeoIP/alias')
- output_handles[country_code] = open(
- '/usr/local/share/GeoIP/alias/%s-%s'%(country_code,proto), 'w'
- )
- file_count += 1
- output_handles[country_code].write("%s\n" % parts[0])
- address_count += 1
- for country_code in output_handles:
- output_handles[country_code].close()
+ result = {'address_count': 0 , 'file_count': 0, 'timestamp': None}
+ if url is not None:
+ # flush data from remote url to temp file and unpack from there
+ with tempfile.NamedTemporaryFile() as tmp_stream:
+ r = requests.get(url)
+ if r.status_code == 200:
+ tmp_stream.write(r.content)
+ tmp_stream.seek(0)
+ with zipfile.ZipFile(tmp_stream, mode='r', compression=zipfile.ZIP_DEFLATED) as zf:
+ # fetch zip file contents
+ file_handles = dict()
+ for item in zf.infolist():
+ if item.file_size > 0:
+ file_handles[os.path.basename(item.filename)] = item
+ # only process geo ip data when archive contains country definitions
+ if 'GeoLite2-Country-Locations-en.csv' in file_handles:
+ dt = datetime.datetime(*file_handles['GeoLite2-Country-Locations-en.csv'].date_time).isoformat()
+ result['timestamp'] = dt
+ country_codes = dict()
+ # parse geoname_id to country code map
+ for line in zf.open(file_handles['GeoLite2-Country-Locations-en.csv']).read().decode().split('\n'):
+ parts = line.split(',')
+ if len(parts) > 4 and len(parts[4]) >= 1 and len(parts[4]) <= 3:
+ country_codes[parts[0]] = parts[4]
+ # process all details into files per country / protocol
+ for proto in ['IPv4', 'IPv6']:
+ if 'GeoLite2-Country-Blocks-%s.csv' % proto in file_handles:
+ output_handles = dict()
+ country_blocks = zf.open(file_handles['GeoLite2-Country-Blocks-%s.csv' % proto]).read()
+ for line in country_blocks.decode().split('\n'):
+ parts = line.split(',')
+ if len(parts) > 3 and parts[1] in country_codes:
+ country_code = country_codes[parts[1]]
+ if country_code not in output_handles:
+ if not os.path.exists('/usr/local/share/GeoIP/alias'):
+ os.makedirs('/usr/local/share/GeoIP/alias')
+ output_handles[country_code] = open(
+ '/usr/local/share/GeoIP/alias/%s-%s'%(country_code,proto), 'w'
+ )
+ result['file_count'] += 1
+ output_handles[country_code].write("%s\n" % parts[0])
+ result['address_count'] += 1
+ for country_code in output_handles:
+ output_handles[country_code].close()
- return (file_count, address_count)
+ open(stats_output,'w').write(ujson.dumps(result))
+
+ return result
diff --git a/src/opnsense/service/templates/OPNsense/Filter/+TARGETS b/src/opnsense/service/templates/OPNsense/Filter/+TARGETS
index b57480fb6..ac87ac037 100644
--- a/src/opnsense/service/templates/OPNsense/Filter/+TARGETS
+++ b/src/opnsense/service/templates/OPNsense/Filter/+TARGETS
@@ -1 +1,2 @@
filter_tables.conf:/usr/local/etc/filter_tables.conf
+filter_geoip.conf:/usr/local/etc/filter_geoip.conf
diff --git a/src/opnsense/service/templates/OPNsense/Filter/filter_geoip.conf b/src/opnsense/service/templates/OPNsense/Filter/filter_geoip.conf
new file mode 100644
index 000000000..88fe73a47
--- /dev/null
+++ b/src/opnsense/service/templates/OPNsense/Filter/filter_geoip.conf
@@ -0,0 +1,6 @@
+[settings]
+{% if helpers.exists('OPNsense.Firewall.Alias.geoip.url') %}
+url={{OPNsense.Firewall.Alias.geoip.url}}
+{% else %}
+url=
+{% endif %}