connect: oper can dial a configured server link on demand
This commit is contained in:
parent
eb7f9f25c4
commit
9e5f71f961
4 changed files with 60 additions and 8 deletions
|
|
@ -34,6 +34,7 @@ pub fn commands() -> Vec<Box<dyn Command>> {
|
||||||
Box::new(Eline),
|
Box::new(Eline),
|
||||||
Box::new(Shun),
|
Box::new(Shun),
|
||||||
Box::new(Qline),
|
Box::new(Qline),
|
||||||
|
Box::new(Connect),
|
||||||
Box::new(ChgHost),
|
Box::new(ChgHost),
|
||||||
Box::new(ChgIdent),
|
Box::new(ChgIdent),
|
||||||
Box::new(SetHost),
|
Box::new(SetHost),
|
||||||
|
|
@ -671,6 +672,48 @@ impl Command for Qline {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// CONNECT — dial a configured server link on demand. `CONNECT <servername>`.
|
||||||
|
struct Connect;
|
||||||
|
impl Command for Connect {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"CONNECT"
|
||||||
|
}
|
||||||
|
fn min_params(&self) -> usize {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
|
||||||
|
if !require_oper(s, uid) {
|
||||||
|
return CmdResult::Fail;
|
||||||
|
}
|
||||||
|
let name = ¶ms[0];
|
||||||
|
let Some(b) = s
|
||||||
|
.link_blocks
|
||||||
|
.iter()
|
||||||
|
.find(|b| b.name.eq_ignore_ascii_case(name))
|
||||||
|
.cloned()
|
||||||
|
else {
|
||||||
|
onotice(s, uid, &format!("CONNECT: no link block named {name}"));
|
||||||
|
return CmdResult::Fail;
|
||||||
|
};
|
||||||
|
if s.servers
|
||||||
|
.values()
|
||||||
|
.any(|sv| sv.name.eq_ignore_ascii_case(&b.name))
|
||||||
|
{
|
||||||
|
onotice(s, uid, &format!("CONNECT: {} is already linked", b.name));
|
||||||
|
return CmdResult::Fail;
|
||||||
|
}
|
||||||
|
let addr = format!("{}:{}", b.ip, b.port);
|
||||||
|
let (tx, counter) = (s.event_tx.clone(), s.conn_counter.clone());
|
||||||
|
std::thread::spawn(move || crate::socketengine::connect_link(&addr, tx, counter));
|
||||||
|
let by = oper_nick(s, uid);
|
||||||
|
s.snotice(&format!(
|
||||||
|
"{by} used CONNECT to {} ({}:{})",
|
||||||
|
b.name, b.ip, b.port
|
||||||
|
));
|
||||||
|
CmdResult::Ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve a nick to a uid, sending ERR_NOSUCHNICK if it's unknown.
|
/// Resolve a nick to a uid, sending ERR_NOSUCHNICK if it's unknown.
|
||||||
fn oper_target(s: &mut Server, uid: Uid, nick: &str) -> Option<Uid> {
|
fn oper_target(s: &mut Server, uid: Uid, nick: &str) -> Option<Uid> {
|
||||||
match s.find_nick(nick) {
|
match s.find_nick(nick) {
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,13 @@ pub struct Ircd {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ircd {
|
impl Ircd {
|
||||||
pub fn new(cfg: Config, event_tx: Sender<Event>) -> Ircd {
|
pub fn new(
|
||||||
|
cfg: Config,
|
||||||
|
event_tx: Sender<Event>,
|
||||||
|
conn_counter: std::sync::Arc<std::sync::atomic::AtomicU64>,
|
||||||
|
) -> Ircd {
|
||||||
Ircd {
|
Ircd {
|
||||||
server: Server::new(cfg, event_tx),
|
server: Server::new(cfg, event_tx, conn_counter),
|
||||||
commands: command_table(),
|
commands: command_table(),
|
||||||
modules: crate::modules::default_modules(),
|
modules: crate::modules::default_modules(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,14 @@ fn main() {
|
||||||
cfg.servername
|
cfg.servername
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// one uid counter shared by every listener (and by CONNECT) so ids stay unique
|
||||||
|
let counter = Arc::new(AtomicU64::new(1));
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
let (tx, rx) = mpsc::channel();
|
||||||
let core_cfg = cfg.clone();
|
let core_cfg = cfg.clone();
|
||||||
let core_tx = tx.clone(); // the core self-injects events (DNS results)
|
let core_tx = tx.clone(); // the core self-injects events (DNS results)
|
||||||
let core = thread::spawn(move || Ircd::new(core_cfg, core_tx).run(rx));
|
let core_counter = counter.clone();
|
||||||
|
let core = thread::spawn(move || Ircd::new(core_cfg, core_tx, core_counter).run(rx));
|
||||||
|
|
||||||
// background timer: drives ping/idle timeouts
|
// background timer: drives ping/idle timeouts
|
||||||
let tick_tx = tx.clone();
|
let tick_tx = tx.clone();
|
||||||
|
|
@ -58,9 +62,6 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// one uid counter shared by every listener so ids stay unique
|
|
||||||
let counter = Arc::new(AtomicU64::new(1));
|
|
||||||
|
|
||||||
// optional TLS listener (bind_tls + tls_cert + tls_key). A cert/bind problem
|
// optional TLS listener (bind_tls + tls_cert + tls_key). A cert/bind problem
|
||||||
// disables TLS but never takes the plaintext listener down.
|
// disables TLS but never takes the plaintext listener down.
|
||||||
if let (Some(bind_tls), Some(cert), Some(key)) = (&cfg.bind_tls, &cfg.tls_cert, &cfg.tls_key) {
|
if let (Some(bind_tls), Some(cert), Some(key)) = (&cfg.bind_tls, &cfg.tls_cert, &cfg.tls_key) {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
use std::net::{SocketAddr, TcpStream};
|
use std::net::{SocketAddr, TcpStream};
|
||||||
|
use std::sync::atomic::AtomicU64;
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
|
@ -148,10 +150,11 @@ pub struct Server {
|
||||||
pub label_capture: RefCell<Option<(Uid, Vec<String>)>>,
|
pub label_capture: RefCell<Option<(Uid, Vec<String>)>>,
|
||||||
pub history: HashMap<String, VecDeque<HistMsg>>, // channel key -> recent messages (CHATHISTORY)
|
pub history: HashMap<String, VecDeque<HistMsg>>, // channel key -> recent messages (CHATHISTORY)
|
||||||
pub event_tx: Sender<Event>, // self-inject events (DNS results)
|
pub event_tx: Sender<Event>, // self-inject events (DNS results)
|
||||||
|
pub conn_counter: Arc<AtomicU64>, // mints connection uids (for CONNECT dials)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn new(cfg: Config, event_tx: Sender<Event>) -> Server {
|
pub fn new(cfg: Config, event_tx: Sender<Event>, conn_counter: Arc<AtomicU64>) -> Server {
|
||||||
Server {
|
Server {
|
||||||
name: cfg.servername,
|
name: cfg.servername,
|
||||||
network: cfg.network,
|
network: cfg.network,
|
||||||
|
|
@ -191,6 +194,7 @@ impl Server {
|
||||||
label_capture: RefCell::new(None),
|
label_capture: RefCell::new(None),
|
||||||
history: HashMap::new(),
|
history: HashMap::new(),
|
||||||
event_tx,
|
event_tx,
|
||||||
|
conn_counter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -783,7 +787,7 @@ mod tests {
|
||||||
|
|
||||||
fn srv() -> Server {
|
fn srv() -> Server {
|
||||||
let (tx, _rx) = mpsc::channel();
|
let (tx, _rx) = mpsc::channel();
|
||||||
Server::new(Config::default(), tx)
|
Server::new(Config::default(), tx, Arc::new(AtomicU64::new(1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue