File Coverage

blib/lib/Net/Radius/Dictionary.pm
Criterion Covered Total %
statement 92 107 85.9
branch 50 58 86.2
condition 6 10 60.0
subroutine 26 31 83.8
pod 11 28 39.2
total 185 234 79.0


line stmt bran cond sub pod time code
1             package Net::Radius::Dictionary;
2              
3 13     13   570231 use strict;
  13         27  
  13         470  
4 13     13   71 use warnings;
  13         23  
  13         405  
5 13     13   71 use vars qw($VERSION);
  13         24  
  13         47312  
6              
7             # $Id: Dictionary.pm 80 2007-04-26 20:20:02Z lem $
8              
9             $VERSION = '1.55';
10              
11             sub new {
12 91     91 1 156145 my $class = shift;
13 91         1135 my $self = {
14             rvsattr => {},
15             vsattr => {},
16             vsaval => {},
17             rvsaval => {},
18             attr => {},
19             rattr => {},
20             val => {},
21             rval => {},
22             vendors => {},
23             packet => undef, # Fall back to default
24             rpacket => undef, # Fall back to default
25             };
26 91         260 bless $self, $class;
27 91         350 $self->readfile($_) for @_; # Read all given dictionaries
28 91         316 return $self;
29             }
30              
31             sub readfile {
32 93     93 1 63242 my ($self, $filename) = @_;
33              
34 93         4234 open DICT, "<$filename";
35              
36 93         1335899 while (defined(my $l = )) {
37 15538 100       37561 next if $l =~ /^\#/;
38 13986 100       1548262 next unless my @l = split /\s+/, $l;
39              
40 12212 100       55052 if ($l[0] =~ m/^vendor$/i)
    100          
    100          
    100          
    100          
    50          
41             {
42 70 50 33     926 if (defined $l[1] and defined $l[2] and $l[2] =~ /^[xo0-9]+$/)
      33        
43             {
44 70 50       287 if (substr($l[2],0,1) eq "0") { #allow hex or octal
45 0         0 my $num = lc($l[2]);
46 0         0 $num =~ s/^0b//;
47 0         0 $l[2] = oct($num);
48             }
49 70         477 $self->{vendors}->{$l[1]} = $l[2];
50             }
51             else
52             {
53 0         0 warn "Garbled VENDOR line $l\n";
54             }
55             }
56             elsif ($l[0] =~ m/^attribute$/i)
57             {
58 3228 100       7597 if (@l == 4)
    100          
59             {
60 1215         5072 $self->{attr}->{$l[1]} = [@l[2,3]];
61 1215         7273 $self->{rattr}->{$l[2]} = [@l[1,3]];
62             }
63             elsif (@l == 5) # VENDORATTR
64             {
65 1980 100       4094 if (substr($l[2],0,1) eq "0") { #allow hex or octal
66 264         334 my $num = lc($l[2]);
67 264         277 $num =~ s/^0b//;
68 264         367 $l[2] = oct($num);
69             }
70 1980 50       4286 if (exists $self->{vendors}->{$l[4]})
    0          
71             {
72 1980         9975 $self->{vsattr}->{$self->{vendors}->{$l[4]}}->{$l[1]}
73             = [@l[2, 3]];
74 1980         14301 $self->{rvsattr}->{$self->{vendors}->{$l[4]}}->{$l[2]}
75             = [@l[1, 3]];
76             }
77             elsif ($l[4] =~ m/^\d+$/)
78             {
79 0         0 $self->{vsattr}->{$l[4]}->{$l[1]} = [@l[2, 3]];
80 0         0 $self->{rvsattr}->{$l[4]}->{$l[2]} = [@l[1, 3]];
81             }
82             else
83             {
84 0         0 warn "Warning: Unknown vendor $l[4]\n";
85             }
86             }
87             }
88             elsif ($l[0] =~ m/^value$/i) {
89 6415 100       13330 if (exists $self->{attr}->{$l[1]}) {
90 1634         6190 $self->{val}->{$self->{attr}->{$l[1]}->[0]}->{$l[2]} = $l[3];
91 1634         8935 $self->{rval}->{$self->{attr}->{$l[1]}->[0]}->{$l[3]} = $l[2];
92             }
93             else {
94 4781         4547 for my $v (keys %{$self->{vsattr}})
  4781         10903  
95             {
96 4735 100       12392 if (defined $self->{vsattr}->{$v}->{$l[1]})
97             {
98 4688         19453 $self->{vsaval}->{$v}->{$self->{vsattr}->{$v}
99             ->{$l[1]}->[0]}->{$l[2]}
100             = $l[3];
101 4688         32976 $self->{rvsaval}->{$v}->{$self->{vsattr}->{$v}
102             ->{$l[1]}->[0]}->{$l[3]}
103             = $l[2];
104             }
105             }
106             }
107             }
108             elsif ($l[0] =~ m/^vendorattr$/i) {
109 528 100       1291 if (substr($l[3],0,1) eq "0") { #allow hex or octal
110 518         715 my $num = lc($l[3]);
111 518         818 $num =~ s/^0b//;
112 518         1115 $l[3] = oct($num);
113             }
114 528 100       10168 if (exists $self->{vendors}->{$l[1]})
    50          
115             {
116 259         1117 $self->{vsattr}->{$self->{vendors}->{$l[1]}}->{$l[2]}
117             = [@l[3, 4]];
118 259         1663 $self->{rvsattr}->{$self->{vendors}->{$l[1]}}->{$l[3]}
119             = [@l[2, 4]];
120             }
121             elsif ($l[1] =~ m/^\d+$/)
122             {
123 269         1551 $self->{vsattr}->{$l[1]}->{$l[2]} = [@l[3, 4]];
124 269         4616 $self->{rvsattr}->{$l[1]}->{$l[3]} = [@l[2, 4]];
125             }
126             else
127             {
128 0         0 warn "Warning: Unknown vendor $l[1]\n";
129             }
130             }
131             elsif ($l[0] =~ m/^vendorvalue$/i) {
132 1961 100       6209 if (substr($l[4],0,1) eq "0")
133             { #allow hex or octal
134 48         111 my $num = lc($l[4]);
135 48         50 $num =~ s/^0b//;
136 48         112 $l[4] = oct($num);
137             }
138 1961 100       5528 if (exists $self->{vendors}->{$l[1]})
    50          
139             {
140 979         4377 $self->{vsaval}->{$self->{vendors}->{$l[1]}}
141             ->{$self->{vsattr}->{$self->{vendors}->{$l[1]}}
142             ->{$l[2]}->[0]}->{$l[3]} = $l[4];
143 979         6911 $self->{rvsaval}->{$self->{vendors}->{$l[1]}}
144             ->{$self->{vsattr}->{$self->{vendors}->{$l[1]}}
145             ->{$l[2]}->[0]}->{$l[4]} = $l[3];
146             }
147             elsif ($l[1] =~ m/^\d+$/)
148             {
149 982         9637 $self->{vsaval}->{$l[1]}->{$self->{vsattr}->{$l[1]}->{$l[2]}
150             ->[0]}->{$l[3]} = $l[4];
151 982         19607 $self->{rvsaval}->{$l[1]}->{$self->{vsattr}->{$l[1]}->{$l[2]}
152             ->[0]}->{$l[4]} = $l[3];
153             }
154             else {
155 0         0 warn "Warning: $filename contains vendor value for ",
156             "unknown vendor attribute - ignored ",
157             "\"$l[1]\"\n $l";
158             }
159             }
160             elsif (lc($l[0]) eq 'packet') {
161 10         17 my ($name, $value) = @l[1,2];
162 10         26 $self->{packet}{$name} = $value;
163 10         51 $self->{rpacket}{$value} = $name;
164             }
165             else {
166 0         0 warn "Warning: Weird dictionary line: $l\n";
167             }
168             }
169 93         6490 close DICT;
170             }
171              
172             # Accessors for standard attributes
173              
174 65     65 1 128773 sub vendor_num { $_[0]->{vendors}->{$_[1]}; }
175 77     77 1 1810 sub attr_num { $_[0]->{attr}->{$_[1]}->[0]; }
176 52     52 1 221 sub attr_type { $_[0]->{attr}->{$_[1]}->[1]; }
177 105     105 1 485 sub attr_name { $_[0]->{rattr}->{$_[1]}->[0]; }
178 309     309 1 1585 sub attr_numtype { $_[0]->{rattr}->{$_[1]}->[1]; }
179 10     10 1 66 sub attr_has_val { $_[0]->{val}->{$_[1]}; }
180 39     39 1 231 sub val_has_name { $_[0]->{rval}->{$_[1]}; }
181 14     14 1 92 sub val_num { $_[0]->{val}->{$_[1]}->{$_[2]}; }
182 31     31 1 187 sub val_name { $_[0]->{rval}->{$_[1]}->{$_[2]}; }
183 0     0 0 0 sub val_tag { $_[0]->{val}->{$_[1]}->{$_[3]}; }
184              
185             # Accessors for Vendor-Specific Attributes
186              
187 8     8 0 57 sub vsattr_num { $_[0]->{vsattr}->{$_[1]}->{$_[2]}->[0]; }
188 6     6 0 35 sub vsattr_type { $_[0]->{vsattr}->{$_[1]}->{$_[2]}->[1]; }
189 42     42 0 183 sub vsattr_name { $_[0]->{rvsattr}->{$_[1]}->{$_[2]}->[0]; }
190 120     120 0 651 sub vsattr_numtype { $_[0]->{rvsattr}->{$_[1]}->{$_[2]}->[1]; }
191 1     1 0 11 sub vsattr_has_val { $_[0]->{vsaval}->{$_[1]}->{$_[2]}; }
192 16     16 0 106 sub vsaval_has_name { $_[0]->{rvsaval}->{$_[1]}->{$_[2]}; }
193 0     0 0 0 sub vsaval_has_tval { $_[0]->{vsaval}->{$_[1]}->{$_[2]}->[0]; }
194 0     0 0 0 sub vsaval_has_tag { $_[0]->{vsaval}->{$_[1]}->{$_[2]}->[1]; }
195 0     0 0 0 sub vsaval_num { $_[0]->{vsaval}->{$_[1]}->{$_[2]}->{$_[3]}; }
196 0     0 0 0 sub vsaval_name { $_[0]->{rvsaval}->{$_[1]}->{$_[2]}->{$_[3]}; }
197              
198             # Accessors for packet types. Fall-back to defaults if the case.
199              
200             # Defaults taken from http://www.iana.org/assignments/radius-types
201             # as of Oct 21, 2006
202             my %default_packets = (
203             'Access-Request' => 1, # [RFC2865]
204             'Access-Accept' => 2, # [RFC2865]
205             'Access-Reject' => 3, # [RFC2865]
206             'Accounting-Request' => 4, # [RFC2865]
207             'Accounting-Response' => 5, # [RFC2865]
208             'Accounting-Status' => 6, # [RFC2882] (now Interim Accounting)
209             'Interim-Accounting' => 6, # see previous note
210             'Password-Request' => 7, # [RFC2882]
211             'Password-Ack' => 8, # [RFC2882]
212             'Password-Reject' => 9, # [RFC2882]
213             'Accounting-Message' => 10, # [RFC2882]
214             'Access-Challenge' => 11, # [RFC2865]
215             'Status-Server' => 12, # (experimental) [RFC2865]
216             'Status-Client' => 13, # (experimental) [RFC2865]
217             'Resource-Free-Request' => 21, # [RFC2882]
218             'Resource-Free-Response' => 22, # [RFC2882]
219             'Resource-Query-Request' => 23, # [RFC2882]
220             'Resource-Query-Response' => 24, # [RFC2882]
221             'Alternate-Resource-Reclaim-Request' => 25, # [RFC2882]
222             'NAS-Reboot-Request' => 26, # [RFC2882]
223             'NAS-Reboot-Response' => 27, # [RFC2882]
224             # 28 Reserved
225             'Next-Passcode' => 29, # [RFC2882]
226             'New-Pin' => 30, # [RFC2882]
227             'Terminate-Session' => 31, # [RFC2882]
228             'Password-Expired' => 32, # [RFC2882]
229             'Event-Request' => 33, # [RFC2882]
230             'Event-Response' => 34, # [RFC2882]
231             'Disconnect-Request' => 40, # [RFC3575]
232             'Disconnect-ACK' => 41, # [RFC3575]
233             'Disconnect-NAK' => 42, # [RFC3575]
234             'CoA-Request' => 43, # [RFC3575]
235             'CoA-ACK' => 44, # [RFC3575]
236             'CoA-NAK' => 45, # [RFC3575]
237             'IP-Address-Allocate' => 50, # [RFC2882]
238             'IP-Address-Release' => 51, # [RFC2882]
239             # 250-253 Experimental Use
240             # 254 Reserved
241             # 255 Reserved [RFC2865]
242             );
243              
244             # Reverse defaults. Remember that code #6 has a double mapping, force
245             # to Interim-Accouting
246             my %default_rpackets
247             = map { $default_packets{$_} => $_ } keys %default_packets;
248             $default_rpackets{6} = 'Interim-Accounting';
249              
250             # Get full hashes
251 8 100   8 0 1471 sub packet_numbers { %{ $_[0]->{packet} || \%default_packets } }
  8         517  
252 20 100   20 0 3147 sub packet_names { %{ $_[0]->{rpacket} || \%default_rpackets }; }
  20         788  
253              
254             # Single resolution, I'm taking care of avoiding auto-vivification
255             sub packet_hasname {
256 8   100 8 0 2358 my $href = $_[0]->{packet} || \%default_packets;
257 8         19 my $ok = exists $href->{$_[1]};
258 8 100       34 return $ok unless wantarray;
259             # return both answer and the resolution
260 4 100       31 return ($ok, $ok ? $href->{$_[1]} : undef);
261             }
262              
263             sub packet_hasnum {
264 8   100 8 0 41 my $href = $_[0]->{rpacket} || \%default_rpackets;
265 8         22 my $ok = exists $href->{$_[1]};
266 8 100       30 return $ok unless wantarray;
267             # return both answer and the resolution
268 4 100       26 return ($ok, $ok ? $href->{$_[1]} : undef);
269             }
270              
271             # Note: crossed, as it might not be immediately evident
272 4     4 0 15 sub packet_num { ($_[0]->packet_hasname($_[1]))[1]; }
273 4     4 0 14 sub packet_name { ($_[0]->packet_hasnum($_[1]))[1]; }
274              
275             1;
276             __END__