use strict; use warnings; use Irssi; use IO::Socket; use Data::Dumper; no autovivification; use feature qw(fc); use vars qw($VERSION %IRSSI); $VERSION = "0.5"; %IRSSI = ( authors => 'vague', contact => 'vague!#irssi@freenode on irc', name => 'identd', description => 'Identd script for irssi', license => 'GPL2', url => 'https://vague.se', changed => "04 May 15:00:00 CEST 2023", ); my $handle = undef; my $connectrec; my $ident_server; my $started = 0; my $verbose = 0; sub VERBOSE { $verbose }; sub cmd_help { my ($args, $server, $witem) = @_; if($args =~ /^identd\b/i) { Irssi::print ( <new( Proto => 'tcp', LocalAddr => '0.0.0.0' , LocalPort => $port, Listen => SOMAXCONN, ReusePort => 1) or print "Can't bind to port $port, $@"; if(!$ident_server) { Irssi::print("Identd - couldn't start server, $@", MSGLEVEL_CLIENTERROR) if VERBOSE; $started = 0; return; } Irssi::print(sprintf("Identd - waiting for connections on %s:%s...", $ident_server->sockhost, $ident_server->sockport)) if VERBOSE; $handle = Irssi::input_add($ident_server->fileno, INPUT_READ, 'handle_connection', $ident_server); } sub handle_connection { return unless $started; my $sock = $_[0]->accept; my $iaddr = inet_aton($sock->peerhost); # or whatever address my $peer = gethostbyaddr($iaddr, AF_INET) // $sock->peerhost; Irssi::print(sprintf("Identd - handling connection from %s(%s)", $peer, $sock->peerhost)) if VERBOSE; my $strict = Irssi::settings_get_bool('identd_strict_conn'); Irssi::print(($peer =~ /(\w+)\.\w+$/i)[0]) if VERBOSE; if($strict && (!exists $connectrec->{($peer =~ /(\w+)\.\w+$/i)[0]} && !exists $connectrec->{$peer})) { Irssi::print("Identd - $peer not found in access list"); close $sock; return; } my $username; my $username_mode = fc(Irssi::settings_get_str('identd_resolve_mode')); my $wl = Irssi::settings_get_int('identd_length') // 10; if($username_mode eq '!random') { my @chars = ('a'..'z',0..9); for(1 .. $wl) { $username .= $chars[int(rand(@chars))]; } } elsif($username_mode eq '!username') { $username = substr +($ENV{USER} // 'unknown'), 0, $wl; } else { $username = substr $username_mode, 0, $wl; } $sock->autoflush(1); my $incoming = <$sock>; $incoming =~ s/\r\n//; $incoming =~ s/\s*//g; $incoming .= ":USERID:UNIX:" . $username . "\n"; print $sock $incoming; close $sock; chomp $incoming; Irssi::print("Identd - responded to $peer with '$incoming'") if VERBOSE; } sub sig_server_connecting { my ($server,$ip) = @_; Irssi::print("Identd - server connecting: " . $server->{address}) if VERBOSE; $connectrec->{$server->{tag}} = $ip; $connectrec->{$server->{address}} = $ip; start_ident_server unless $started++; } sub sig_event_connected { my ($server) = @_; Irssi::print("Identd - server done connecting: " . $server->{address}) if VERBOSE; print Dumper($connectrec) if VERBOSE; # print Dumper($server) if VERBOSE; delete $connectrec->{$server->{address}}; delete $connectrec->{$server->{tag}}; if(!keys %$connectrec) { Irssi::print("Identd - shutting down...") if VERBOSE; Irssi::input_remove($handle) if $handle; $ident_server->close if $ident_server; $started = 0; } } sub sig_setup_changed { $verbose = Irssi::settings_get_bool('identd_verbose'); } Irssi::settings_add_str('identd', 'identd_resolve_mode', '!username'); Irssi::settings_add_int('identd', 'identd_port', 8113); Irssi::settings_add_int('identd', 'identd_length', 10); Irssi::settings_add_bool('identd', 'identd_verbose', 0); Irssi::settings_add_bool('identd', 'identd_strict_conn', 0); Irssi::command_bind_first('help', 'cmd_help'); Irssi::signal_add_first('server looking', 'sig_server_connecting'); Irssi::signal_add_last('event connected', 'sig_event_connected'); Irssi::signal_add_last('server connect failed', 'sig_event_connected'); Irssi::signal_add('setup changed', 'sig_setup_changed'); sig_setup_changed();