make a useful cli

This commit is contained in:
xenia 2021-06-15 00:01:58 -04:00
parent 291a287141
commit dfb2b9d956
4 changed files with 116 additions and 23 deletions

View File

@ -1,5 +1,7 @@
import asyncio
import binascii
from typing import Optional
import secrets
from typing import Optional, Any
from pyroute2 import IPRoute, WireGuard
@ -9,9 +11,28 @@ from .database import Database, Node, SERVER_NODE_ID
IFNAME = 'leyline-wg'
DEFAULT_PORT = 31337
API_PORT = 31338
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:
with open("/proc/sys/net/ipv4/ip_forward", "w") as f:
f.write("1")
@ -62,6 +83,7 @@ def add_node_to_wg(wg: WireGuard, node: Node) -> None:
def create_or_get_interface() -> int:
net_init()
with IPRoute() as ipr:
lookup = ipr.link_lookup(ifname=IFNAME)
if len(lookup) > 0:

View File

@ -1,5 +1,65 @@
from leylines import net_init, create_or_get_interface, sync_interface
import argparse
import ipaddress
net_init()
create_or_get_interface()
from leylines import main, db, sync_interface, seckey_to_pubkey, generate_node_config
from leylines.database import SERVER_NODE_ID
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()

View File

@ -1,5 +1,6 @@
import binascii
import ipaddress
import secrets
import sqlite3
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)")
self.conn.execute(
"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()
@ -51,6 +55,11 @@ class Database:
cur.execute("SELECT value FROM settings WHERE name='subnet'")
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:
subnet = self.get_subnet().network
subnets = [self.get_subnet().network]

View File

@ -1,6 +1,7 @@
from setuptools import setup
setup(name='leylines',
setup(
name='leylines',
version='0.1',
description='Sample text',
url='https://awoo.systems',
@ -9,12 +10,13 @@ setup(name='leylines',
license='AGPLv3',
packages=['leylines'],
install_requires=[
# requirements
"leylines-monocypher",
"pyroute2"
],
include_package_data=True,
entry_points={
'console_scripts': [
# bins
"leylines=leylines.__main__:nop"
]
},
zip_safe=True)