aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 9b9c9cfb3aa296d6f2f52bca6fac55590447b144 (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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use rsdsl_pppoe::client::Client;
use rsdsl_pppoe::config::Config;
use rsdsl_pppoe::error::{Error, Result};

use std::fs::File;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

use byteorder::{ByteOrder, NetworkEndian as NE};
use pppoe::packet::IPV4;
use rsdsl_ip_config::IpConfig;
use rsdsl_netlinkd::link;
use tun_tap::{Iface, Mode};

fn prepend<T>(v: Vec<T>, s: &[T]) -> Vec<T>
where
    T: Clone,
{
    let mut tmp = s.to_owned();
    tmp.extend(v);
    tmp
}

fn tun2ppp(tx: mpsc::Sender<Option<Vec<u8>>>, tun: Arc<Iface>) -> Result<()> {
    loop {
        let mut buf = [0; 4 + 1492];
        let n = tun.recv(&mut buf)?;
        let buf = &buf[..n];

        let ether_type = NE::read_u16(&buf[2..4]);
        if ether_type != IPV4 {
            println!(
                "dropping outbound non-IPv4 packet, EtherType: 0x{:04x}",
                ether_type
            );
            continue;
        }

        tx.send(Some(buf[4..].to_vec()))?;
    }
}

fn ppp2tun(rx: Arc<Mutex<mpsc::Receiver<Vec<u8>>>>, tun: Arc<Iface>) -> Result<()> {
    let rx = rx.lock().unwrap();

    let mut packet_info = [0; 4];
    NE::write_u16(&mut packet_info[2..4], IPV4);

    while let Ok(mut buf) = rx.recv() {
        buf = prepend(buf, &packet_info);

        let n = tun.send(&buf)?;
        if n != buf.len() {
            return Err(Error::PartialTransmission);
        }
    }

    Ok(())
}

fn write_config(rx: mpsc::Receiver<IpConfig>) -> Result<()> {
    while let Ok(ip_config) = rx.recv() {
        let mut file = File::create(rsdsl_ip_config::LOCATION)?;
        serde_json::to_writer_pretty(&mut file, &ip_config)?;
    }

    Ok(())
}

fn main() -> Result<()> {
    let mut file = File::open("/data/pppoe.conf")?;
    let config: Config = serde_json::from_reader(&mut file)?;

    println!("read config, launching on interface {}", config.link);

    while !link::is_up(config.link.clone())? {
        println!("waiting for {} to come up", config.link);
        thread::sleep(Duration::from_secs(8));
    }

    let tun = Arc::new(Iface::new("rsppp0", Mode::Tun)?);

    let (recv_tx, recv_rx) = mpsc::channel();
    let recv_rx = Arc::new(Mutex::new(recv_rx));

    let (send_tx, send_rx) = mpsc::channel();
    let send_rx = Arc::new(Mutex::new(send_rx));

    loop {
        println!("connecting...");

        let clt = Client::new(config.clone())?;

        let recv_rx2 = recv_rx.clone();
        let send_tx2 = send_tx.clone();
        let tun2 = tun.clone();
        let tun3 = tun.clone();

        thread::spawn(move || match tun2ppp(send_tx2, tun2) {
            Ok(_) => {}
            Err(e) => panic!("tun2ppp error: {}", e),
        });

        thread::spawn(move || match ppp2tun(recv_rx2, tun3) {
            Ok(_) => {}
            Err(e) => panic!("ppp2tun error: {}", e),
        });

        let (ipchange_tx, ipchange_rx) = mpsc::channel();
        thread::spawn(move || match write_config(ipchange_rx) {
            Ok(_) => {}
            Err(e) => panic!("write_config error: {}", e),
        });

        clt.run(recv_tx.clone(), send_rx.clone(), ipchange_tx)?;

        send_tx.send(None)?;
        println!("connection lost");
    }
}