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
|
use std::fs::{File, OpenOptions};
use tokio::sync::mpsc;
use rsdsl_ip_config::DsConfig;
use rsdsl_netlinklib::Connection;
use rsdsl_pppoe3::{Client, Error, Result};
use serde::{Deserialize, Serialize};
use sysinfo::{ProcessExt, Signal, System, SystemExt};
const INTERFACE: &str = "carrier0";
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
struct Config {
username: String,
password: String,
}
#[tokio::main]
async fn main() -> Result<()> {
let conn = Connection::new().await?;
println!("[info] wait for {}", INTERFACE);
conn.link_wait_up(INTERFACE.into()).await?;
println!("[info] startup");
let mut config_file = File::open("/data/pppoe.conf")?;
let config: Config = serde_json::from_reader(&mut config_file)?;
let mut ds_config: DsConfig = {
let mut ds_config_file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(rsdsl_ip_config::LOCATION_LAST)?;
serde_json::from_reader(&mut ds_config_file).unwrap_or_else(|_| {
println!("[info] no valid ds config to reuse");
DsConfig::default()
})
};
let mut ds_config_last = ds_config;
let (v4_tx, mut v4_rx) = mpsc::unbounded_channel();
let (v6_tx, mut v6_rx) = mpsc::unbounded_channel();
let client = Client::new(
INTERFACE.into(),
config.username,
config.password,
ds_config.v4.map(|v4| v4.addr),
ds_config
.v6
.map(|v6| (u128::from(v6.laddr) & u128::from(u64::MAX)) as u64),
)?;
let mut join_handle = tokio::spawn(client.run(v4_tx.clone(), v6_tx.clone()));
loop {
tokio::select! {
result = v4_rx.recv() => {
ds_config.v4 = result.ok_or(Error::V4ChannelClosed)?;
let mut ds_config_file = File::create(rsdsl_ip_config::LOCATION)?;
serde_json::to_writer_pretty(&mut ds_config_file, &ds_config)?;
if ds_config.v4.is_some() {
ds_config_last.v4 = ds_config.v4;
let mut ds_config_last_file = File::create(rsdsl_ip_config::LOCATION_LAST)?;
serde_json::to_writer_pretty(&mut ds_config_last_file, &ds_config_last)?;
}
inform();
if let Some(v4) = ds_config.v4 {
println!("[info] <> ipv4: addr={}, dns1={}, dns2={}", v4.addr, v4.dns1, v4.dns2);
} else {
println!("[info] <> ipv4: n/a");
}
}
result = v6_rx.recv() => {
ds_config.v6 = result.ok_or(Error::V6ChannelClosed)?;
let mut ds_config_file = File::create(rsdsl_ip_config::LOCATION)?;
serde_json::to_writer_pretty(&mut ds_config_file, &ds_config)?;
if ds_config.v6.is_some() {
ds_config_last.v6 = ds_config.v6;
let mut ds_config_last_file = File::create(rsdsl_ip_config::LOCATION_LAST)?;
serde_json::to_writer_pretty(&mut ds_config_last_file, &ds_config_last)?;
}
inform();
if let Some(v6) = ds_config.v6 {
println!("[info] <> ipv6: laddr={}, raddr={}", v6.laddr, v6.raddr);
} else {
println!("[info] <> ipv6: n/a");
}
}
result = &mut join_handle => {
result??;
println!("[info] <> exiting");
return Ok(());
}
}
}
}
/// Informs netlinkd of IPv4/IPv6 configuration changes.
fn inform() {
for netlinkd in System::new_all().processes_by_exact_name("rsdsl_netlinkd") {
netlinkd.kill_with(Signal::User1);
}
}
|