aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
blob: 79fecf8e7066b00f48749a3e25be115ce5a6750c (plain) (blame)
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
#![feature(test)]

#[macro_use] extern crate failure;
#[macro_use] extern crate structopt_derive;
#[macro_use] extern crate log;

extern crate chrono;
extern crate colored;
extern crate daemonize;
extern crate fern;
extern crate nix;
extern crate structopt;
extern crate wireguard;

use daemonize::Daemonize;
use failure::Error;
use fern::colors::{Color, ColoredLevelConfig};
use wireguard::interface::Interface;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "wgrs", about = "WireGuard - a network tunnel")]
struct Opt {
    /// A flag, true if used in the command line.
    #[structopt(short = "d", long = "debug", help = "Activate debug mode")]
    debug: bool,

    /// An argument of type float, with a default value.
    #[structopt(short = "f", long = "foreground", help = "Run in the foreground")]
    foreground: bool,

    /// Needed parameter, the first on the command line.
    #[structopt(help = "WireGuard interface name", default_value = "utun4")]
    interface: String,

    /// An optional parameter, will be `None` if not present on the
    /// command line.
    #[structopt(help = "Output file, stdout if not present")]
    output: Option<String>,
}

fn main() {
    let opt = Opt::from_args();

    let interface = opt.interface.clone();
    let colors = ColoredLevelConfig::new()
        .debug(Color::Magenta)
        .info(Color::BrightBlue)
        .warn(Color::BrightYellow)
        .error(Color::BrightRed);
    fern::Dispatch::new()
        .format(move |out, message, record| {
            let pad = record.level() == log::Level::Warn || record.level() == log::Level::Info;
            out.finish(format_args!(
                "{} {}  {}{}  {}",
                chrono::Local::now().format("%H:%M:%S%.3f"),
                interface,
                colors.color(record.level()),
                if pad { " " } else { "" },
                message,
            ))
        })
        .level(log::LevelFilter::Warn)
        // .level_for("wireguard", log::LevelFilter::Debug)
        .chain(std::io::stdout())
        .apply().unwrap();

    if !opt.foreground {
        daemonize().expect("failed to daemonize");
    }

    if let Err(e) = Interface::new(&opt.interface).start() {
        error!("failed to start interface: {}", e);
    }
}

fn daemonize() -> Result<(), Error> {
    if !nix::unistd::getuid().is_root() {
        bail!("You are not the root user which can spawn the daemon.");
    }

    debug!("Starting daemon.");
    let daemonize = Daemonize::new()
        .stream_redirect("/var/log/wireguard.log");

    daemonize.start()?;
    Ok(())
}