Skip to content

Commit 709a5cc

Browse files
committed
update sync method and to python3.12
1 parent 7f0335d commit 709a5cc

16 files changed

+336
-356
lines changed

.env.example

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
MIKROTIK_HOST=192.168.88.1
2+
MIKROTIK_USER=username
3+
MIKROTIK_PASSWORD=password
4+
BLOCKLIST_URL=http://YOUR_BLOCK_LIST/security/blocklist?ipv4only
5+
SYNC_INTERVAL_MIN=15
6+
LOG_LEVEL=INFO

Dockerfile

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
FROM python:3.11.9-slim
1+
FROM python:3.12.5-slim
22

33
WORKDIR /srv/
44

55
COPY pyproject.toml .
66
COPY poetry.lock .
77

8-
RUN apt update && apt upgrade -y && pip install poetry
8+
RUN apt update && pip install poetry
99

1010
RUN poetry config virtualenvs.create false
1111
RUN poetry install
@@ -14,4 +14,4 @@ RUN apt-get remove -y gcc cmake make libc-dev-bin libc6-dev
1414
RUN rm -rf /var/lib/apt/lists/* && apt-get autoremove -y && apt-get clean
1515
RUN pip uninstall pipenv poetry -y
1616

17-
COPY . .
17+
COPY . .

README.md

+50-24
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
1-
# MikroSecList
1+
# MikroSecList - Mikrotik Security List
22

3-
## Mikrotik + CrowdSec block lists sync
3+
[![crowdsec blocklist](./crowdsec_blocklist/crowdsec_blocklist.png)](https://github.com/akmalovaa/mikroseclist)
44

5-
This app constantly synchronizes and updates the firewall address list in mikrotik.
5+
CrowdSec Blocklist mirror synchronization to RouterOS firewall address list
66

7-
Actual dangerous IP addresses will already be in the blocked list
7+
- [DockerHub crowdsec](https://hub.docker.com/r/crowdsecurity/crowdsec)
8+
- [DockerHub blocklist-mirror](https://hub.docker.com/r/crowdsecurity/blocklist-mirror)
9+
- [Docs Blocklist mirror](https://docs.crowdsec.net/u/bouncers/blocklist-mirror#installation/)
810

9-
[CrowdSec Blocklist mirror](https://docs.crowdsec.net/u/bouncers/blocklist-mirror/#installation/)
11+
### Guide
1012

11-
Allows you to use a list of IP addresses to add
13+
Configure Blocklist Mirror or use your own list of IP addresses *(need HTTP format output list)*
1214

1315
*`config.yml`*
1416
```yaml | code
1517
blocklists:
16-
format: mikrotik
18+
format: plain_text
1719
```
18-
Output lines for mikrotik, format is `/ip|/ipv6 firewall address-list add list={list_name} address={ip} comment="{scenario} for {duration}"`
19-
20-
The list of dangerous IP addresses is very large ~ 25,000, when updated in this way, all addresses are deleted and added again. It's pointless to do this every time you update.
21-
22-
This service only allows you to edit changes. Delete something, add something
23-
24-
## Guide
25-
26-
### Prepare block list
27-
28-
[docker-compose crowdsec-blocklist](https://github.com/akmalovaa/crowdsec-blocklist)
29-
30-
Or use your own list of IP addresses, the list should be accessible by url
3120
3221
### Prepare Router OS
3322
@@ -39,22 +28,29 @@ add name=Server common-name=server
3928
add name=Client common-name=client
4029
```
4130

42-
Certificates should be signed.
31+
Certificates should be signed.
32+
**Change your RouterOS host address**
4333
```
4434
/certificate
4535
sign CA-Template
4636
sign Client
4737
sign Server ca-crl-host=192.168.88.1 name=ServerCA
4838
```
4939

50-
Enable API-SSL
40+
Enable API-SSL. **Change api access address**
5141
```
5242
/ip service
5343
set api-ssl address=192.168.88.0/24 certificate=ServerCA
5444
```
5545

5646
### Docker compose
5747

48+
change `.env` file variables
49+
```
50+
cp .env.exmaple .env
51+
nano .env
52+
```
53+
5854
build
5955
```bash
6056
docker build . -t mikroseclist:latest
@@ -89,10 +85,40 @@ change environment variables and run:
8985
docker-compose up -d
9086
```
9187

92-
Change Mikrotik Firewall Rules
88+
After first syncing сhange Mikrotik Firewall Rules
9389
```sh
9490
/ip firewall filter
9591
add action=accept chain=input src-address-list=access # access list optional
9692
add action=drop chain=input in-interface=ether1 src-address-list=block
9793
add action=drop chain=forward in-interface=ether1 src-address-list=block
98-
```
94+
```
95+
96+
### Settings
97+
98+
https://github.com/akmalovaa/mikroseclist/blob/main/mikroseclist/settings.py
99+
100+
You can override this variables in the .env file
101+
102+
103+
## CrowdSec block lists sync
104+
105+
You can use default **CrowdSec Blocklist mirror** format without `mikroseclist` service:
106+
107+
This app constantly synchronizes and updates the firewall address list in mikrotik.
108+
109+
Actual dangerous IP addresses will already be in the blocked list
110+
111+
[CrowdSec Blocklist mirror](https://docs.crowdsec.net/u/bouncers/blocklist-mirror/#installation/)
112+
113+
Allows you to use a list of IP addresses to add
114+
115+
*`config.yml`*
116+
```yaml | code
117+
blocklists:
118+
format: mikrotik
119+
```
120+
Output lines for mikrotik, format is `/ip|/ipv6 firewall address-list add list={list_name} address={ip} comment="{scenario} for {duration}"`
121+
122+
The list of dangerous IP addresses is very large ~ 25,000, when updated in this way, all addresses are deleted and added again. It's pointless to do this every time you update.
123+
124+
This service only allows you to edit changes. Delete something, add something

Taskfile.yml

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1-
version: "3"
1+
version: '3'
2+
3+
env:
4+
IMAGE_TAG: 'mikroseclist:latest'
25

36
tasks:
7+
cli:
8+
aliases: [bash, shell, exec]
9+
desc: run temporary container and passthrough current directory
10+
cmds:
11+
- docker run --rm -it --env-file .env -v .:/srv $IMAGE_TAG bash
12+
413
build:
5-
desc: "build Dockerfile"
6-
dir: "{{.USER_WORKING_DIR}}"
714
cmds:
8-
- docker build . -t mikroseclist:latest
15+
- docker build . -t $IMAGE_TAG
16+
17+
# export PYTHONPATH='/srv/mikroseclist/'
18+
# python -m mikroseclist.main

compose-dev.yaml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: "3.9"
2-
31
services:
42
mikroseclist:
53
image: mikroseclist:latest
@@ -8,12 +6,14 @@ services:
86
dockerfile: Dockerfile
97
container_name: mikroseclist
108
command: ["python", "-m", "mikroseclist.main"]
9+
# command: ["tail", "-f", "/dev/null"]
1110
environment:
11+
LOG_LEVEL: DEBUG
1212
MIKROTIK_HOST: ${MIKROTIK_HOST:-'192.168.88.1'}
1313
MIKROTIK_USER: ${MIKROTIK_USER:-'admin'}
1414
MIKROTIK_PASSWORD: ${MIKROTIK_PASSWORD:-'password'}
1515
BLOCKLIST_URL: ${BLOCKLIST_URL}
16-
SYNC_INTERVAL_MIN: 15
16+
SYNC_INTERVAL_MIN: 2
1717
volumes:
1818
- ./:/srv/
1919
restart: on-failure

compose.yaml

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
version: "3.9"
2-
31
services:
42
mikroseclist:
53
image: ghcr.io/akmalovaa/mikroseclist:latest
64
container_name: mikroseclist
7-
command: ["python", "-m", "mikroseclist.main"]
5+
command: ["python", "-m", "mikroseclist"]
86
environment:
97
MIKROTIK_HOST: ${MIKROTIK_HOST:-'192.168.88.1'}
108
MIKROTIK_USER: ${MIKROTIK_USER:-'admin'}
119
MIKROTIK_PASSWORD: ${MIKROTIK_PASSWORD:-'password'}
12-
BLOCKLIST_URL: 'http://blocklist:41412/security/blocklist?ipv4only'
10+
BLOCKLIST_URL: ${BLOCKLIST_URL:-'http://blocklist:41412/security/blocklist?ipv4only'}
1311
SYNC_INTERVAL_MIN: 15
1412
restart: on-failure

compose-crowdsec.yaml crowdsec_blocklist/compose.yaml

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# Install guide https://github.com/akmalovaa/crowdsec-blocklist
2-
31
services:
42
crowdsec:
53
image: ${CROWDSEC_IMAGE_TAG:-crowdsecurity/crowdsec:latest}
@@ -36,7 +34,7 @@ services:
3634
ports:
3735
- 41412:41412
3836
volumes:
39-
- ./crowdsec-blocklist-mirror.yaml:/etc/crowdsec/bouncers/crowdsec-blocklist-mirror.yaml
37+
- ./blocklist_config.yaml:/etc/crowdsec/bouncers/crowdsec-blocklist-mirror.yaml
4038
healthcheck:
4139
test: wget -qO- http://localhost:41412/security/blocklist?ipv4only || exit 1
4240
start_period: 20s
@@ -45,7 +43,7 @@ services:
4543
retries: 5
4644
networks:
4745
crowdsec_net:
48-
ipv4_address: 172.21.0.2
46+
ipv4_address: 172.21.0.12
4947

5048
mikroseclist:
5149
image: ${MIKROSECLIST_IMAGE_TAG:-ghcr.io/akmalovaa/mikroseclist:latest}
@@ -66,7 +64,7 @@ services:
6664
restart: unless-stopped
6765
networks:
6866
crowdsec_net:
69-
ipv4_address: 172.21.0.3
67+
ipv4_address: 172.21.0.13
7068

7169
networks:
7270
crowdsec_net:
219 KB
Loading

mikroseclist/__init__.py

Whitespace-only changes.

mikroseclist/__main__.py

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import ipaddress
2+
import sys
3+
import time
4+
5+
import requests
6+
from loguru import logger
7+
from schedule import every, repeat, run_pending
8+
9+
from mikroseclist.mikrotik_client import MikroTikClient
10+
from mikroseclist.settings import settings
11+
12+
logger.remove()
13+
logger.add(
14+
sys.stderr,
15+
level=settings.log_level,
16+
format="{time:DD.MM.YY HH:mm:ss} {level} {message}",
17+
)
18+
19+
mikrotik = MikroTikClient(
20+
settings.mikrotik_host, settings.mikrotik_user, settings.mikrotik_password
21+
)
22+
23+
24+
def download_blocklist_file() -> None:
25+
logger.info(f"Fetch blocklist from url: {settings.blocklist_url}")
26+
try:
27+
response = requests.get(settings.blocklist_url)
28+
except requests.exceptions.RequestException as e:
29+
logger.error(
30+
f"Fetch blocklist from url: {settings.blocklist_url} exceptions: {e}"
31+
)
32+
sys.exit()
33+
if response.status_code == 200:
34+
with open(settings.blocklist_filename, "wb") as file:
35+
file.write(response.content)
36+
logger.debug(f"Save crowdsec blocklist to file: {settings.blocklist_filename}")
37+
else:
38+
logger.error("Addresses list could not be downloaded")
39+
return
40+
41+
42+
def fetch_crowdsec_block_list() -> list:
43+
logger.debug(f"Fetch data from file: {settings.blocklist_filename}")
44+
block_list: list = []
45+
download_blocklist_file()
46+
with open(settings.blocklist_filename, "r") as file:
47+
for line in file:
48+
stripped_line = line.strip()
49+
if stripped_line:
50+
try:
51+
ipaddress.ip_address(stripped_line)
52+
block_list.append(stripped_line)
53+
except ValueError:
54+
logger.warning(
55+
f"Invalid IP address found and skipped: {stripped_line}"
56+
)
57+
return block_list
58+
59+
60+
def sync_addres_list() -> None:
61+
logger.info(f"Run synchronization")
62+
mikrotik_block_list: list = mikrotik.fetch_address_list()
63+
crowdsec_block_list: list = fetch_crowdsec_block_list()
64+
mikrotik_add_list: list = list(set(crowdsec_block_list) - set(mikrotik_block_list))
65+
mikrotik_delete_list: list = list(
66+
set(mikrotik_block_list) - set(crowdsec_block_list)
67+
)
68+
if mikrotik_add_list:
69+
logger.debug(f"Found {len(mikrotik_add_list)} new addresses to add")
70+
mikrotik.add_address_list(mikrotik_add_list)
71+
else:
72+
logger.debug(f"No addresses found to add")
73+
if mikrotik_delete_list:
74+
logger.debug(f"Found {len(mikrotik_delete_list)} new addresses to delete")
75+
mikrotik.delete_address_list(mikrotik_delete_list)
76+
else:
77+
logger.debug(f"No addresses found to delete")
78+
logger.info(
79+
f"Successful synchronization. Total block list addresses: {len(crowdsec_block_list)}"
80+
)
81+
82+
83+
@repeat(every(settings.sync_interval_min).minutes)
84+
def run_sync_list() -> None:
85+
logger.info("sync mikrotik firewall address list")
86+
sync_addres_list()
87+
88+
89+
def run_scheduler() -> None:
90+
logger.info(
91+
f"Run scheduler: sync address list every {settings.sync_interval_min} minutes"
92+
)
93+
while True:
94+
run_pending()
95+
time.sleep(60)
96+
97+
98+
if __name__ == "__main__":
99+
logger.info("Mikrotik firewall address list synchronization started")
100+
sync_addres_list()
101+
run_scheduler()

0 commit comments

Comments
 (0)