make a useful cli
This commit is contained in:
parent
291a287141
commit
dfb2b9d956
|
@ -1,5 +1,7 @@
|
||||||
|
import asyncio
|
||||||
import binascii
|
import binascii
|
||||||
from typing import Optional
|
import secrets
|
||||||
|
from typing import Optional, Any
|
||||||
|
|
||||||
from pyroute2 import IPRoute, WireGuard
|
from pyroute2 import IPRoute, WireGuard
|
||||||
|
|
||||||
|
@ -9,9 +11,28 @@ from .database import Database, Node, SERVER_NODE_ID
|
||||||
|
|
||||||
IFNAME = 'leyline-wg'
|
IFNAME = 'leyline-wg'
|
||||||
DEFAULT_PORT = 31337
|
DEFAULT_PORT = 31337
|
||||||
|
API_PORT = 31338
|
||||||
db = Database("leylines.db")
|
db = Database("leylines.db")
|
||||||
|
|
||||||
|
|
||||||
|
async def client_connected(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
line = reader.readline()
|
||||||
|
if line.strip() != db.get_token():
|
||||||
|
raise Exception("unauthorized")
|
||||||
|
# TODO
|
||||||
|
finally:
|
||||||
|
writer.close()
|
||||||
|
await writer.wait_closed()
|
||||||
|
|
||||||
|
|
||||||
|
async def main() -> None:
|
||||||
|
sync_interface()
|
||||||
|
server = await asyncio.create_server(client_connected, host="127.0.0.1", port=API_PORT)
|
||||||
|
await server.serve_forever()
|
||||||
|
|
||||||
|
|
||||||
def net_init() -> None:
|
def net_init() -> None:
|
||||||
with open("/proc/sys/net/ipv4/ip_forward", "w") as f:
|
with open("/proc/sys/net/ipv4/ip_forward", "w") as f:
|
||||||
f.write("1")
|
f.write("1")
|
||||||
|
@ -62,6 +83,7 @@ def add_node_to_wg(wg: WireGuard, node: Node) -> None:
|
||||||
|
|
||||||
|
|
||||||
def create_or_get_interface() -> int:
|
def create_or_get_interface() -> int:
|
||||||
|
net_init()
|
||||||
with IPRoute() as ipr:
|
with IPRoute() as ipr:
|
||||||
lookup = ipr.link_lookup(ifname=IFNAME)
|
lookup = ipr.link_lookup(ifname=IFNAME)
|
||||||
if len(lookup) > 0:
|
if len(lookup) > 0:
|
||||||
|
|
|
@ -1,5 +1,65 @@
|
||||||
from leylines import net_init, create_or_get_interface, sync_interface
|
import argparse
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
net_init()
|
from leylines import main, db, sync_interface, seckey_to_pubkey, generate_node_config
|
||||||
create_or_get_interface()
|
from leylines.database import SERVER_NODE_ID
|
||||||
sync_interface()
|
|
||||||
|
|
||||||
|
def nop():
|
||||||
|
# needed because setup.py is weird
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description="wireguard management system for dragons")
|
||||||
|
cmd = parser.add_subparsers(dest="cmd")
|
||||||
|
cmd.required = True
|
||||||
|
|
||||||
|
cmd_daemon = cmd.add_parser("daemon")
|
||||||
|
|
||||||
|
cmd_status = cmd.add_parser("status")
|
||||||
|
|
||||||
|
cmd_init = cmd.add_parser("init")
|
||||||
|
cmd_init.add_argument("-n", "--name", type=str, help="Name of the server node", required=True)
|
||||||
|
cmd_init.add_argument("-i", "--ip", type=str, help="Public IP of the server node", required=True)
|
||||||
|
|
||||||
|
cmd_add = cmd.add_parser("add")
|
||||||
|
cmd_add.add_argument("-n", "--name", type=str, help="Name of the node to add", required=True)
|
||||||
|
cmd_add.add_argument("-i", "--ip", type=str, help="Public IP of the node, if any", required=False)
|
||||||
|
cmd_add.add_argument("-k", "--ssh-key", type=argparse.FileType("r"),
|
||||||
|
help="SSH private keyfile for the node, if any", required=False)
|
||||||
|
|
||||||
|
cmd_get_conf = cmd.add_parser("get-conf")
|
||||||
|
cmd_get_conf.add_argument("id", type=int, help="Node ID")
|
||||||
|
|
||||||
|
cmd_sync = cmd.add_parser("sync")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.cmd == "daemon":
|
||||||
|
asyncio.run(main())
|
||||||
|
elif args.cmd == "status":
|
||||||
|
token = db.get_token()
|
||||||
|
subnet = db.get_subnet()
|
||||||
|
nodes = db.get_nodes()
|
||||||
|
server_node = db.get_server_node()
|
||||||
|
print("TOKEN:", token)
|
||||||
|
print("SUBNET:", subnet)
|
||||||
|
if server_node is None:
|
||||||
|
print("SERVER: <not defined. run leylines init>")
|
||||||
|
else:
|
||||||
|
print("SERVER:", server_node.name, server_node.ip, server_node.public_ip,
|
||||||
|
seckey_to_pubkey(server_node.seckey))
|
||||||
|
for node in nodes:
|
||||||
|
if node.id == SERVER_NODE_ID:
|
||||||
|
continue
|
||||||
|
print(f"NODE {node.id}:", node.name, node.public_ip, node.ip,
|
||||||
|
seckey_to_pubkey(node.seckey), "<Have SSH Key>" if node.ssh_key is not None else "")
|
||||||
|
elif args.cmd == "init":
|
||||||
|
db.init_server(args.name, ipaddress.IPv4Address(args.ip))
|
||||||
|
elif args.cmd == "add":
|
||||||
|
db.add_node(args.name, args.ip, args.ssh_key.read() if args.ssh_key is not None else None)
|
||||||
|
sync_interface()
|
||||||
|
elif args.cmd == "get-conf":
|
||||||
|
print(generate_node_config(args.id))
|
||||||
|
elif args.cmd == "sync":
|
||||||
|
sync_interface()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import binascii
|
import binascii
|
||||||
import ipaddress
|
import ipaddress
|
||||||
|
import secrets
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from typing import Iterable, List, NamedTuple, Optional, Set
|
from typing import Iterable, List, NamedTuple, Optional, Set
|
||||||
|
|
||||||
|
@ -38,6 +39,9 @@ class Database:
|
||||||
"CREATE TABLE IF NOT EXISTS settings (name TEXT PRIMARY KEY, value TEXT NOT NULL)")
|
"CREATE TABLE IF NOT EXISTS settings (name TEXT PRIMARY KEY, value TEXT NOT NULL)")
|
||||||
self.conn.execute(
|
self.conn.execute(
|
||||||
"INSERT OR IGNORE INTO settings (name, value) VALUES ('subnet', ?)", (DEFAULT_SUBNET,))
|
"INSERT OR IGNORE INTO settings (name, value) VALUES ('subnet', ?)", (DEFAULT_SUBNET,))
|
||||||
|
self.conn.execute(
|
||||||
|
"INSERT OR IGNORE INTO settings (name, value) VALUES ('token', ?)",
|
||||||
|
(secrets.token_hex(32),))
|
||||||
|
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
|
@ -51,6 +55,11 @@ class Database:
|
||||||
cur.execute("SELECT value FROM settings WHERE name='subnet'")
|
cur.execute("SELECT value FROM settings WHERE name='subnet'")
|
||||||
return ipaddress.IPv4Interface(cur.fetchone()[0])
|
return ipaddress.IPv4Interface(cur.fetchone()[0])
|
||||||
|
|
||||||
|
def get_token(self) -> str:
|
||||||
|
cur = self.conn.cursor()
|
||||||
|
cur.execute("SELECT value FROM settings WHERE name='token'")
|
||||||
|
return cur.fetchone()[0]
|
||||||
|
|
||||||
def _get_free_ip(self) -> ipaddress.IPv4Address:
|
def _get_free_ip(self) -> ipaddress.IPv4Address:
|
||||||
subnet = self.get_subnet().network
|
subnet = self.get_subnet().network
|
||||||
subnets = [self.get_subnet().network]
|
subnets = [self.get_subnet().network]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
|
||||||
setup(name='leylines',
|
setup(
|
||||||
|
name='leylines',
|
||||||
version='0.1',
|
version='0.1',
|
||||||
description='Sample text',
|
description='Sample text',
|
||||||
url='https://awoo.systems',
|
url='https://awoo.systems',
|
||||||
|
@ -9,12 +10,13 @@ setup(name='leylines',
|
||||||
license='AGPLv3',
|
license='AGPLv3',
|
||||||
packages=['leylines'],
|
packages=['leylines'],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
# requirements
|
"leylines-monocypher",
|
||||||
|
"pyroute2"
|
||||||
],
|
],
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
# bins
|
"leylines=leylines.__main__:nop"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
zip_safe=True)
|
zip_safe=True)
|
||||||
|
|
Loading…
Reference in New Issue