summaryrefslogtreecommitdiff
path: root/src/daemon_dbus.rs
blob: 7065eec2d66491d50d8950da1df301b5f6bb4e10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use base64::prelude::*;
use dbus::{channel::MatchingReceiver, message::MatchRule};
use dbus_crossroads::{Context, Crossroads, MethodErr};
use defguard_wireguard_rs::{
    host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WGApi, WireguardInterfaceApi,
};
use log::{debug, error, info, warn};
use rand::Rng;
use std::{
    collections::{BTreeSet, HashMap},
    marker::PhantomData,
    ops::DerefMut,
    str::FromStr,
    sync::Arc,
};
use tokio::{
    net::TcpListener,
    sync::{broadcast, RwLock},
    task,
};

use crate::{daemon::*, daemon_network::*};

// TODO also take peers
pub async fn handle_add_network(
    mut ctx: Context,
    state: Arc<RwLock<State>>,
    (name, may_key, may_ip, may_lp, may_mp): (String, String, String, u16, u16),
) -> PhantomData<(bool,)> {
    // NOTE: this is kinda stupid: we convert to a string later anyways, as thats what
    // defguard_wg takes...
    let key = Key::new(match may_key.as_str() {
        "" => rand::thread_rng().gen(),
        _ => match BASE64_STANDARD.decode(may_key) {
            Ok(v) if v.len() == 32 => v.try_into().unwrap(),
            _ => {
                warn!("AddNetwork with bad key");
                return ctx.reply(Err(MethodErr::invalid_arg("bad key")));
            }
        },
    });

    // we store the ip as the original string, but should validate it regardless
    let (ip, ip_string) = match may_ip.as_str() {
        "" => todo!(),
        _ => match IpAddrMask::from_str(&may_ip) {
            Ok(ip_mask) => (ip_mask.ip, may_ip),
            Err(_) => {
                warn!("AddNetwork with bad ip");
                return ctx.reply(Err(MethodErr::invalid_arg("invalid ip")));
            }
        },
    };

    let lp = if may_lp == 0 { 25565 } else { may_lp };
    let mp = if may_mp == 0 { 51820 } else { may_mp };

    let mut state_rw_guard = state.write().await;
    let state_rw = state_rw_guard.deref_mut();

    let wg_api = match add_network(
        &mut state_rw.hostfile,
        name.clone(),
        key.to_string(),
        ip_string,
        lp,
        &HashMap::new(),
    )
    .await
    {
        Ok(wg_api) => wg_api,
        Err(e) => {
            warn!("AddNetwork couldn't add network: {e}");
            return ctx.reply(Err(MethodErr::failed(&e)));
        }
    };

    // TODO ins wg_api
    let listener = match TcpListener::bind((ip, mp)).await {
        Ok(l) => l,
        Err(e) => {
            let _ = wg_api.remove_interface();
            warn!("AddNetwork couldn't start listener: {e}");
            return ctx.reply(Err(MethodErr::failed(&e)));
        }
    };
    let h = task::spawn(print_error(run_network(
        state.clone(),
        listener,
        name.clone(),
    )));

    state_rw.nw_handles.insert(name.clone(), (wg_api, h));

    // TODO save new config

    ctx.reply(Ok((true,)))
}