connect: oper can dial a configured server link on demand
This commit is contained in:
parent
cc3240c04f
commit
f5cc12e809
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(Shun),
|
||||
Box::new(Qline),
|
||||
Box::new(Connect),
|
||||
Box::new(ChgHost),
|
||||
Box::new(ChgIdent),
|
||||
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.
|
||||
fn oper_target(s: &mut Server, uid: Uid, nick: &str) -> Option<Uid> {
|
||||
match s.find_nick(nick) {
|
||||
|
|
|
|||
|
|
@ -66,9 +66,13 @@ pub struct 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 {
|
||||
server: Server::new(cfg, event_tx),
|
||||
server: Server::new(cfg, event_tx, conn_counter),
|
||||
commands: command_table(),
|
||||
modules: crate::modules::default_modules(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,10 +44,14 @@ fn main() {
|
|||
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 core_cfg = cfg.clone();
|
||||
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
|
||||
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
|
||||
// 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) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::net::{SocketAddr, TcpStream};
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
|
|
@ -148,10 +150,11 @@ pub struct Server {
|
|||
pub label_capture: RefCell<Option<(Uid, Vec<String>)>>,
|
||||
pub history: HashMap<String, VecDeque<HistMsg>>, // channel key -> recent messages (CHATHISTORY)
|
||||
pub event_tx: Sender<Event>, // self-inject events (DNS results)
|
||||
pub conn_counter: Arc<AtomicU64>, // mints connection uids (for CONNECT dials)
|
||||
}
|
||||
|
||||
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 {
|
||||
name: cfg.servername,
|
||||
network: cfg.network,
|
||||
|
|
@ -191,6 +194,7 @@ impl Server {
|
|||
label_capture: RefCell::new(None),
|
||||
history: HashMap::new(),
|
||||
event_tx,
|
||||
conn_counter,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -783,7 +787,7 @@ mod tests {
|
|||
|
||||
fn srv() -> Server {
|
||||
let (tx, _rx) = mpsc::channel();
|
||||
Server::new(Config::default(), tx)
|
||||
Server::new(Config::default(), tx, Arc::new(AtomicU64::new(1)))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue