Skip to content

Commit 15ebd88

Browse files
committed
security/q-feeds-connector: sync with master
1 parent 53e98c4 commit 15ebd88

7 files changed

Lines changed: 51 additions & 10 deletions

File tree

security/q-feeds-connector/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
PLUGIN_NAME= q-feeds-connector
22
PLUGIN_VERSION= 1.5
3-
PLUGIN_REVISION= 2
3+
PLUGIN_REVISION= 3
44
PLUGIN_COMMENT= Connector for Q-Feeds threat intel
55
PLUGIN_MAINTAINER= devel@qfeeds.com
66
PLUGIN_TIER= 2

security/q-feeds-connector/pkg-descr

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ Plugin Changelog
1111
* Feature: Add dest address for unbound
1212
* Bugfix: Invalidate alias cache on reconfigure
1313
* Bugfix: Ignore "pass" log lines for `qfeedsctl.py logs`
14+
* Bugfix: Use proper configctl command option for flushing
15+
* Bugfix: Add optional locked mode in qfeedsctl.py for cron runners and wait for configfile changes when HTTP 401 is thrown
16+
* Bugfix: Ignore invalid json index file leading to instant exit of qfeedsctl.py
1417

1518
1.4
1619

security/q-feeds-connector/src/etc/inc/plugins.inc.d/qfeeds.inc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828

2929
function qfeeds_cron()
3030
{
31-
$jobs = [];
32-
$jobs[]['autocron'] = ['/usr/local/sbin/configctl -d qfeeds update', '*/5'];
33-
$jobs[]['autocron'] = ['/usr/local/sbin/configctl -d ! qfeeds stats', '*/15'];
34-
return $jobs;
31+
return [
32+
['autocron' => ['/usr/local/sbin/configctl -d qfeeds update', '*/5']],
33+
['autocron' => ['/usr/local/sbin/configctl -df qfeeds stats', '*/15']],
34+
];
3535
}

security/q-feeds-connector/src/opnsense/scripts/qfeeds/lib/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,10 @@ def index(self):
6363
list(self.fetch_index())
6464
elif not os.path.exists(self.index_file):
6565
return {}
66-
data = ujson.load(open(self.index_file)) or {}
66+
try:
67+
data = ujson.load(open(self.index_file)) or {}
68+
except ujson.JSONDecodeError:
69+
data = {}
6770
if type(data) is dict:
6871
for feed in data.get('feeds', []):
6972
feed['local_filename'] = "%s/%s.txt" % (self._target_dir, feed['feed_type'])

security/q-feeds-connector/src/opnsense/scripts/qfeeds/lib/api.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,31 @@
2323
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2424
POSSIBILITY OF SUCH DAMAGE.
2525
"""
26+
2627
import os
2728
import requests
2829
from configparser import ConfigParser
2930

3031

3132
class QFeedsConfig:
33+
config_filename = '/usr/local/etc/qfeeds.conf'
34+
conf_timestamp = None
3235
api_key = None
3336

3437
def __init__(self):
35-
config_filename = '/usr/local/etc/qfeeds.conf'
36-
if os.path.isfile(config_filename):
38+
if os.path.isfile(self.config_filename):
3739
cnf = ConfigParser()
38-
cnf.read(config_filename)
40+
cnf.read(self.config_filename)
3941
if cnf.has_section('api') and cnf.has_option('api', 'key'):
4042
self.api_key = cnf.get('api', 'key').strip()
4143

44+
if self.conf_timestamp is None:
45+
QFeedsConfig.conf_timestamp = os.stat(self.config_filename).st_mtime
46+
47+
@classmethod
48+
def has_changed(cls):
49+
return os.path.isfile(cls.config_filename) and cls.conf_timestamp != os.stat(cls.config_filename).st_mtime
50+
4251

4352
class Api:
4453
def __init__(self):

security/q-feeds-connector/src/opnsense/scripts/qfeeds/qfeedsctl.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,34 @@
2727
"""
2828

2929
import argparse
30+
import fcntl
31+
import time
3032
import sys
3133
import ujson
3234
from requests.exceptions import HTTPError, Timeout
3335
from lib import QFeedsActions
36+
from lib.api import QFeedsConfig
3437

3538

3639
if __name__ == '__main__':
3740
parser = argparse.ArgumentParser()
3841
parser.add_argument('--target_dir', default='/var/db/qfeeds-tables')
3942
parser.add_argument('-f', help='forced (auto index)' , default=False, action='store_true')
4043
parser.add_argument('-v', help='verbose output' , default=False, action='store_true')
44+
parser.add_argument('-l', help='lock operation' , default=False, action='store_true')
4145
parser.add_argument("action", choices=QFeedsActions.list_actions(), nargs='*')
4246
args = parser.parse_args()
47+
48+
fhandle = None
49+
if args.l:
50+
lck_filename = '/tmp/qfeeds_prc.LCK'
51+
fhandle = open(lck_filename, 'a+')
52+
try:
53+
fcntl.flock(fhandle, fcntl.LOCK_EX | fcntl.LOCK_NB)
54+
except IOError:
55+
print('already busy, exit')
56+
sys.exit(0)
57+
4358
if args.v:
4459
# verbose mode
4560
import http.client as http_client
@@ -51,6 +66,14 @@
5166
print(msg)
5267
except HTTPError as exc:
5368
print('exit with HTTPError %d (%s)' % (exc.response.status_code, exc.response.text))
69+
if exc.response.status_code == 401 and 'update' in args.action:
70+
print('batch mode - wait for configuration update or timeout')
71+
t_start = time.time()
72+
while not QFeedsConfig.has_changed():
73+
if time.time() - t_start > 3600:
74+
print('timeout waiting for config change')
75+
break
76+
time.sleep(5)
5477
sys.exit(-1)
5578
except Timeout as exc:
5679
print('timeout reaching api endpoint')
@@ -61,3 +84,6 @@
6184
except ujson.JSONDecodeError:
6285
print("JSON decode error")
6386
sys.exit(-1)
87+
finally:
88+
if fhandle:
89+
fcntl.flock(fhandle, fcntl.LOCK_UN)

security/q-feeds-connector/src/opnsense/service/conf/actions.d/actions_qfeeds.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ message:reconfigure QFeeds
66
errors:no
77

88
[update]
9-
command:/usr/local/opnsense/scripts/qfeeds/qfeedsctl.py update
9+
command:/usr/local/opnsense/scripts/qfeeds/qfeedsctl.py -l update
1010
parameters:
1111
type:script_output
1212
message:update QFeeds

0 commit comments

Comments
 (0)