Move mqtt to a separate service
mqtt does not want to run under freeradius
This commit is contained in:
parent
d8bec448ad
commit
abd70a0d72
@ -5,3 +5,4 @@ policies
|
||||
requirements.txt
|
||||
*.ipt
|
||||
*.acl
|
||||
data
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -260,3 +260,5 @@ cython_debug/
|
||||
# acl files
|
||||
*.acl
|
||||
*.ipt
|
||||
|
||||
data/
|
||||
|
@ -2,6 +2,8 @@ import json
|
||||
import os
|
||||
import os.path
|
||||
from collections import defaultdict
|
||||
from typing import List
|
||||
import time
|
||||
|
||||
import netaddr
|
||||
import paho.mqtt.client as mqtt
|
||||
@ -15,7 +17,7 @@ def log(level, s):
|
||||
|
||||
# The callback for when the client receives a CONNACK response from the server.
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
print("Connected with result code " + str(rc))
|
||||
log(radiusd.L_INFO, "Connected with result code " + str(rc))
|
||||
|
||||
# Subscribing in on_connect() means that if we lose the connection and
|
||||
# reconnect then subscriptions will be renewed.
|
||||
@ -23,39 +25,19 @@ def on_connect(client, userdata, flags, rc):
|
||||
|
||||
|
||||
def get_leases():
|
||||
msgs = defaultdict(lambda: defaultdict(str))
|
||||
with open("/config/leases.json", encoding="utf-8") as file:
|
||||
msgs = defaultdict(lambda: defaultdict(str), json.loads(file.read()))
|
||||
|
||||
# The callback for when a PUBLISH message is received from the server.
|
||||
def on_message(client, userdata, msg):
|
||||
lease = json.loads(msg.payload)
|
||||
lease["identifier"] = os.path.basename(msg.topic)
|
||||
msgs[lease["identifier"]] = defaultdict(str, lease)
|
||||
|
||||
client = mqtt.Client()
|
||||
client.username_pw_set(os.getenv("MQTT_USERNAME"), os.getenv("MQTT_PASSWORD"))
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
|
||||
client.connect("hassio.narnian.us", 1883, 60)
|
||||
|
||||
cont = True
|
||||
count = 0
|
||||
while cont:
|
||||
client.loop(timeout=0.5)
|
||||
client.loop(timeout=0.5)
|
||||
client.loop(timeout=0.5)
|
||||
client.loop(timeout=0.5)
|
||||
if count == len(msgs):
|
||||
break
|
||||
count = len(msgs)
|
||||
return msgs
|
||||
|
||||
|
||||
def select_acls(lease):
|
||||
log(radiusd.L_INFO, str(lease))
|
||||
log(radiusd.L_INFO, str(lease["vendor_identifier"]))
|
||||
acls = []
|
||||
if lease["vendor_identifier"].contains("PS4"):
|
||||
acls.append("DENY")
|
||||
acls.append("WEB")
|
||||
if "MSFT" in lease["vendor_identifier"]:
|
||||
acls.append("windows")
|
||||
acls.append("web")
|
||||
|
||||
return acls
|
||||
|
||||
@ -65,21 +47,39 @@ def ciscoize_acl_names(acls):
|
||||
for acl in acls:
|
||||
cisco.append(
|
||||
tuple(
|
||||
"Cisco-AVPair",
|
||||
"+=",
|
||||
f"ACS:CiscoSecure-Defined-ACL=#ACSACL#-${acl}-fuckcisc",
|
||||
[
|
||||
"Cisco-AVPair",
|
||||
"+=",
|
||||
f"ACS:CiscoSecure-Defined-ACL=#ACSACL#-IP-{acl}-588b68cd",
|
||||
]
|
||||
)
|
||||
)
|
||||
log(radiusd.L_INFO, str(cisco))
|
||||
return cisco
|
||||
|
||||
|
||||
def deciscoize_acl_name(acl_name):
|
||||
return acl_name.split("#ACSACL#-")[1][0:-9]
|
||||
return acl_name.split("#ACSACL#-IP-")[1][0:-9]
|
||||
|
||||
|
||||
def get_acl(acl_name):
|
||||
with open(acl_name, encoding="utf-8") as f:
|
||||
return f.read()
|
||||
with open(f"acl/{acl_name}.acl", encoding="utf-8") as file:
|
||||
return file.read().splitlines()
|
||||
|
||||
|
||||
def ciscoize_acl(acl: List[str]):
|
||||
cisco = []
|
||||
for i, line in enumerate(acl):
|
||||
cisco.append(
|
||||
tuple(
|
||||
[
|
||||
"Cisco-AVPair",
|
||||
"+=",
|
||||
f"ip:inacl#{i+1}={line}",
|
||||
]
|
||||
)
|
||||
)
|
||||
return cisco
|
||||
|
||||
|
||||
def authorize(p):
|
||||
@ -99,11 +99,14 @@ def authorize(p):
|
||||
]
|
||||
|
||||
if netaddr.valid_mac(request["User-Name"]):
|
||||
mac = netaddr.EUI(request["User-Name"])
|
||||
mac.dialect = netaddr.mac_unix_expanded
|
||||
leases = get_leases()
|
||||
log(radiusd.L_INFO, str(leases))
|
||||
|
||||
reply.extend(ciscoize_acl_names(select_acls(leases[request["User-Name"]])))
|
||||
reply.extend(ciscoize_acl_names(select_acls(leases[str(mac)])))
|
||||
elif "#ACSACL#" in request["User-Name"]:
|
||||
deciscoize_acl_name(request["User-Name"])
|
||||
reply.extend(ciscoize_acl(get_acl(deciscoize_acl_name(request["User-Name"]))))
|
||||
|
||||
conf = [
|
||||
("Auth-Type", "Accept"),
|
||||
|
@ -7,7 +7,7 @@ header {
|
||||
# NOTES: iptables produces filter 'lines' that must be used as args to the
|
||||
# '$ iptables' cmd, while Speedway produces stateful iptables filters
|
||||
# compatible with iptables-restore (most people will prefer speedway)
|
||||
target:: cisco default-web extended
|
||||
target:: cisco web extended
|
||||
target:: speedway INPUT
|
||||
}
|
||||
|
||||
|
4
root/etc/services.d/mqtt/run
Executable file
4
root/etc/services.d/mqtt/run
Executable file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
|
||||
exec \
|
||||
s6-setuidgid abc /usr/bin/mqtt.py /config/leases.json
|
49
root/usr/bin/mqtt.py
Executable file
49
root/usr/bin/mqtt.py
Executable file
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python3
|
||||
import json
|
||||
import os.path
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
|
||||
# The callback for when the client receives a CONNACK response from the server.
|
||||
def on_connect(client, userdata, flags, rc):
|
||||
print("Connected with result code " + str(rc))
|
||||
|
||||
# Subscribing in on_connect() means that if we lose the connection and
|
||||
# reconnect then subscriptions will be renewed.
|
||||
client.subscribe("router7/#")
|
||||
|
||||
|
||||
def get_leases():
|
||||
msgs = defaultdict(lambda: defaultdict(str))
|
||||
|
||||
# The callback for when a PUBLISH message is received from the server.
|
||||
def on_message(client, userdata, msg):
|
||||
lease = json.loads(msg.payload)
|
||||
lease["identifier"] = os.path.basename(msg.topic)
|
||||
msgs[lease["hardware_addr"].lower()] = defaultdict(str, lease)
|
||||
with open(sys.argv[1], mode="w", encoding="utf-8") as file:
|
||||
file.write(json.dumps(msgs) + "\n")
|
||||
|
||||
client = mqtt.Client()
|
||||
client.username_pw_set(os.getenv("MQTT_USERNAME"), os.getenv("MQTT_PASSWORD"))
|
||||
client.on_connect = on_connect
|
||||
client.on_message = on_message
|
||||
|
||||
client.connect("hassio.narnian.us", 1883, 60)
|
||||
|
||||
# Blocking call that processes network traffic, dispatches callbacks and
|
||||
# handles reconnecting.
|
||||
# Other loop*() functions are available that give a threaded interface and a
|
||||
# manual interface.
|
||||
|
||||
cont = True
|
||||
while cont:
|
||||
client.loop(timeout=0.5)
|
||||
return msgs
|
||||
|
||||
|
||||
for m in get_leases():
|
||||
print(json.dumps(m))
|
Loading…
x
Reference in New Issue
Block a user