File Coverage

blib/lib/Net/Radius/Server/NS.pm
Criterion Covered Total %
statement 18 101 17.8
branch 0 38 0.0
condition 0 18 0.0
subroutine 6 9 66.6
pod n/a
total 24 166 14.4


line stmt bran cond sub pod time code
1             package Net::Radius::Server::NS;
2              
3 1     1   1242 use 5.008;
  1         4  
  1         48  
4 1     1   5 use strict;
  1         3  
  1         37  
5 1     1   6 use warnings;
  1         2  
  1         46  
6 1     1   1264 use Net::Radius::Packet;
  1         15045  
  1         68  
7 1     1   13 use base qw/Net::Server::MultiType Net::Radius::Server/;
  1         2  
  1         998  
8 1     1   72583 use Net::Radius::Server::Base qw/:all/;
  1         3  
  1         11  
9              
10             our $VERSION = do { sprintf "%0.3f", 1+(q$Revision: 89 $ =~ /\d+/g)[0]/1000 };
11              
12             # Verify that the required configuration keys are present. Initialize
13             # whatever we'll require for request processing, such as dictionaries,
14             # RADIUS setup file and 'secret' sources.
15             sub options
16             {
17 0     0     my $self = shift;
18 0           my $prop = $self->{server};
19 0           my $ref = shift;
20              
21 0           $self->SUPER::options($ref, @_);
22              
23 0           for ( qw(nrs_rule_script nrs_secret_script nrs_dictionary_script) )
24             {
25 0 0         $prop->{$_} = [] unless exists $prop->{$_};
26 0           $ref->{$_} = $prop->{$_};
27             }
28             }
29              
30             sub configure
31             {
32 0     0     my $self = shift; # A Net::Server-derived object
33 0           my $s = $self->{server};
34            
35 0           $self->SUPER::configure(@_);
36              
37             # We need to have a few keys defined before proceeding.
38 0 0 0       die __PACKAGE__, " definitions are missing\n"
      0        
39             unless (exists $s->{nrs_rule_script}
40             and exists $s->{nrs_secret_script}
41             and exists $s->{nrs_dictionary_script});
42              
43 0           for (qw/nrs_dictionary_script nrs_rule_script nrs_secret_script/)
44             {
45 0           die __PACKAGE__, ": Exactly one $_ must be specified\n"
46 0 0         if @{$s->{$_}} != 1;
47             }
48              
49 0           my ($d_method, $s_method, $rules);
50              
51 0           eval { $d_method = do ($s->{nrs_dictionary_script}->[0]) };
  0            
52 0 0         warn "Dictionary script ", $s->{nrs_dictionary_script}->[0],
53             " produced output: $@\n" if $@;
54 0 0 0       die "Dictionary script ", $s->{nrs_dictionary_script}->[0],
55             " must return a coderef (returned "
56             . ($d_method||'false/undef') . ")\n"
57             unless ref($d_method) eq 'CODE';
58              
59 0           eval { $s_method = do ($s->{nrs_secret_script}->[0]) };
  0            
60 0 0         warn "Secret script ", $s->{nrs_secret_script}->[0],
61             " produced output: $@\n" if $@;
62 0 0 0       die "Secret script ", $s->{nrs_secret_script}->[0],
63             " must return a coderef (returned "
64             . ($s_method||'false/undef') . ")\n"
65             unless ref($s_method) eq 'CODE';
66              
67 0           eval { $rules = do ($s->{nrs_rule_script}->[0]) };
  0            
68 0 0         warn "Rule script produced output: $@\n" if $@;
69 0 0 0       die "Rule script must return a listref (returned "
70             . ($rules||'false/undef') . ")\n"
71             unless ref($rules) eq 'ARRAY';
72              
73 0           $self->{_nrs} = {
74             secret => $s_method,
75             dict => $d_method,
76             rules => $rules,
77             };
78             }
79              
80             # Add the processing handler that is responsible for each packet
81             sub process_request
82             {
83 0     0     my $self = shift;
84 0           my $prop = $self->{server};
85 0           my $data = {
86             packet => $prop->{udp_data},
87             peer_addr => $prop->{peeraddr},
88             peer_host => $prop->{peerhost},
89             peer_port => $prop->{peerport},
90             port => $prop->{sockport},
91             sockaddr => $prop->{sockaddr},
92             server => $self,
93             };
94              
95 0 0         if (length($data->{packet}) < 18)
96             {
97 0           $self->log(2, "Packet too short - Ignoring");
98 0           return;
99             }
100              
101 0           $data->{secret} = $self->{_nrs}->{secret}->($data);
102 0           $data->{dict} = $self->{_nrs}->{dict}->($data);
103 0           $data->{response} = new Net::Radius::Packet $data->{dict};
104 0           $data->{request} = Net::Radius::Packet->new($data->{dict},
105             $data->{packet});
106              
107 0 0         if (not defined $data->{request})
108             {
109 0           $self->log(2, "Failed to decode RADIUS packet (garbage?)");
110 0           return;
111             }
112              
113 0           $self->log(2, "Received from " . ($data->{peer_addr} || '[no peer]')
114             . ' (' . $data->{request}->code . ' '
115 0           . join(', ', map { "$_ => " . $data->{request}->attr($_) }
116 0   0       grep { $_ !~ /(?i)password|-message/ }
117             $data->{request}->attributes)
118             . ') ');
119              
120 0           $self->log(4, "Request: " . $data->{request}->str_dump);
121              
122             # Verify that the authenticator in the packet matches the packet
123             # data. Discard the packet if this check fails
124              
125 0 0         if (grep { $data->{request}->code eq $_ }
  0            
126             qw/Accounting-Request
127             Disconnect-Request Disconnect-ACK Disconnect-NAK
128             CoA-Request CoA-ACK CoA-NAK/)
129             {
130 0 0         if (auth_acct_verify($data->{packet}, $data->{secret}))
131             {
132 0           $self->log(4, $data->{request}->code .
133             ' with good secret from ' .
134             $data->{peer_addr});
135             }
136             else
137             {
138             # Bad secret - Ignore request
139 0           $self->log(2, $data->{request}->code .
140             ' with bad secret from ' .
141             $data->{peer_addr});
142 0           return;
143             }
144             }
145              
146 0           my $res = undef;
147 0           for my $r (@{$self->{_nrs}->{rules}})
  0            
148             {
149 0           $res = $r->eval($data);
150 0 0         unless (defined $res)
151             {
152 0           $self->log(4, $r->description . ": Did not match");
153 0           next;
154             }
155              
156 0 0         if ($res & NRS_SET_DISCARD)
157             {
158 0           $self->log(2, $r->description . ": Requested discard");
159 0           return;
160             }
161              
162 0 0         if ($res & NRS_SET_SKIP)
163             {
164 0           $self->log(4, $r->description . ": Requested skip");
165 0           next;
166             }
167              
168 0 0         if ($res & NRS_SET_RESPOND)
169             {
170 0           $self->log(4, $r->description . ": Requested respond");
171 0           last;
172             }
173             }
174              
175 0 0         unless (defined $res)
176             {
177 0           $self->log(2, "Discard: No matching rule");
178 0           return;
179             }
180              
181 0 0         if ($res & NRS_SET_RESPOND)
182             {
183 0           $self->log(2, "Sent " . $data->{response}->code . ' '
184 0           . join(', ', map { "$_ => " . $data->{response}->attr($_) }
185 0           grep { $_ !~ /(?i)password|-message/ }
186             $data->{response}->attributes) . " to request from "
187             . ($data->{peer_addr} || '[no peer]')
188             . ' (' . $data->{request}->code . ' '
189 0           . join(', ', map { "$_ => " . $data->{request}->attr($_) }
190 0   0       grep { $_ !~ /(?i)password|-message/ }
191             $data->{request}->attributes)
192             . ') ');
193 0           $self->log(3, "Responding");
194 0           my $reply_packet = auth_resp($data->{response}->pack,
195             $data->{secret});
196 0           $self->{server}->{client}->send($reply_packet);
197 0           $self->log(4, "Response: " .
198             Net::Radius::Packet->new($data->{dict},
199             $reply_packet)->str_dump);
200             }
201             else
202             {
203 0           $self->log(2, "Ignoring request from " .
204             ($data->{peer_addr} || '[no peer]')
205             . ' (' . $data->{request}->code . ' '
206 0           . join(', ', map { "$_ => " . $data->{request}->attr($_) }
207 0   0       grep { $_ !~ /(?i)password|-message/ }
208             $data->{request}->attributes)
209             . ') ');
210             }
211             }
212              
213             42;
214              
215             __END__