(20250209) Something about MikrTik. Don't ask
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
"""
|
||||
|
||||
AUTHOR:
|
||||
|
||||
Khushal P Soonderji
|
||||
|
||||
DATE:
|
||||
|
||||
Sunday, 9th Feb, 2025.
|
||||
|
||||
OBJECTIVE:
|
||||
|
||||
To provide an easy way to configure MikroTik devices remotely.
|
||||
|
||||
REFERENCES:
|
||||
|
||||
N/A
|
||||
|
||||
DOWNLOADS:
|
||||
|
||||
N/A
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** IMPORT ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# To make sibling directories accessible for imports:
|
||||
import sys
|
||||
sys.path.append(".")
|
||||
sys.path.append("..")
|
||||
|
||||
# System-level activities:
|
||||
import io
|
||||
import os
|
||||
|
||||
# My utils:
|
||||
from utils_v2.string import json
|
||||
|
||||
# For SSH:
|
||||
from paramiko import SSHClient, AutoAddPolicy
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** MACROS / ONE-TIME INIT ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# --- Nothing Yet
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** VARIABLES ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
# --- Nothing Yet
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** FUNCTIONS ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
def ssh_exec_one(ssh: SSHClient, command: str):
|
||||
|
||||
# Start by assuming failure:
|
||||
result = {
|
||||
"stdin": None,
|
||||
"stdout": None,
|
||||
"stderr": None,
|
||||
"returnCode": -999,
|
||||
"exception": None
|
||||
}
|
||||
|
||||
try:
|
||||
|
||||
# Run the command:
|
||||
stdin, stdout, stderr = ssh.exec_command(command)
|
||||
|
||||
print(stdin)
|
||||
|
||||
# Extract the results:
|
||||
result["stdin"] = stdin.read().decode("utf8")
|
||||
result["stdout"] = stdout.read().decode("utf8")
|
||||
result["stderr"] = stderr.read().decode("utf8")
|
||||
result["returnCode"] = stdout.channel.recv_exit_status()
|
||||
|
||||
# Close the file-like objects:
|
||||
stdin.close()
|
||||
stdout.close()
|
||||
stderr.close()
|
||||
|
||||
# If something goes wrong:
|
||||
except Exception as exception:
|
||||
result["exception"] = exception
|
||||
raise exception
|
||||
|
||||
# Done here:
|
||||
return result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
def ssh_test(config: dict):
|
||||
|
||||
# Initialize the object:
|
||||
ssh = SSHClient()
|
||||
# ssh.load_host_keys("~/.ssh/known_hosts")
|
||||
ssh.load_system_host_keys()
|
||||
ssh.set_missing_host_key_policy(AutoAddPolicy())
|
||||
|
||||
# Log in to the SSH client:
|
||||
ssh.connect(
|
||||
hostname = config["nasIp"],
|
||||
port = 19991,
|
||||
username = config["username"],
|
||||
password = config["password"]
|
||||
)
|
||||
|
||||
# Execute the needed commands:
|
||||
result = ssh_exec_one(ssh, "hostname")
|
||||
print("EXEC ONE JSON:", json.to_string(result, default = str))
|
||||
|
||||
# Close the connection:
|
||||
ssh.close()
|
||||
|
||||
|
||||
# *****************************************************************************************************************
|
||||
# ***** ****
|
||||
# *** MAIN PROGRAM ***
|
||||
# ***** ****
|
||||
# *****************************************************************************************************************
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# The expected configuration structure from the database:
|
||||
sample_config_json = {
|
||||
"siteName": "Hirani Telcom",
|
||||
# "nasIp": "102.210.175.251",
|
||||
"nasIp": "wtt.ditscentre.in",
|
||||
"radius": "102.210.175.242",
|
||||
"secret": "abcdefgh",
|
||||
# "username": "easyfi",
|
||||
"username": "chaalu",
|
||||
# "password": "easyfi",
|
||||
"password": "hellochaalu",
|
||||
"location": "Kenya",
|
||||
"snmpCommunity": "abcdefgh"
|
||||
}
|
||||
|
||||
ssh_test(config = sample_config_json)
|
||||
@@ -0,0 +1,405 @@
|
||||
# MiktoTik Configuration Steps
|
||||
### We need to configure MikroTik servers for two end use cases - PPPoE or HotSpot. here are the steps to achieve them through MikroTik's REST API facility. Use the `MiktoTik (EasyFi)` Postman collection for this.
|
||||
#### Authors: Bhushan, Hari, Khushal
|
||||
#### Date: 20250209
|
||||
|
||||
|
||||
### General Notes:
|
||||
|
||||
Private IP series has been allocated for doing carrier-grade NAT = 100.64.0.0/10
|
||||
|
||||
PPPoE user master subnet = 100.64.0.0/16
|
||||
pppoe_ip_subnet: 100.64.0.0/24 = if user is under 256
|
||||
pppoe_ip_subnet: 100.64.0.0/23 = if user is under 512
|
||||
pppoe_ip_subnet: 100.64.0.0/22 = if user is under 1024
|
||||
pppoe_ip_subnet: 100.64.0.0/21 = if user is under 2048
|
||||
PPPoE deactivated user master subnet = 10.0.0.0/16
|
||||
|
||||
HotSpot user master subnet = 100.65.0.0/16
|
||||
hotspot_ip_subnet: 100.65.0.0/24 = if user is under 256
|
||||
hotspot_ip_subnet: 100.65.0.0/23 = if user is under 512
|
||||
hotspot_ip_subnet: 100.65.0.0/22 = if user is under 1024
|
||||
hotspot_ip_subnet: 100.65.0.0/21 = if user is under 2048
|
||||
|
||||
---
|
||||
|
||||
## Steps for HotSpot
|
||||
|
||||
### 1. Interface
|
||||
- Enlist the available interfaces.
|
||||
- Select the first one that has field `"running"` set to `"false"`, and pick its `".id"`.
|
||||
- Rename it to `"hs-easyfi"` by its `".id"`.
|
||||
|
||||
### 2. Create a VLAN
|
||||
Create a VLAN with the following config:
|
||||
```json
|
||||
{
|
||||
"name": "easyfi-vlan-<vlan_id>",
|
||||
"interface": "easyfi-hs", // The name that was given in the previous step.
|
||||
"vlan-id": "<vlan_id>", // From the config received on the portal.
|
||||
"disabled": "no"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Add a new IP Address to the VLAN interface
|
||||
```json
|
||||
{
|
||||
"address": "<hotspot_ip_subnet>", // Refer to the general notes.
|
||||
"interface": "easyfi-vlan-<vlan_id>", // Same as the 'name' given in the previous step.
|
||||
"disabled": "no"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Add a New IP Pool for HotSpot Users
|
||||
```json
|
||||
{
|
||||
"name": "easyfi-hs-pool-<vlan_id>",
|
||||
"ranges": "<hotspot_ip_subnet>" // Refer to the general notes.
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Add a New HotSpot Profile
|
||||
```json
|
||||
{
|
||||
"dns-name": "hs01.easyfi.net.in",
|
||||
"hotspot-address": "100.65.0.1", // First from the subnet. Refer to the general notes.
|
||||
"html-directory": "hotspot",
|
||||
"html-directory-override": "",
|
||||
"http-cookie-lifetime": "3d",
|
||||
"http-proxy": "0.0.0.0:0",
|
||||
"install-hotspot-queue": "false",
|
||||
"login-by": "cookie,http-chap",
|
||||
"name": "hs01.easyfi.net.in",
|
||||
"split-user-domain": "false",
|
||||
"use-radius": "true",
|
||||
"nas-port-type": "wireless-802.11",
|
||||
"radius-accounting": "true",
|
||||
"radius-default-domain": "",
|
||||
"radius-interim-update": "received",
|
||||
"radius-location-id": "",
|
||||
"radius-location-name": "",
|
||||
"radius-mac-format": "XX:XX:XX:XX:XX:XX"
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Add a New HotSpot Server
|
||||
```json
|
||||
{
|
||||
"address-pool": "easyfi-hs-pool-<vlan_id>", // Same as the name given when creating the pool.
|
||||
"addresses-per-mac": "2",
|
||||
"idle-timeout": "5m",
|
||||
"interface": "easyfi-vlan-<vlan_id>", // Same as the 'name' given when creating the VLAN.
|
||||
"keepalive-timeout": "none",
|
||||
"login-timeout": "none",
|
||||
"name": "hs01.easyfi.net.in",
|
||||
"profile": "hs01.easyfi.net.in",
|
||||
"disabled": "false"
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Add a New DHCP Server
|
||||
```json
|
||||
{
|
||||
"address-pool": "easyfi-hs-pool-<vlan_id>", // Same as the name given when creating the pool.
|
||||
"authoritative": "yes",
|
||||
"disabled": "false",
|
||||
"interface": "easyfi-vlan-<vlan_id>", // Same as the 'name' given when creating the VLAN.
|
||||
"lease-time": "30m",
|
||||
"name": "easyfi-hs-dhcp-<vlan_id>",
|
||||
"use-radius": "no"
|
||||
}
|
||||
```
|
||||
|
||||
### 8. Add a New DHCP Network
|
||||
```json
|
||||
{
|
||||
"address": "<hotspot_ip_subnet>", // Refer to the general notes.
|
||||
"gateway": "100.65.0.1", // First from the subnet. Refer to the general notes.
|
||||
"netmask": "24", // Refer to the no. of users in the general notes.
|
||||
"dns-server": "100.65.0.1" // First from the subnet. Refer to the general notes.
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 9. Whitelist the RADIUS Server IP in the HotSpot Server
|
||||
Hint: Walled-Garden IPs
|
||||
```json
|
||||
{
|
||||
"action": "accept",
|
||||
"dst-address": "<radius_server_ip>" // Received from the portal.
|
||||
}
|
||||
```
|
||||
|
||||
### 10. Add a New RADIUS Server:
|
||||
```json
|
||||
{
|
||||
"accounting-port": "1813",
|
||||
"address": "<radius_server_ip>", // Received from the portal.
|
||||
"authentication-port": "1812",
|
||||
"disabled": "false",
|
||||
"protocol": "udp",
|
||||
"secret": "<radius_server_secret>", // Received from the portal.
|
||||
"service": "ppp,login,hotspot,dhcp",
|
||||
"timeout": "300ms"
|
||||
}
|
||||
```
|
||||
|
||||
### 11. Allow Incoming Communication from the RADIUS Server to the MikroTik Device
|
||||
```json
|
||||
{
|
||||
"accept": "yes",
|
||||
"port": "3799"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 12. Add a New DNS Server
|
||||
```json
|
||||
{
|
||||
"allow-remote-requests": "true",
|
||||
"servers": "8.8.8.8,8.8.4.4"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 13. Add Firewall Rules for NAT-ing
|
||||
**NOTE:** Looping needed to split the bigger IP subnet into smaller subnets.
|
||||
```json
|
||||
{
|
||||
"action": "src-nat",
|
||||
"chain": "srcnat",
|
||||
"disabled": "false",
|
||||
"src-address": "100.65.0.16/28",
|
||||
"to-addresses": "111.222.111.111"
|
||||
}
|
||||
```
|
||||
|
||||
### 14. Add a New SNMP Community
|
||||
```json
|
||||
{
|
||||
"addresses": "::/0",
|
||||
"authentication-password": "",
|
||||
"authentication-protocol": "MD5",
|
||||
"disabled": "false",
|
||||
"encryption-password": "",
|
||||
"encryption-protocol": "DES",
|
||||
"name": "<random_16_chars>",
|
||||
"read-access": "true",
|
||||
"security": "none",
|
||||
"write-access": "false" // ALWAYS FALSE
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Steps for PPPoE
|
||||
|
||||
### 1. Interface
|
||||
- Enlist the available interfaces.
|
||||
- Select the first one that has field `"running"` set to `"false"`, and pick its `".id"`.
|
||||
- Rename it to `"easyfi-ppp"` by its `".id"`.
|
||||
|
||||
### 2. Create a VLAN
|
||||
Create a VLAN with the following config:
|
||||
```json
|
||||
{
|
||||
"name": "easyfi-vlan-<vlan_id>",
|
||||
"interface": "easyfi-ppp", // The name that was given in the previous step.
|
||||
"vlan-id": "<vlan_id>", // From the config received on the portal.
|
||||
"disabled": "no"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Add a New IP Pool for PPPoE Users
|
||||
```json
|
||||
{
|
||||
"name": "easyfi-ppp-pool-<vlan_id>",
|
||||
"ranges": "<pppoe_ip_subnet>" // Refer to the general notes.
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Add a New PPPoE Profile
|
||||
```json
|
||||
{
|
||||
"address-list": "",
|
||||
"bridge-learning": "default",
|
||||
"change-tcp-mss": "yes",
|
||||
"dns-server": "8.8.8.8",
|
||||
"local-address": "102.210.175.251", // nasIP (MikroTik IP)
|
||||
"name": "easyfi-ppp-profile",
|
||||
"only-one": "yes",
|
||||
"remote-address": "easyfi-ppp-pool-<vlan_id>",
|
||||
"use-compression": "default",
|
||||
"use-encryption": "default",
|
||||
"use-ipv6": "yes",
|
||||
"use-mpls": "default",
|
||||
"use-upnp": "default"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 5. Add a PPPoE Server
|
||||
```json
|
||||
{
|
||||
"address-list": "",
|
||||
"bridge-learning": "default",
|
||||
"change-tcp-mss": "yes",
|
||||
"default": "false",
|
||||
"dns-server": "8.8.8.8",
|
||||
"local-address": "102.210.175.251",
|
||||
"name": "easyfi-ppp-profile",
|
||||
"only-one": "yes",
|
||||
"remote-address": "easyfi-ppp-pool-2001",
|
||||
"use-compression": "default",
|
||||
"use-encryption": "default",
|
||||
"use-ipv6": "yes",
|
||||
"use-mpls": "default",
|
||||
"use-upnp": "default"
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Allowing User Authentication RADIUS Server
|
||||
```json
|
||||
{
|
||||
"accounting": "true",
|
||||
"interim-update": "3m",
|
||||
"use-circuit-id-in-nas-port-id": "false",
|
||||
"use-radius": "true"
|
||||
}
|
||||
```
|
||||
|
||||
### 7. Add a New RADIUS Server:
|
||||
```json
|
||||
{
|
||||
"accounting-port": "1813",
|
||||
"address": "<radius_server_ip>", // Received from the portal.
|
||||
"authentication-port": "1812",
|
||||
"disabled": "false",
|
||||
"protocol": "udp",
|
||||
"secret": "<radius_server_secret>", // Received from the portal.
|
||||
"service": "ppp,login,hotspot,dhcp",
|
||||
"timeout": "300ms"
|
||||
}
|
||||
```
|
||||
|
||||
### 8. Allow Incoming Communication from the RADIUS Server to the MikroTik Device
|
||||
```json
|
||||
{
|
||||
"accept": "yes",
|
||||
"port": "3799"
|
||||
}
|
||||
```
|
||||
|
||||
### 9. Add Firewall Rules for NAT-ing
|
||||
**NOTE:** Looping needed to split the bigger IP subnet into smaller subnets.
|
||||
```json
|
||||
{
|
||||
"action": "src-nat",
|
||||
"chain": "srcnat",
|
||||
"disabled": "false",
|
||||
"src-address": "100.64.0.16/28",
|
||||
"to-addresses": "111.222.111.111"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 10. Add a New SNMP Community
|
||||
```json
|
||||
{
|
||||
"addresses": "::/0",
|
||||
"authentication-password": "",
|
||||
"authentication-protocol": "MD5",
|
||||
"disabled": "false",
|
||||
"encryption-password": "",
|
||||
"encryption-protocol": "DES",
|
||||
"name": "<random_16_chars>",
|
||||
"read-access": "true",
|
||||
"security": "none",
|
||||
"write-access": "false" // ALWAYS FALSE
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
### General Notes:
|
||||
|
||||
- Master Block Private IP series used for Active Customers PPPoE and HotSpot range is 100.64.0.0/10
|
||||
- - Private IP series used for Active Customers PPPoE and is 100.64.0.0/16
|
||||
- Private IP series used for Active Customers HotSpot range is 100.65.0.0/16
|
||||
- Private IP series used for Deactivated Customers PPPoE range is 10.0.0.0/16
|
||||
|
||||
---
|
||||
|
||||
### Steps for PPPoE:
|
||||
|
||||
- Create IP Pool.
|
||||
- /ip/pool
|
||||
- Add a new pool with the `"Name"` set to `"permitted"` and `Addresses` set to `100.64.0.0/24`.
|
||||
- Add a new pool with the `"Name"` set to `"deactived"` and `Addresses` set to `10.0.0.0/16`.
|
||||
- Create a PPPoE profile.
|
||||
- /ppp/profiles
|
||||
- Add a local address (Local Address is the WAN IP of the MikroTik) to the profile.
|
||||
- Add a remote address to the profile with the `Name` set to `"permitted"`.
|
||||
- Add a DNS server to the profile.
|
||||
- Change `TCP MSS` to `"yes"`
|
||||
- Change `Limits -> Only One` to `"yes"`
|
||||
- /interface/pppoe-server
|
||||
- Add a new server.
|
||||
- Add service name (as per req.)
|
||||
- Select the interface.
|
||||
- Select the profile.
|
||||
- Select authentication mechanism (chap/pap/mschap1/mschap2).
|
||||
- Keepalive Timeout 900
|
||||
- /ppp/secret/ppp-authorization and accounting, select use radius and accounting.
|
||||
- Go to RADIUS
|
||||
- Add service (select: ppp, login, hotspot, dhcp)
|
||||
- Put in the RADIUS server's addr in the address col, select UDP as the protocol, put the secret.
|
||||
- Go to IP firewall.
|
||||
- NAT
|
||||
- Create source-map (as per req.)
|
||||
|
||||
---
|
||||
|
||||
### Steps for HotSpot:
|
||||
|
||||
- Create IP Pool.
|
||||
- /ip/pool
|
||||
- Add a new pool with the `"Name"` set to `"hotspot"` and `Addresses` set to `100.65.0.0/24`.
|
||||
- IP -> Hotspot -> Add -> Server Name = "New hotspot" -> Interface -> Pool -> Name = "hotspot" -> Add
|
||||
- IP -> Addresses -> Add -> Address -> First IP from the Hotspot IP Pool as the gateway (100.65.0.1/24)
|
||||
Reference in New Issue
Block a user