subnet and encoder plugins added. stable diffusion fix. updated requirements.txt
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
plugins/subnet.py – Subnet calculator and network splitting plugin for Funguy Bot.
|
||||
|
||||
Provides the following commands:
|
||||
!subnet info <CIDR> – Show detailed info about a network
|
||||
!subnet split <CIDR> --prefix <N> – Split network into smaller subnets (new prefix length)
|
||||
!subnet split <CIDR> --diff <N> – Split network into equal subnets (prefixlen delta)
|
||||
!subnet adjacent <CIDR> <count> – Show given network and next <count> adjacent ones
|
||||
!subnet help – Display this help
|
||||
|
||||
Examples:
|
||||
!subnet info 192.168.4.0/26
|
||||
!subnet split 192.168.4.0/24 --prefix 26
|
||||
!subnet split 10.0.0.0/16 --diff 2
|
||||
!subnet adjacent 192.168.4.0/26 3
|
||||
"""
|
||||
|
||||
import ipaddress
|
||||
import sys
|
||||
from typing import Union
|
||||
|
||||
# ------------------------------- helper functions --------------------------------
|
||||
|
||||
def _fmt_subnet_info(net: Union[ipaddress.IPv4Network, ipaddress.IPv6Network]) -> str:
|
||||
"""Return a human‑readable string with all relevant subnet details."""
|
||||
nw = net.network_address
|
||||
bc = net.broadcast_address if hasattr(net, "broadcast_address") else None
|
||||
total = net.num_addresses
|
||||
|
||||
if net.version == 4:
|
||||
if net.prefixlen == 32:
|
||||
usable_count = 1
|
||||
first = last = nw
|
||||
elif net.prefixlen == 31:
|
||||
usable_count = 2
|
||||
first = nw
|
||||
last = bc
|
||||
else:
|
||||
usable_count = max(0, total - 2)
|
||||
first = nw + 1 if usable_count > 0 else None
|
||||
last = bc - 1 if usable_count > 0 else None
|
||||
else:
|
||||
hosts_iter = net.hosts()
|
||||
try:
|
||||
first = next(hosts_iter)
|
||||
last = net.network_address + (total - 1)
|
||||
usable_count = total
|
||||
except StopIteration:
|
||||
first = last = None
|
||||
usable_count = 0
|
||||
|
||||
lines = [
|
||||
f"CIDR: {net.with_prefixlen}",
|
||||
f"Network: {nw}",
|
||||
f"Broadcast: {bc if bc is not None else 'N/A'}",
|
||||
f"Netmask: {net.netmask if hasattr(net, 'netmask') else 'N/A'}",
|
||||
f"Wildcard Mask: {net.hostmask if hasattr(net, 'hostmask') else 'N/A'}",
|
||||
f"Total IPs: {total}",
|
||||
f"Usable Hosts: {usable_count}",
|
||||
]
|
||||
if first is not None and last is not None:
|
||||
lines.append(f"First Usable: {first}")
|
||||
lines.append(f"Last Usable: {last}")
|
||||
lines.append(f"Usable Range: {first} - {last}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _split_by_prefix(net, new_prefix: int) -> str:
|
||||
if new_prefix < net.prefixlen:
|
||||
return f"[!] New prefix /{new_prefix} is smaller than current prefix /{net.prefixlen}. Cannot split."
|
||||
out = [f"# Splitting {net.with_prefixlen} into /{new_prefix} subnets:"]
|
||||
for i, sub in enumerate(net.subnets(new_prefix=new_prefix)):
|
||||
out.append(f"\n-- Subnet #{i+1} --")
|
||||
out.append(_fmt_subnet_info(sub))
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def _split_by_diff(net, diff: int) -> str:
|
||||
new_prefix = net.prefixlen + diff
|
||||
return _split_by_prefix(net, new_prefix)
|
||||
|
||||
|
||||
def _adjacent_networks(net, count: int) -> str:
|
||||
out = [f"# Adjacent networks of size /{net.prefixlen} (starting at {net.with_prefixlen}):"]
|
||||
current = net
|
||||
for i in range(count + 1):
|
||||
out.append(f"\n-- Adjacent #{i} --")
|
||||
out.append(_fmt_subnet_info(current))
|
||||
try:
|
||||
next_net_addr = current.network_address + current.num_addresses
|
||||
current = ipaddress.ip_network(f"{next_net_addr}/{current.prefixlen}", strict=True)
|
||||
except ValueError:
|
||||
out.append("[!] Reached address space limit.")
|
||||
break
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
# ------------------------------- bot plugin entry -------------------------------
|
||||
|
||||
async def handle_command(room, message, bot, prefix, config):
|
||||
import simplematrixbotlib as botlib
|
||||
match = botlib.MessageMatch(room, message, bot, prefix)
|
||||
|
||||
if not (match.is_not_from_this_bot() and match.prefix() and match.command("subnet")):
|
||||
return
|
||||
|
||||
args = match.args()
|
||||
if not args:
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
"Usage: !subnet <info|split|adjacent> ...\n"
|
||||
" !subnet help – show full help"
|
||||
)
|
||||
return
|
||||
|
||||
subcmd = args[0].lower()
|
||||
|
||||
# --- help ---
|
||||
if subcmd in ("help", "-h", "--help"):
|
||||
# Send nicely formatted HTML in a details tag via markdown
|
||||
html = "<details><summary><strong>!subnet</strong> – Subnet calculator and exploration</summary>\n"
|
||||
html += "<p>Calculate subnet details, split networks, or enumerate adjacent subnets.</p>\n"
|
||||
html += "<h4>Commands</h4>\n"
|
||||
html += "<ul>\n"
|
||||
html += "<li><b>info</b> – Show detailed info for a network<br>\n"
|
||||
html += "<code>!subnet info <CIDR></code><br>\n"
|
||||
html += "Example: <code>!subnet info 192.168.1.0/24</code></li>\n"
|
||||
html += "<li><b>split</b> – Split a network into smaller subnets<br>\n"
|
||||
html += "<code>!subnet split <CIDR> --prefix <new_prefix></code><br>\n"
|
||||
html += "Example: <code>!subnet split 192.168.1.0/24 --prefix 26</code><br>\n"
|
||||
html += "<i>Alternatively, use --diff to split by prefix delta:</i><br>\n"
|
||||
html += "<code>!subnet split <CIDR> --diff <delta></code><br>\n"
|
||||
html += "Example: <code>!subnet split 10.0.0.0/16 --diff 2</code> (creates 4 subnets)</li>\n"
|
||||
html += "<li><b>adjacent</b> – Show the current network and adjacent ones<br>\n"
|
||||
html += "<code>!subnet adjacent <CIDR> <count></code><br>\n"
|
||||
html += "Example: <code>!subnet adjacent 192.168.4.0/26 3</code></li>\n"
|
||||
html += "</ul>\n"
|
||||
html += "<h4>Notes</h4>\n"
|
||||
html += "<ul>\n"
|
||||
html += "<li>IPv4 /31 and /32 networks show both addresses as usable (RFC 3021).</li>\n"
|
||||
html += "<li>IPv6 networks list all addresses as hosts (no broadcast).</li>\n"
|
||||
html += "</ul>\n"
|
||||
html += "</details>"
|
||||
await bot.api.send_markdown_message(room.room_id, html)
|
||||
return
|
||||
|
||||
# --- info (or a CIDR passed directly) ---
|
||||
if subcmd == "info" or "/" in subcmd:
|
||||
cidr = args[1] if subcmd == "info" else subcmd
|
||||
try:
|
||||
net = ipaddress.ip_network(cidr, strict=False)
|
||||
except ValueError as e:
|
||||
await bot.api.send_text_message(room.room_id, f"[!] Invalid CIDR: {e}")
|
||||
return
|
||||
await bot.api.send_text_message(room.room_id, _fmt_subnet_info(net))
|
||||
return
|
||||
|
||||
# --- split ---
|
||||
if subcmd == "split":
|
||||
if len(args) < 2:
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
"Usage: !subnet split <CIDR> --prefix <new_prefix> OR --diff <delta>"
|
||||
)
|
||||
return
|
||||
cidr = args[1]
|
||||
try:
|
||||
net = ipaddress.ip_network(cidr, strict=False)
|
||||
except ValueError as e:
|
||||
await bot.api.send_text_message(room.room_id, f"[!] Invalid CIDR: {e}")
|
||||
return
|
||||
|
||||
if "--prefix" in args:
|
||||
try:
|
||||
idx = args.index("--prefix")
|
||||
new_prefix = int(args[idx + 1])
|
||||
except (ValueError, IndexError):
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
"Usage: !subnet split <CIDR> --prefix <number>"
|
||||
)
|
||||
return
|
||||
result = _split_by_prefix(net, new_prefix)
|
||||
elif "--diff" in args:
|
||||
try:
|
||||
idx = args.index("--diff")
|
||||
diff = int(args[idx + 1])
|
||||
except (ValueError, IndexError):
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
"Usage: !subnet split <CIDR> --diff <delta>"
|
||||
)
|
||||
return
|
||||
result = _split_by_diff(net, diff)
|
||||
else:
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
"You must provide either --prefix <N> or --diff <N> for split."
|
||||
)
|
||||
return
|
||||
await bot.api.send_text_message(room.room_id, result)
|
||||
return
|
||||
|
||||
# --- adjacent ---
|
||||
if subcmd == "adjacent":
|
||||
if len(args) < 3:
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
"Usage: !subnet adjacent <CIDR> <count>"
|
||||
)
|
||||
return
|
||||
cidr = args[1]
|
||||
try:
|
||||
net = ipaddress.ip_network(cidr, strict=False)
|
||||
except ValueError as e:
|
||||
await bot.api.send_text_message(room.room_id, f"[!] Invalid CIDR: {e}")
|
||||
return
|
||||
try:
|
||||
count = int(args[2])
|
||||
except ValueError:
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
"Count must be an integer."
|
||||
)
|
||||
return
|
||||
result = _adjacent_networks(net, count)
|
||||
await bot.api.send_text_message(room.room_id, result)
|
||||
return
|
||||
|
||||
# Unknown subcommand
|
||||
await bot.api.send_text_message(
|
||||
room.room_id,
|
||||
f"Unknown subcommand '{subcmd}'. Use !subnet help to see available commands."
|
||||
)
|
||||
|
||||
|
||||
# Plugin metadata
|
||||
__version__ = "1.0.1"
|
||||
__author__ = "Funguy Bot"
|
||||
__description__ = "Subnet calculator, splitter, and adjacent network enumerator"
|
||||
__help__ = """
|
||||
<details>
|
||||
<summary><strong>!subnet</strong> – Subnet calculator and exploration</summary>
|
||||
<p>Calculate subnet details, split networks, or enumerate adjacent subnets.</p>
|
||||
<ul>
|
||||
<li><code>!subnet info <CIDR></code> – Show detailed info for a network<br>
|
||||
Example: <code>!subnet info 192.168.1.0/24</code></li>
|
||||
<li><code>!subnet split <CIDR> --prefix <new_prefix></code> – Split into smaller subnets<br>
|
||||
Example: <code>!subnet split 192.168.1.0/24 --prefix 26</code></li>
|
||||
<li><code>!subnet split <CIDR> --diff <delta></code> – Split by prefix delta<br>
|
||||
Example: <code>!subnet split 10.0.0.0/16 --diff 2</code></li>
|
||||
<li><code>!subnet adjacent <CIDR> <count></code> – Show adjacent networks<br>
|
||||
Example: <code>!subnet adjacent 192.168.4.0/26 3</code></li>
|
||||
</ul>
|
||||
</details>
|
||||
"""
|
||||
Reference in New Issue
Block a user