File Coverage

blib/lib/POE/Component/Server/IRC/Plugin/Auth.pm
Criterion Covered Total %
statement 70 134 52.2
branch 7 38 18.4
condition 2 4 50.0
subroutine 16 22 72.7
pod 0 10 0.0
total 95 208 45.6


line stmt bran cond sub pod time code
1             package POE::Component::Server::IRC::Plugin::Auth;
2             our $AUTHORITY = 'cpan:BINGOS';
3             $POE::Component::Server::IRC::Plugin::Auth::VERSION = '1.62';
4 2     2   1200 use strict;
  2         28  
  2         67  
5 2     2   12 use warnings;
  2         5  
  2         82  
6 2     2   11 use Carp 'croak';
  2         4  
  2         111  
7 2     2   13 use POE;
  2         5  
  2         13  
8 2     2   2058 use POE::Component::Client::Ident::Agent;
  2         10862  
  2         67  
9 2     2   1148 use POE::Component::Client::DNS;
  2         145738  
  2         330  
10 2     2   53 use POE::Component::Server::IRC::Plugin 'PCSI_EAT_NONE';
  2         16  
  2         281  
11 2     2   31 use Net::IP::Minimal qw[ip_is_ipv6];
  2         15  
  2         5393  
12              
13             sub new {
14 1     1 0 66 my ($package, %args) = @_;
15 1         60 return bless \%args, $package;
16             }
17              
18             sub PCSI_register {
19 1     1 0 288 my ($self, $ircd) = splice @_, 0, 2;
20              
21 1         11 $self->{ircd} = $ircd;
22              
23 1         40 POE::Session->create(
24             object_states => [
25             $self => [qw(
26             _start
27             resolve_hostname
28             resolve_ident
29             got_hostname
30             got_ip
31             )],
32             $self => {
33             ident_agent_reply => 'got_ident',
34             ident_agent_error => 'got_ident_error',
35             }
36             ],
37             );
38              
39 1         172 $ircd->plugin_register($self, 'SERVER', qw(connection));
40 1         82 return 1;
41             }
42              
43             sub PCSI_unregister {
44 1     1 0 382 my ($self, $ircd) = splice @_, 0, 2;
45 1 50       9 $self->{resolver}->shutdown() if $self->{resolver};
46 1         248 return 1;
47             }
48              
49             sub _start {
50 1     1   860 my ($self, $session) = @_[OBJECT, SESSION];
51 1         5 $self->{session_id} = $session->ID;
52              
53 1         12 $self->{resolver} = POE::Component::Client::DNS->spawn(
54             Timeout => 10,
55             );
56 1         1923 return;
57             }
58              
59             sub IRCD_connection {
60 1     1 0 67 my ($self, $ircd) = splice @_, 0, 2;
61 1         5 my $server = $ircd->server_name();
62 1         2 pop @_;
63             my ($conn_id, $peeraddr, $peerport, $sockaddr, $sockport, $needs_auth)
64 1         3 = map { $$_ } @_;
  8         27  
65              
66 1 50       5 return PCSI_EAT_NONE if !$needs_auth;
67 1 50       25 return PCSI_EAT_NONE if !$ircd->connection_exists($conn_id);
68              
69 1         5 $self->{conns}{$conn_id} = {
70             hostname => '',
71             ident => '',
72             done => 0,
73             };
74              
75 1         26 $ircd->send_output(
76             {
77             prefix => $server,
78             command => 'NOTICE',
79             params => ['*', '*** Checking Ident'],
80             },
81             $conn_id,
82             );
83              
84 1         8 $ircd->send_output(
85             {
86             prefix => $server,
87             command => 'NOTICE',
88             params => ['*', '*** Checking Hostname'],
89             },
90             $conn_id,
91             );
92              
93 1 50       7 if ($peeraddr =~ /^127\./) {
94 1         6 $ircd->send_output(
95             {
96             prefix => $server,
97             command => 'NOTICE',
98             params => ['*', '*** Found your hostname']
99             },
100             $conn_id,
101             );
102 1         3 $self->{conns}{$conn_id}{hostname} = 'localhost';
103 1         4 $self->_auth_done($conn_id);
104             }
105             else {
106             $poe_kernel->call(
107 0         0 $self->{session_id}, 'resolve_hostname',
108             $conn_id, $peeraddr,
109             );
110             }
111              
112             $poe_kernel->call(
113 1         7 $self->{session_id}, 'resolve_ident',
114             $conn_id, $peeraddr, $peerport, $sockaddr, $sockport,
115             );
116              
117 1         20 return PCSI_EAT_NONE;
118             }
119              
120             sub resolve_hostname {
121 0     0 0 0 my ($self, $conn_id, $peeraddr) = @_[OBJECT, ARG0, ARG1];
122              
123             my $response = $self->{resolver}->resolve(
124 0         0 event => 'got_hostname',
125             host => $peeraddr,
126             type => 'PTR',
127             context => {
128             conn_id => $conn_id,
129             peeraddr => $peeraddr,
130             },
131             );
132              
133 0 0       0 $poe_kernel->call('got_hostname', $response) if $response;
134 0         0 return;
135             }
136              
137             sub resolve_ident {
138 1     1 0 79 my ($kernel, $self, $conn_id, $peeraddr, $peerport, $sockaddr, $sockport)
139             = @_[KERNEL, OBJECT, ARG0..$#_];
140              
141             POE::Component::Client::Ident::Agent->spawn(
142             PeerAddr => $peeraddr,
143             PeerPort => $peerport,
144             SockAddr => $sockaddr,
145             SockPort => $sockport,
146             BuggyIdentd => 1,
147             TimeOut => ( $self->{ircd}{config}{ident_timeout} || 10 ),
148             Reference => $conn_id,
149 1   50     41 IdentPort => ( $self->{identport} || '' ),
      50        
150             );
151 1         1403 return;
152             }
153              
154             sub got_hostname {
155 0     0 0 0 my ($kernel, $self, $response) = @_[KERNEL, OBJECT, ARG0];
156 0         0 my $conn_id = $response->{context}{conn_id};
157 0         0 my $peer_ip = $response->{context}{peeraddr};
158 0         0 my $ircd = $self->{ircd};
159              
160 0 0       0 if (!$ircd->connection_exists($conn_id)) {
161 0         0 delete $self->{conns}{$conn_id};
162 0         0 return;
163             }
164              
165             my $fail = sub {
166             $ircd->send_output(
167             {
168 0     0   0 prefix => $self->{ircd}->server_name(),
169             command => 'NOTICE',
170             params => [
171             '*',
172             "*** Couldn\'t look up your hostname",
173             ],
174             },
175             $conn_id,
176             );
177              
178 0         0 $self->_auth_done($conn_id);
179 0         0 };
180              
181 0 0       0 return $fail->() if !defined $response->{response};
182 0         0 my @answers = $response->{response}->answer();
183 0 0       0 return $fail->() if !@answers;
184              
185 0         0 for my $answer (@answers) {
186 0         0 my $context = $response->{context};
187 0         0 $context->{hostname} = $answer->rdatastr();
188              
189 0 0       0 chop $context->{hostname} if $context->{hostname} =~ /\.$/;
190             my $query = $self->{resolver}->resolve(
191 0 0       0 event => 'got_ip',
192             host => $answer->rdatastr(),
193             context => $context,
194             type => ( ip_is_ipv6( $peer_ip ) ? 'AAAA' : 'A' ),
195             );
196 0 0       0 if (defined $query) {
197 0         0 $kernel->call($self->{session_id}, 'got_ip', $query);
198             }
199             }
200              
201 0         0 return;
202             }
203              
204             sub got_ip {
205 0     0 0 0 my ($kernel, $self, $response) = @_[KERNEL, OBJECT, ARG0];
206 0         0 my $conn_id = $response->{context}{conn_id};
207 0         0 my $ircd = $self->{ircd};
208 0         0 my $server = $ircd->server_name();
209              
210 0 0       0 if (!$ircd->connection_exists($conn_id)) {
211 0         0 delete $self->{conns}{$conn_id};
212 0         0 return;
213             }
214              
215             my $fail = sub {
216 0     0   0 $ircd->send_output(
217             {
218             prefix => $server,
219             command => 'NOTICE',
220             params => [
221             '*',
222             "*** Couldn't look up your hostname",
223             ],
224             },
225             $conn_id,
226             );
227 0         0 $self->_auth_done($conn_id);
228 0         0 };
229              
230 0 0       0 return $fail->() if !defined $response->{response};
231 0         0 my @answers = $response->{response}->answer();
232 0 0       0 return $fail->() if !@answers;
233              
234 0         0 my $peeraddr = $response->{context}{peeraddr};
235 0         0 my $hostname = $response->{context}{hostname};
236 0         0 for my $answer (@answers) {
237 0 0       0 if ($answer->rdatastr() eq $peeraddr) {
238 0         0 $ircd->send_output(
239             {
240             prefix => $server,
241             command => 'NOTICE',
242             params => ['*', '*** Found your hostname'],
243             },
244             $conn_id,
245             );
246 0         0 $self->{conns}{$conn_id}{hostname} = $hostname;
247 0         0 $self->_auth_done($conn_id);
248 0         0 return;
249             }
250             }
251              
252             $ircd->send_output(
253             {
254 0         0 prefix => $server,
255             command => 'NOTICE',
256             params => [
257             '*',
258             '*** Your forward and reverse DNS do not match',
259             ],
260             },
261             $conn_id,
262             );
263 0         0 $self->_auth_done($conn_id);
264 0         0 return;
265             }
266              
267             sub _auth_done {
268 2     2   12 my ($self, $conn_id) = @_;
269              
270 2         91 $self->{conns}{$conn_id}{done}++;
271 2 100       11 return if $self->{conns}{$conn_id}{done} != 2;
272              
273 1         2 my $auth = delete $self->{conns}{$conn_id};
274             $self->{ircd}->send_event(
275             'auth_done',
276             $conn_id,
277             {
278             ident => $auth->{ident},
279             hostname => $auth->{hostname},
280             },
281 1         6 );
282 1         115 return;
283             }
284              
285             sub got_ident_error {
286 1     1 0 588 my ($kernel, $self, $ref, $error) = @_[KERNEL, OBJECT, ARG0, ARG1];
287 1         3 my $conn_id = $ref->{Reference};
288 1         2 my $ircd = $self->{ircd};
289              
290 1 50       5 if (!$ircd->connection_exists($conn_id)) {
291 0         0 delete $self->{conns}{$conn_id};
292 0         0 return;
293             }
294              
295             $ircd->send_output(
296             {
297 1         7 prefix => $ircd->server_name(),
298             command => 'NOTICE',
299             params => ['*', "*** No Ident response"],
300             },
301             $conn_id,
302             );
303 1         5 $self->_auth_done($conn_id);
304 1         3 return;
305             }
306              
307             sub got_ident {
308 0     0 0   my ($kernel, $self, $ref, $opsys, $other)
309             = @_[KERNEL, OBJECT, ARG0, ARG1, ARG2];
310 0           my $conn_id = $ref->{Reference};
311 0           my $ircd = $self->{ircd};
312              
313 0 0         if (!$ircd->connection_exists($conn_id)) {
314 0           delete $self->{conns}{$conn_id};
315 0           return;
316             }
317              
318 0           my $ident = '';
319 0 0         $ident = $other if uc $opsys ne 'OTHER';
320 0           $ircd->send_output(
321             {
322             prefix => $ircd->server_name(),
323             command => 'NOTICE',
324             params => ['*', "*** Got Ident response"],
325             },
326             $conn_id,
327             );
328 0           $self->{conns}{$conn_id}{ident} = $ident;
329 0           $self->_auth_done($conn_id);
330 0           return;
331             }
332              
333             1;
334              
335             =encoding utf8
336              
337             =head1 NAME
338              
339             POE::Component::Server::IRC::Plugin::Auth - Authentication subsystem of POE::Component::Server::IRC::Backend
340              
341             =head1 DESCRIPTION
342              
343             This module is used internally by
344             L.
345             No need for you to use it.
346              
347             =head1 AUTHOR
348              
349             Hinrik Ern SigurEsson
350              
351             Chris 'BinGOs' Williams
352              
353             =cut