From cf7d55d71a8a8b2ad88370a46881e81d826b81b0 Mon Sep 17 00:00:00 2001 From: Per-Arne Date: Sat, 9 May 2020 23:13:05 +0200 Subject: [PATCH] * Breaking changes: Must remove subnet from client configurations in dashboard * Added subnet support as described in #11 --- wg_dashboard_backend/main.py | 2 +- .../versions/004_create_server_subnet.py | 21 +++++++++++++++++++ wg_dashboard_backend/models.py | 1 + wg_dashboard_backend/routers/v1/peer.py | 4 ++-- wg_dashboard_backend/schemas.py | 1 + wg_dashboard_backend/templates/peer.j2 | 2 +- wg_dashboard_backend/templates/server.j2 | 4 ++-- .../src/app/interfaces/server.ts | 1 + .../add-server/add-server.component.html | 15 +++++++++++-- .../add-server/add-server.component.ts | 18 +++++++++++----- .../app/page/dashboard/dashboard.module.ts | 2 ++ .../dashboard/server/server.component.html | 2 +- .../app/validators/ip-address.validator.ts | 2 +- 13 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 wg_dashboard_backend/migrations/versions/004_create_server_subnet.py diff --git a/wg_dashboard_backend/main.py b/wg_dashboard_backend/main.py index 00a0fce..a876841 100644 --- a/wg_dashboard_backend/main.py +++ b/wg_dashboard_backend/main.py @@ -37,7 +37,7 @@ _db: Session = SessionLocal() if not database_exists(engine.url): ADMIN_USERNAME = os.getenv("ADMIN_USERNAME") if not ADMIN_USERNAME: - raise RuntimeError("Database does not exist and no ADMIN_USER is set") + raise RuntimeError("Database does not exist and no ADMIN_USERNAME is set") ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD") diff --git a/wg_dashboard_backend/migrations/versions/004_create_server_subnet.py b/wg_dashboard_backend/migrations/versions/004_create_server_subnet.py new file mode 100644 index 0000000..539a81d --- /dev/null +++ b/wg_dashboard_backend/migrations/versions/004_create_server_subnet.py @@ -0,0 +1,21 @@ +from sqlalchemy import * +from migrate import * + + +def upgrade(migrate_engine): + try: + meta = MetaData(bind=migrate_engine) + server = Table('server', meta, autoload=True) + subnet = Column('subnet', Text) + subnet.create(server) + except: + pass + + +def downgrade(migrate_engine): + try: + meta = MetaData(bind=migrate_engine) + server = Table('server', meta, autoload=True) + server.c.subnet.drop() + except: + pass diff --git a/wg_dashboard_backend/models.py b/wg_dashboard_backend/models.py index 0e4a07d..0b615d5 100644 --- a/wg_dashboard_backend/models.py +++ b/wg_dashboard_backend/models.py @@ -21,6 +21,7 @@ class WGServer(Base): id = Column(Integer, primary_key=True, index=True) interface = Column(sqlalchemy.String, unique=True, index=True) + subnet = Column(sqlalchemy.Integer, nullable=False) address = Column(sqlalchemy.String, unique=True) listen_port = Column(sqlalchemy.String, unique=True) private_key = Column(sqlalchemy.String) diff --git a/wg_dashboard_backend/routers/v1/peer.py b/wg_dashboard_backend/routers/v1/peer.py index c81aa08..c49c903 100644 --- a/wg_dashboard_backend/routers/v1/peer.py +++ b/wg_dashboard_backend/routers/v1/peer.py @@ -21,7 +21,7 @@ def add_peer( server = schemas.WGServer(interface=peer_add.server_interface).from_db(sess) peer = schemas.WGPeer(server_id=server.id) - address_space = set(ipaddress.ip_network(server.address, strict=False).hosts()) + address_space = set(ipaddress.ip_network(f"{server.address}/{server.subnet}", strict=False).hosts()) occupied_space = set() # Try add server IP to list. @@ -41,7 +41,7 @@ def add_peer( address_space -= occupied_space # Select first available address - peer.address = str(list(sorted(address_space)).pop(0)) + "/32" + peer.address = str(list(sorted(address_space)).pop(0)) # Private public key generation keys = script.wireguard.generate_keys() diff --git a/wg_dashboard_backend/schemas.py b/wg_dashboard_backend/schemas.py index 6a53614..d98c08a 100644 --- a/wg_dashboard_backend/schemas.py +++ b/wg_dashboard_backend/schemas.py @@ -144,6 +144,7 @@ class PSK(GenericModel): class WGServer(GenericModel): id: int = None address: str = None + subnet: int = None interface: str listen_port: int = None endpoint: str = None diff --git a/wg_dashboard_backend/templates/peer.j2 b/wg_dashboard_backend/templates/peer.j2 index c02656a..5639bff 100644 --- a/wg_dashboard_backend/templates/peer.j2 +++ b/wg_dashboard_backend/templates/peer.j2 @@ -1,5 +1,5 @@ [Interface] -Address = {{ data.peer.address.replace("/32", "/24") }} +Address = {{ data.peer.address }}/{{ data.server.subnet }} PrivateKey = {{ data.peer.private_key }} DNS = {{ data.peer.dns }} diff --git a/wg_dashboard_backend/templates/server.j2 b/wg_dashboard_backend/templates/server.j2 index e4f50dd..4f1c83c 100644 --- a/wg_dashboard_backend/templates/server.j2 +++ b/wg_dashboard_backend/templates/server.j2 @@ -1,5 +1,5 @@ [Interface] -Address = {{ data.address }} +Address = {{ data.address }}/{{ data.subnet }} ListenPort = {{ data.listen_port }} PrivateKey = {{ data.private_key }} @@ -13,5 +13,5 @@ PublicKey = {{ peer.public_key }} {%- if peer.shared_key %} PresharedKey = {{ peer.shared_key }} {%- endif %} -AllowedIPs = {{ peer.address }} +AllowedIPs = {{ peer.address }}/32 {% endfor %} diff --git a/wg_dashboard_frontend/src/app/interfaces/server.ts b/wg_dashboard_frontend/src/app/interfaces/server.ts index fb0d536..5c28a10 100644 --- a/wg_dashboard_frontend/src/app/interfaces/server.ts +++ b/wg_dashboard_frontend/src/app/interfaces/server.ts @@ -12,5 +12,6 @@ export interface Server { post_up: string; post_down: string; configuration: string; + subnet: number; peers: Peer[]; } diff --git a/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.html b/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.html index a30a80a..e32498a 100644 --- a/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.html +++ b/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.html @@ -29,10 +29,21 @@ - Address Scope - + Address + + + + + Subnet + + + + + diff --git a/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.ts b/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.ts index ab81121..2262814 100644 --- a/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.ts +++ b/wg_dashboard_frontend/src/app/page/dashboard/add-server/add-server.component.ts @@ -5,10 +5,10 @@ import { NumberValidator } from '../../../validators/number.validator'; import { Server } from '../../../interfaces/server'; import { ServerService } from '../../../services/server.service'; import { DataService } from '../../../services/data.service'; -import Parser, {Property, Section, Sections} from "@jedmao/ini-parser"; +import Parser, {Section} from "@jedmao/ini-parser"; import {Peer} from "../../../interfaces/peer"; -import {forkJoin, from, Observable, of} from "rxjs"; -import {concatAll, concatMap, filter, map, mergeAll, mergeMap, switchMap} from "rxjs/operators"; +import {forkJoin, from} from "rxjs"; +import {map, mergeMap} from "rxjs/operators"; import {NotifierService} from "angular-notifier"; @Component({ selector: 'app-add-server', @@ -34,13 +34,17 @@ export class AddServerComponent implements OnInit { "DNS": "dns" } + subnets = []; + selectedSubnet = 24; + serverForm: FormGroup = null; isEdit = false; editServer: Server = null; initForm(){ this.serverForm = new FormGroup({ - address: new FormControl('', [IPValidator.isIPAddress]), + address: new FormControl('', [Validators.required, IPValidator.isIPAddress]), + subnet: new FormControl('', [Validators.required, Validators.min(1), Validators.max(32)]), interface: new FormControl('', [Validators.required, Validators.minLength(3)]), listen_port: new FormControl('', [Validators.required, NumberValidator.stringIsNumber]), endpoint: new FormControl('', Validators.required), @@ -62,6 +66,7 @@ export class AddServerComponent implements OnInit { } ngOnInit(): void { + this.subnets = Array(32).fill(1).map((x,i)=>i+1); this.initForm(); this.comm.on('server-edit').subscribe((data: Server) => { @@ -140,11 +145,14 @@ export class AddServerComponent implements OnInit { return false; } + iFace.nodes["subnet"] = iFace.nodes["address"].split("/")[1]; + iFace.nodes["address"] = iFace.nodes["address"].split("/")[0]; + iFace.nodes["peers"] = sPeers .map( x => x.nodes) .map( x => { x.server_id = -1; - x.address = x.allowed_ips; // Allowed_ips in server is the address of the peer (Seen from server perspective) + x.address = x.allowed_ips.split("/")[0]; // Allowed_ips in server is the address of the peer (Seen from server perspective) x.allowed_ips = null; // This should be retrieved from peer data config return x; }) diff --git a/wg_dashboard_frontend/src/app/page/dashboard/dashboard.module.ts b/wg_dashboard_frontend/src/app/page/dashboard/dashboard.module.ts index 7560191..2257217 100644 --- a/wg_dashboard_frontend/src/app/page/dashboard/dashboard.module.ts +++ b/wg_dashboard_frontend/src/app/page/dashboard/dashboard.module.ts @@ -18,6 +18,7 @@ import { MatTableModule } from '@angular/material/table'; import { PeerComponent } from './peer/peer.component'; import { QRCodeModule } from 'angularx-qrcode'; import {MatTooltipModule} from "@angular/material/tooltip"; +import {MatSelectModule} from "@angular/material/select"; @NgModule({ declarations: [ @@ -43,6 +44,7 @@ import {MatTooltipModule} from "@angular/material/tooltip"; FormsModule, QRCodeModule, MatTooltipModule, + MatSelectModule, ], }) diff --git a/wg_dashboard_frontend/src/app/page/dashboard/server/server.component.html b/wg_dashboard_frontend/src/app/page/dashboard/server/server.component.html index 01b933e..86c181c 100644 --- a/wg_dashboard_frontend/src/app/page/dashboard/server/server.component.html +++ b/wg_dashboard_frontend/src/app/page/dashboard/server/server.component.html @@ -83,7 +83,7 @@ - Endpoint: {{server.endpoint}}:{{server.listen_port}} - Address Space: {{server.address}} + Endpoint: {{server.endpoint}}:{{server.listen_port}} - Address: {{server.address}}/{{server.subnet}} diff --git a/wg_dashboard_frontend/src/app/validators/ip-address.validator.ts b/wg_dashboard_frontend/src/app/validators/ip-address.validator.ts index 00bd47c..b29c386 100644 --- a/wg_dashboard_frontend/src/app/validators/ip-address.validator.ts +++ b/wg_dashboard_frontend/src/app/validators/ip-address.validator.ts @@ -4,7 +4,7 @@ import * as IPCIDR from 'ip-cidr'; export class IPValidator { static isIPAddress(control: AbstractControl): ValidationErrors | null { - if (!control.value || !(new IPCIDR(control.value).isValid()) || !control.value.includes('/')) { + if (!control.value || !(new IPCIDR(control.value).isValid())) { return { validIP: true }; } return null;