-
Notifications
You must be signed in to change notification settings - Fork 234
/
identd.pl
161 lines (136 loc) · 5.24 KB
/
identd.pl
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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 ( <<SCRIPTHELP_EOF
%_Description:%_
Handles identd responses during server connections.
Port 113 from the outside has to be portforwarded to identd_port for
the script to work. The port has to be above 1024 or irssi will complain.
Another option is to run irssi as root but that is strongly discouraged.
%_Available settings:%_
identd_port - the port the identd server is listening on
identd_length - maximum length of the username to return
identd_resolve_mode - the available modes to use are:
* !random - username is a identd_length
long random string consisting of 0-9a-z
* !username - use the logged in user's name
* it's up to you, identd_length characters are
used
identd_verbose - print status messages when identd is listening
to connections
identd_strict_conn - verify an incoming connection is from a server we are
connecting to
SCRIPTHELP_EOF
,MSGLEVEL_CLIENTCRAP);
Irssi::signal_stop;
}
}
sub start_ident_server {
my $port = Irssi::settings_get_int('identd_port') // 8113;
Irssi::print("Identd - starting...") if VERBOSE;
$ident_server = IO::Socket::INET->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();