radiustar 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +11 -0
- data/README.rdoc +50 -16
- data/Rakefile +7 -7
- data/lib/radiustar/dictionary.rb +63 -26
- data/lib/radiustar/dictionary/attributes.rb +23 -7
- data/lib/radiustar/dictionary/values.rb +3 -3
- data/lib/radiustar/packet.rb +187 -54
- data/lib/radiustar/request.rb +101 -25
- data/lib/radiustar/vendor.rb +2 -2
- data/radiustar.gemspec +18 -16
- data/spec/radiustar_spec.rb +13 -3
- data/spec/value_spec.rb +11 -0
- data/templates/dictionary.rfc2865 +137 -0
- data/version.txt +1 -1
- metadata +36 -15
- data/.gitignore +0 -7
data/History.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
== 0.0.5 / 2012-02-02
|
2
|
+
* Bugfixes(charl, Mark Bryars, jamesotron, dguerri, gderosa, mkocher)
|
3
|
+
* You can now use VSAs in packets (jamesotron)
|
4
|
+
* Add support for CoA and Disconnect Packets (Mark Bryars)
|
5
|
+
|
6
|
+
== 0.0.4 / 2010-12/04
|
7
|
+
* github fork (dguerri)
|
8
|
+
* bugfixes
|
9
|
+
* added multiple dictionary files support (dguerri)
|
10
|
+
* added accounting support
|
11
|
+
|
1
12
|
== 0.0.3 / 2010-06-30
|
2
13
|
* no longer require to specify your own IP (via bwlang)
|
3
14
|
|
data/README.rdoc
CHANGED
@@ -32,27 +32,50 @@ Ruby Radius Library
|
|
32
32
|
|
33
33
|
== FEATURES
|
34
34
|
|
35
|
-
* Import your own radius
|
36
|
-
*
|
37
|
-
*
|
38
|
-
|
39
|
-
== COMING SOON
|
40
|
-
|
41
|
-
* Use vendor specific attributes
|
35
|
+
* Import your own radius dictionaries
|
36
|
+
* Authentication
|
37
|
+
* Accounting
|
42
38
|
|
43
39
|
== SYNOPSIS:
|
44
40
|
|
41
|
+
require 'rubygems'
|
45
42
|
require 'radiustar'
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
44
|
+
# Load dictionaries from freeradius directory
|
45
|
+
dict = Radiustar::Dictionary.new('/usr/share/freeradius/')
|
46
|
+
|
47
|
+
# Lets get authenticated
|
48
|
+
auth_custom_attr = {
|
49
|
+
'Framed-Address' => '127.0.0.1',
|
50
|
+
'NAS-Port' => 0,
|
51
|
+
'NAS-Port-Type' => 'Ethernet'
|
52
|
+
}
|
53
|
+
|
54
|
+
req = Radiustar::Request.new('127.0.0.1', { :dict => dict })
|
55
|
+
reply = req.authenticate('John Doe', 'hello', 'testing123', auth_custom_attr)
|
56
|
+
|
57
|
+
if reply[:code] == 'Access-Accept'
|
58
|
+
req = Radiustar::Request.new('127.0.0.1:1813', { :dict => dict })
|
59
|
+
|
60
|
+
acct_custom_attr = {
|
61
|
+
'Framed-Address' => '127.0.0.1',
|
62
|
+
'NAS-Port' => 0,
|
63
|
+
'NAS-Port-Type' => 'Ethernet',
|
64
|
+
'Acct-Session-Time' => 0
|
65
|
+
}
|
66
|
+
|
67
|
+
timings = Time.now
|
68
|
+
reply = req.accounting_start('John Doe', 'testing123', '123456', acct_custom_attr)
|
69
|
+
|
70
|
+
sleep(rand 5)
|
71
|
+
acct_custom_attr['Acct-Session-Time'] = Time.now - timings
|
72
|
+
reply = req.accounting_update('John Doe', 'testing123', '123456', acct_custom_attr)
|
73
|
+
|
74
|
+
sleep(rand 5)
|
75
|
+
acct_custom_attr['Acct-Session-Time'] = Time.now - timings
|
76
|
+
reply = req.accounting_stop('John Doe', 'testing123', '123456', acct_custom_attr)
|
77
|
+
|
78
|
+
end
|
56
79
|
|
57
80
|
== REQUIREMENTS:
|
58
81
|
|
@@ -62,6 +85,17 @@ Ruby Radius Library
|
|
62
85
|
|
63
86
|
gem install radiustar
|
64
87
|
|
88
|
+
== Thanks:
|
89
|
+
Thanks to everyone who has contributed to this project. Without your help and support, this would not have been possible.
|
90
|
+
|
91
|
+
* charl
|
92
|
+
* Mark Bryars
|
93
|
+
* jamesotron
|
94
|
+
* dguerri
|
95
|
+
* gderosa
|
96
|
+
* mkocher
|
97
|
+
* bwlang
|
98
|
+
|
65
99
|
== LICENSE:
|
66
100
|
|
67
101
|
Copyright (c) 2010 [PJ Davis], released under the CC0 1.0 Universal license.
|
data/Rakefile
CHANGED
@@ -9,12 +9,12 @@ task :default => 'test:run'
|
|
9
9
|
task 'gem:release' => 'test:run'
|
10
10
|
|
11
11
|
Bones {
|
12
|
-
name
|
13
|
-
authors
|
14
|
-
email
|
15
|
-
url
|
16
|
-
ignore_file
|
17
|
-
readme_file
|
18
|
-
|
12
|
+
name 'radiustar'
|
13
|
+
authors 'PJ Davis'
|
14
|
+
email 'pj.davis@gmail.com'
|
15
|
+
url 'http://github.com/pjdavis/radiustar'
|
16
|
+
ignore_file '.gitignore'
|
17
|
+
readme_file 'README.rdoc'
|
18
|
+
depend_on 'ipaddr_extensions'
|
19
19
|
}
|
20
20
|
|
data/lib/radiustar/dictionary.rb
CHANGED
@@ -4,38 +4,25 @@ module Radiustar
|
|
4
4
|
|
5
5
|
include Radiustar
|
6
6
|
|
7
|
-
|
7
|
+
DEFAULT_DICTIONARIES_PATH = ::File.join(::File.dirname(__FILE__), '..', '..', 'templates')
|
8
8
|
|
9
9
|
def initialize(initial_path = nil)
|
10
10
|
@attributes = AttributesCollection.new
|
11
11
|
@vendors = VendorCollection.new
|
12
12
|
|
13
|
-
|
13
|
+
read_files initial_path if initial_path
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
when "ATTRIBUTE"
|
25
|
-
current_vendor.nil? ? set_attr(split_line) : set_vendor_attr(current_vendor, split_line)
|
26
|
-
when "VALUE"
|
27
|
-
current_vendor.nil? ? set_value(split_line) : set_vendor_value(current_vendor, split_line)
|
28
|
-
when "VENDOR"
|
29
|
-
add_vendor(split_line)
|
30
|
-
when "BEGIN-VENDOR"
|
31
|
-
current_vendor = set_vendor(split_line)
|
32
|
-
when "END-VENDOR"
|
33
|
-
current_vendor = nil
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
16
|
+
def read_files(path)
|
17
|
+
dict_files = File.join(path, "*")
|
18
|
+
Dir.glob(dict_files) { |file|
|
19
|
+
read_attributes(file)
|
20
|
+
}
|
21
|
+
Dir.glob(dict_files) { |file|
|
22
|
+
read_values(file)
|
23
|
+
}
|
37
24
|
end
|
38
|
-
|
25
|
+
|
39
26
|
def find_attribute_by_name(name)
|
40
27
|
@attributes.find_by_name(name)
|
41
28
|
end
|
@@ -67,9 +54,59 @@ module Radiustar
|
|
67
54
|
class << self
|
68
55
|
|
69
56
|
def default
|
70
|
-
new
|
57
|
+
new DEFAULT_DICTIONARIES_PATH
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
def read_attributes(path)
|
65
|
+
file = File.open(path) do |f|
|
66
|
+
current_vendor = nil
|
67
|
+
f.each_line do |line|
|
68
|
+
next if line =~ /^\#/ # discard comments
|
69
|
+
split_line = line.split(/\s+/)
|
70
|
+
next if split_line == []
|
71
|
+
case split_line.first.upcase
|
72
|
+
when "ATTRIBUTE"
|
73
|
+
current_vendor.nil? ? set_attr(split_line) : set_vendor_attr(current_vendor, split_line)
|
74
|
+
when "VENDOR"
|
75
|
+
add_vendor(split_line)
|
76
|
+
when "BEGIN-VENDOR"
|
77
|
+
current_vendor = set_vendor(split_line)
|
78
|
+
when "END-VENDOR"
|
79
|
+
current_vendor = nil
|
80
|
+
end
|
81
|
+
end
|
71
82
|
end
|
83
|
+
end
|
72
84
|
|
85
|
+
def read_values(path)
|
86
|
+
file = File.open(path) do |f|
|
87
|
+
current_vendor = nil
|
88
|
+
f.each_line do |line|
|
89
|
+
next if line =~ /^\#/ # discard comments
|
90
|
+
split_line = line.split(/\s+/)
|
91
|
+
next if split_line == []
|
92
|
+
case split_line.first.upcase
|
93
|
+
when "VALUE"
|
94
|
+
if current_vendor.nil?
|
95
|
+
set_value(split_line)
|
96
|
+
else
|
97
|
+
begin
|
98
|
+
set_vendor_value(current_vendor, split_line)
|
99
|
+
rescue
|
100
|
+
set_value(split_line)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
when "BEGIN-VENDOR"
|
104
|
+
current_vendor = set_vendor(split_line)
|
105
|
+
when "END-VENDOR"
|
106
|
+
current_vendor = nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
73
110
|
end
|
74
111
|
|
75
112
|
private
|
@@ -100,4 +137,4 @@ module Radiustar
|
|
100
137
|
|
101
138
|
end
|
102
139
|
|
103
|
-
end
|
140
|
+
end
|
@@ -2,13 +2,20 @@ module Radiustar
|
|
2
2
|
|
3
3
|
class AttributesCollection < Array
|
4
4
|
|
5
|
-
|
5
|
+
attr_accessor :vendor
|
6
|
+
|
7
|
+
def initialize vendor=nil
|
6
8
|
@collection = {}
|
7
|
-
@revcollection =
|
9
|
+
@revcollection = {}
|
10
|
+
@vendor = vendor if vendor
|
8
11
|
end
|
9
12
|
|
10
13
|
def add(name, id, type)
|
11
|
-
|
14
|
+
if vendor?
|
15
|
+
@collection[name] ||= Attribute.new(name, id.to_i, type, @vendor)
|
16
|
+
else
|
17
|
+
@collection[name] ||= Attribute.new(name, id.to_i, type)
|
18
|
+
end
|
12
19
|
@revcollection[id.to_i] ||= @collection[name]
|
13
20
|
self << @collection[name]
|
14
21
|
end
|
@@ -18,7 +25,11 @@ module Radiustar
|
|
18
25
|
end
|
19
26
|
|
20
27
|
def find_by_id(id)
|
21
|
-
@revcollection[id
|
28
|
+
@revcollection[id]
|
29
|
+
end
|
30
|
+
|
31
|
+
def vendor?
|
32
|
+
!!@vendor
|
22
33
|
end
|
23
34
|
|
24
35
|
end
|
@@ -27,13 +38,14 @@ module Radiustar
|
|
27
38
|
|
28
39
|
include Radiustar
|
29
40
|
|
30
|
-
attr_reader :name, :id, :type
|
41
|
+
attr_reader :name, :id, :type, :vendor
|
31
42
|
|
32
|
-
def initialize(name, id, type)
|
43
|
+
def initialize(name, id, type, vendor=nil)
|
33
44
|
@values = ValuesCollection.new
|
34
45
|
@name = name
|
35
46
|
@id = id.to_i
|
36
47
|
@type = type
|
48
|
+
@vendor = vendor if vendor
|
37
49
|
end
|
38
50
|
|
39
51
|
def add_value(name, id)
|
@@ -56,6 +68,10 @@ module Radiustar
|
|
56
68
|
@values
|
57
69
|
end
|
58
70
|
|
71
|
+
def vendor?
|
72
|
+
!!@vendor
|
73
|
+
end
|
74
|
+
|
59
75
|
end
|
60
76
|
|
61
|
-
end
|
77
|
+
end
|
@@ -4,7 +4,7 @@ module Radiustar
|
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@collection = {}
|
7
|
-
@revcollection =
|
7
|
+
@revcollection = {}
|
8
8
|
end
|
9
9
|
|
10
10
|
def add(name, id)
|
@@ -31,7 +31,7 @@ module Radiustar
|
|
31
31
|
|
32
32
|
include Radiustar
|
33
33
|
|
34
|
-
attr_accessor :name
|
34
|
+
attr_accessor :name, :id
|
35
35
|
|
36
36
|
def initialize(name, id)
|
37
37
|
@name = name
|
@@ -40,4 +40,4 @@ module Radiustar
|
|
40
40
|
|
41
41
|
end
|
42
42
|
|
43
|
-
end
|
43
|
+
end
|
data/lib/radiustar/packet.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
module Radiustar
|
2
2
|
|
3
3
|
require 'digest/md5'
|
4
|
+
require 'ipaddr_extensions'
|
4
5
|
|
5
6
|
class Packet
|
6
7
|
|
7
8
|
CODES = { 'Access-Request' => 1, 'Access-Accept' => 2,
|
8
9
|
'Access-Reject' => 3, 'Accounting-Request' => 4,
|
9
10
|
'Accounting-Response' => 5, 'Access-Challenge' => 11,
|
10
|
-
'Status-Server' => 12, 'Status-Client' => 13
|
11
|
+
'Status-Server' => 12, 'Status-Client' => 13,
|
12
|
+
'Disconnect-Request' => 40, 'Disconnect-ACK' => 41,
|
13
|
+
'Disconnect-NAK' => 42, 'CoA-Request' => 43,
|
14
|
+
'CoA-ACK' => 44, 'CoA-NAK' => 45 }
|
11
15
|
|
12
16
|
|
13
17
|
HDRLEN = 1 + 1 + 2 + 16 # size of packet header
|
@@ -15,7 +19,7 @@ module Radiustar
|
|
15
19
|
P_ATTR = "CCa*" # pack template for attribute
|
16
20
|
|
17
21
|
attr_accessor :code
|
18
|
-
attr_reader :id, :attributes
|
22
|
+
attr_reader :id, :attributes, :authenticator
|
19
23
|
|
20
24
|
def initialize(dictionary, id, data = nil)
|
21
25
|
@dict = dictionary
|
@@ -38,63 +42,100 @@ module Radiustar
|
|
38
42
|
|
39
43
|
# Generate an authenticator. It will try to use /dev/urandom if
|
40
44
|
# possible, or the system rand call if that's not available.
|
41
|
-
def
|
42
|
-
authenticator = []
|
43
|
-
8.times do
|
44
|
-
authenticator << rand(65536)
|
45
|
-
end
|
46
|
-
authenticator.pack("n8")
|
45
|
+
def gen_auth_authenticator
|
47
46
|
if (File.exist?("/dev/urandom"))
|
48
47
|
File.open("/dev/urandom") do |urandom|
|
49
|
-
authenticator = urandom.read(16)
|
48
|
+
@authenticator = urandom.read(16)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
@authenticator = []
|
52
|
+
8.times do
|
53
|
+
@authenticator << rand(65536)
|
50
54
|
end
|
55
|
+
@authenticator = @authenticator.pack("n8")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def gen_acct_authenticator(secret)
|
60
|
+
# From RFC2866
|
61
|
+
# Request Authenticator
|
62
|
+
#
|
63
|
+
# In Accounting-Request Packets, the Authenticator value is a 16
|
64
|
+
# octet MD5 [5] checksum, called the Request Authenticator.
|
65
|
+
#
|
66
|
+
# The NAS and RADIUS accounting server share a secret. The Request
|
67
|
+
# Authenticator field in Accounting-Request packets contains a one-
|
68
|
+
# way MD5 hash calculated over a stream of octets consisting of the
|
69
|
+
# Code + Identifier + Length + 16 zero octets + request attributes +
|
70
|
+
# shared secret (where + indicates concatenation). The 16 octet MD5
|
71
|
+
# hash value is stored in the Authenticator field of the
|
72
|
+
# Accounting-Request packet.
|
73
|
+
#
|
74
|
+
# Note that the Request Authenticator of an Accounting-Request can
|
75
|
+
# not be done the same way as the Request Authenticator of a RADIUS
|
76
|
+
# Access-Request, because there is no User-Password attribute in an
|
77
|
+
# Accounting-Request.
|
78
|
+
#
|
79
|
+
@authenticator = "\000"*16
|
80
|
+
@authenticator = Digest::MD5.digest(pack + secret)
|
81
|
+
@packed = nil
|
82
|
+
@authenticator
|
83
|
+
end
|
84
|
+
|
85
|
+
def gen_response_authenticator(secret, request_authenticator)
|
86
|
+
@authenticator = request_authenticator
|
87
|
+
@authenticator = Digest::MD5.digest(pack + secret)
|
88
|
+
@packed = nil
|
89
|
+
@authenticator
|
90
|
+
end
|
91
|
+
|
92
|
+
def validate_acct_authenticator(secret)
|
93
|
+
if @authenticator
|
94
|
+
original_authenticator = @authenticator
|
95
|
+
if gen_acct_authenticator(secret) == original_authenticator
|
96
|
+
true
|
97
|
+
else
|
98
|
+
@authenticator = original_authenticator
|
99
|
+
false
|
100
|
+
end
|
101
|
+
else
|
102
|
+
false
|
51
103
|
end
|
52
|
-
@authenticator = authenticator
|
53
104
|
end
|
54
105
|
|
55
106
|
def set_attribute(name, value)
|
56
|
-
@attributes[name] = value
|
107
|
+
@attributes[name] = Attribute.new(@dict, name, value)
|
57
108
|
end
|
58
109
|
|
59
110
|
def unset_attribute(name)
|
60
|
-
@attributes
|
111
|
+
@attributes.delete(name)
|
61
112
|
end
|
62
113
|
|
63
114
|
def attribute(name)
|
64
|
-
@attributes[name]
|
115
|
+
if @attributes[name]
|
116
|
+
@attributes[name].value
|
117
|
+
end
|
65
118
|
end
|
66
119
|
|
67
120
|
def unset_all_attributes
|
68
|
-
@attributes =
|
121
|
+
@attributes = {}
|
69
122
|
end
|
70
123
|
|
71
124
|
def set_encoded_attribute(name, value, secret)
|
72
|
-
@attributes[name] = encode(value, secret)
|
125
|
+
@attributes[name] = Attribute.new(@dict, name, encode(value, secret))
|
73
126
|
end
|
74
127
|
|
75
|
-
def
|
128
|
+
def decode_attribute(name, secret)
|
129
|
+
if @attributes[name]
|
130
|
+
decode(@attributes[name].value.to_s, secret)
|
131
|
+
end
|
132
|
+
end
|
76
133
|
|
134
|
+
def pack
|
77
135
|
attstr = ""
|
78
|
-
@attributes.
|
79
|
-
|
80
|
-
anum = attribute.id
|
81
|
-
val = case attribute.type
|
82
|
-
when "string"
|
83
|
-
value
|
84
|
-
when "integer"
|
85
|
-
[attribute.has_values? ? attribute.find_values_by_id(value) : value].pack("N")
|
86
|
-
when "ipaddr"
|
87
|
-
[inet_aton(value)].pack("N")
|
88
|
-
when "date"
|
89
|
-
[value].pack("N")
|
90
|
-
when "time"
|
91
|
-
[value].pack("N")
|
92
|
-
else
|
93
|
-
next
|
94
|
-
end
|
95
|
-
attstr += [attribute.id, val.length + 2, val].pack(P_ATTR)
|
136
|
+
@attributes.values.each do |attribute|
|
137
|
+
attstr += attribute.pack
|
96
138
|
end
|
97
|
-
|
98
139
|
@packed = [CODES[@code], @id, attstr.length + HDRLEN, @authenticator, attstr].pack(P_HDR)
|
99
140
|
end
|
100
141
|
|
@@ -102,7 +143,10 @@ module Radiustar
|
|
102
143
|
|
103
144
|
def unpack
|
104
145
|
@code, @id, len, @authenticator, attribute_data = @packed.unpack(P_HDR)
|
105
|
-
|
146
|
+
raise "Incomplete Packet(read #{@packed.length} != #{len})" if @packed.length != len
|
147
|
+
|
148
|
+
@code = CODES.key(@code)
|
149
|
+
vendor = nil
|
106
150
|
|
107
151
|
unset_all_attributes
|
108
152
|
|
@@ -111,41 +155,43 @@ module Radiustar
|
|
111
155
|
attribute_type, attribute_value = attribute_data.unpack("Cxa#{length-2}")
|
112
156
|
attribute_type = attribute_type.to_i
|
113
157
|
|
114
|
-
|
115
|
-
|
158
|
+
if attribute_type == 26 # Vendor Specific Attribute
|
159
|
+
vid, attribute_type, attribute_value = attribute_data.unpack("xxNCxa#{length-6}")
|
160
|
+
vendor = @dict.vendors.find_by_id(vid)
|
161
|
+
attribute = vendor.find_attribute_by_id(attribute_type)
|
162
|
+
else
|
163
|
+
vendor = nil
|
164
|
+
attribute = @dict.find_attribute_by_id(attribute_type)
|
165
|
+
end
|
166
|
+
|
167
|
+
attribute_value = case attribute.type
|
116
168
|
when 'string'
|
117
169
|
attribute_value
|
118
170
|
when 'integer'
|
119
171
|
attribute.has_values? ? attribute.find_values_by_id(attribute_value.unpack("N")[0]).name : attribute_value.unpack("N")[0]
|
120
172
|
when 'ipaddr'
|
121
|
-
|
173
|
+
attribute_value.unpack("N")[0].to_ip.to_s
|
122
174
|
when 'time'
|
123
175
|
attribute_value.unpack("N")[0]
|
124
176
|
when 'date'
|
125
177
|
attribute_value.unpack("N")[0]
|
126
178
|
end
|
127
179
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
180
|
+
if vendor
|
181
|
+
set_attribute(vendor.name+"/"+attribute.name, attribute_value) if attribute
|
182
|
+
else
|
183
|
+
set_attribute(attribute.name, attribute_value) if attribute
|
184
|
+
end
|
132
185
|
|
133
|
-
|
134
|
-
if (hostname =~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/)
|
135
|
-
return (($1.to_i & 0xff) << 24) + (($2.to_i & 0xff) << 16) + (($3.to_i & 0xff) << 8) + (($4.to_i & 0xff))
|
186
|
+
attribute_data[0, length] = ""
|
136
187
|
end
|
137
|
-
0
|
138
|
-
end
|
139
|
-
|
140
|
-
def inet_ntoa(iaddr)
|
141
|
-
sprintf("%d.%d.%d.%d", (iaddr >> 24) & 0xff, (iaddr >> 16) & 0xff, (iaddr >> 8) & 0xff, (iaddr) & 0xff)
|
142
188
|
end
|
143
189
|
|
144
190
|
def xor_str(str1, str2)
|
145
191
|
i = 0
|
146
192
|
newstr = ""
|
147
193
|
str1.each_byte do |c1|
|
148
|
-
c2 = str2[i]
|
194
|
+
c2 = str2.bytes.to_a[i]
|
149
195
|
newstr = newstr << (c1 ^ c2)
|
150
196
|
i = i+1
|
151
197
|
end
|
@@ -168,7 +214,7 @@ module Radiustar
|
|
168
214
|
decoded_value = ""
|
169
215
|
lastround = @authenticator
|
170
216
|
0.step(value.length-1, 16) do |i|
|
171
|
-
decoded_value
|
217
|
+
decoded_value += xor_str(value[i, 16], Digest::MD5.digest(secret + lastround))
|
172
218
|
lastround = value[i, 16]
|
173
219
|
end
|
174
220
|
|
@@ -177,5 +223,92 @@ module Radiustar
|
|
177
223
|
return decoded_value
|
178
224
|
end
|
179
225
|
|
226
|
+
class Attribute
|
227
|
+
|
228
|
+
attr_reader :dict, :name, :vendor
|
229
|
+
attr_accessor :value
|
230
|
+
|
231
|
+
def initialize dict, name, value, vendor=nil
|
232
|
+
@dict = dict
|
233
|
+
# This is the cheapest and easiest way to add VSA's!
|
234
|
+
if (name && (chunks = name.split('/')) && (chunks.size == 2))
|
235
|
+
@vendor = chunks[0]
|
236
|
+
@name = chunks[1]
|
237
|
+
else
|
238
|
+
@name = name
|
239
|
+
end
|
240
|
+
@vendor ||= vendor
|
241
|
+
@value = value.is_a?(Attribute) ? value.to_s : value
|
242
|
+
end
|
243
|
+
|
244
|
+
def vendor?
|
245
|
+
!!@vendor
|
246
|
+
end
|
247
|
+
|
248
|
+
def pack
|
249
|
+
attribute = if (vendor? && (@dict.vendors.find_by_name(@vendor)))
|
250
|
+
@dict.vendors.find_by_name(@vendor).attributes.find_by_name(@name)
|
251
|
+
else
|
252
|
+
@dict.find_attribute_by_name(@name)
|
253
|
+
end
|
254
|
+
raise "Undefined attribute '#{@name}'." if attribute.nil?
|
255
|
+
|
256
|
+
if vendor?
|
257
|
+
pack_vendor_specific_attribute attribute
|
258
|
+
else
|
259
|
+
pack_attribute attribute
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def inspect
|
264
|
+
@value
|
265
|
+
end
|
266
|
+
|
267
|
+
def to_s
|
268
|
+
@value
|
269
|
+
end
|
270
|
+
|
271
|
+
private
|
272
|
+
|
273
|
+
def pack_vendor_specific_attribute attribute
|
274
|
+
inside_attribute = pack_attribute attribute
|
275
|
+
vid = attribute.vendor.id.to_i
|
276
|
+
header = [ 26, inside_attribute.size + 6 ].pack("CC") # 26: Type = Vendor-Specific, 4: length of Vendor-Id field
|
277
|
+
header += [ 0, vid >> 16, vid >> 8, vid ].pack("CCCC") # first byte of Vendor-Id is 0
|
278
|
+
header + inside_attribute
|
279
|
+
end
|
280
|
+
|
281
|
+
def pack_attribute attribute
|
282
|
+
anum = attribute.id
|
283
|
+
val = case attribute.type
|
284
|
+
when "string"
|
285
|
+
@value
|
286
|
+
when "integer"
|
287
|
+
raise "Invalid value name '#{@value}'." if attribute.has_values? && attribute.find_values_by_name(@value).nil?
|
288
|
+
[attribute.has_values? ? attribute.find_values_by_name(@value).id : @value].pack("N")
|
289
|
+
when "ipaddr"
|
290
|
+
[@value.to_ip.to_i].pack("N")
|
291
|
+
when "ipv6addr"
|
292
|
+
ipi = @value.to_ip.to_i
|
293
|
+
[ ipi >> 96, ipi >> 64, ipi >> 32, ipi ].pack("NNNN")
|
294
|
+
when "date"
|
295
|
+
[@value].pack("N")
|
296
|
+
when "time"
|
297
|
+
[@value].pack("N")
|
298
|
+
else
|
299
|
+
""
|
300
|
+
end
|
301
|
+
begin
|
302
|
+
[anum,
|
303
|
+
val.length + 2,
|
304
|
+
val
|
305
|
+
].pack(P_ATTR)
|
306
|
+
rescue
|
307
|
+
puts "#{@name} => #{@value}"
|
308
|
+
puts [anum, val.length + 2, val].inspect
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
180
313
|
end
|
181
|
-
end
|
314
|
+
end
|
data/lib/radiustar/request.rb
CHANGED
@@ -4,12 +4,14 @@ module Radiustar
|
|
4
4
|
|
5
5
|
class Request
|
6
6
|
|
7
|
-
def initialize(server,
|
8
|
-
@dict =
|
7
|
+
def initialize(server, options = {})
|
8
|
+
@dict = options[:dict].nil? ? Dictionary.default : options[:dict]
|
9
|
+
@nas_ip = options[:nas_ip] || get_my_ip(@host)
|
10
|
+
@nas_identifier = options[:nas_identifier] || @nas_ip
|
11
|
+
@reply_timeout = options[:reply_timeout].nil? ? 60 : options[:reply_timeout].to_i
|
12
|
+
@retries_number = options[:retries_number].nil? ? 1 : options[:retries_number].to_i
|
9
13
|
|
10
14
|
@host, @port = server.split(":")
|
11
|
-
|
12
|
-
@my_ip = my_ip || get_my_ip(@host)
|
13
15
|
|
14
16
|
@port = Socket.getservbyname("radius", "udp") unless @port
|
15
17
|
@port = 1812 unless @port
|
@@ -18,29 +20,104 @@ module Radiustar
|
|
18
20
|
@socket.connect(@host, @port)
|
19
21
|
end
|
20
22
|
|
21
|
-
def authenticate(name, password, secret)
|
23
|
+
def authenticate(name, password, secret, user_attributes = {})
|
22
24
|
@packet = Packet.new(@dict, Process.pid & 0xff)
|
25
|
+
@packet.gen_auth_authenticator
|
23
26
|
@packet.code = 'Access-Request'
|
24
|
-
@packet.gen_authenticator
|
25
27
|
@packet.set_attribute('User-Name', name)
|
26
|
-
@packet.set_attribute('NAS-
|
28
|
+
@packet.set_attribute('NAS-Identifier', @nas_identifier)
|
29
|
+
@packet.set_attribute('NAS-IP-Address', @nas_ip)
|
27
30
|
@packet.set_encoded_attribute('User-Password', password, secret)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
+
|
32
|
+
user_attributes.each_pair do |name, value|
|
33
|
+
@packet.set_attribute(name, value)
|
34
|
+
end
|
35
|
+
|
36
|
+
retries = @retries_number
|
37
|
+
begin
|
38
|
+
send_packet
|
39
|
+
@received_packet = recv_packet(@reply_timeout)
|
40
|
+
rescue Exception => e
|
41
|
+
retry if (retries -= 1) > 0
|
42
|
+
raise
|
43
|
+
end
|
44
|
+
|
45
|
+
reply = { :code => @received_packet.code }
|
46
|
+
reply.merge @received_packet.attributes
|
31
47
|
end
|
48
|
+
|
49
|
+
def accounting_request(status_type, name, secret, sessionid, user_attributes = {})
|
32
50
|
|
33
|
-
def get_attributes(name, password, secret)
|
34
51
|
@packet = Packet.new(@dict, Process.pid & 0xff)
|
35
|
-
@packet.code = '
|
36
|
-
|
52
|
+
@packet.code = 'Accounting-Request'
|
53
|
+
|
37
54
|
@packet.set_attribute('User-Name', name)
|
38
|
-
@packet.set_attribute('NAS-
|
39
|
-
@packet.
|
40
|
-
|
41
|
-
@
|
42
|
-
|
43
|
-
|
55
|
+
@packet.set_attribute('NAS-Identifier', @nas_identifier)
|
56
|
+
@packet.set_attribute('NAS-IP-Address', @nas_ip)
|
57
|
+
@packet.set_attribute('Acct-Status-Type', status_type)
|
58
|
+
@packet.set_attribute('Acct-Session-Id', sessionid)
|
59
|
+
@packet.set_attribute('Acct-Authentic', 'RADIUS')
|
60
|
+
|
61
|
+
user_attributes.each_pair do |name, value|
|
62
|
+
@packet.set_attribute(name, value)
|
63
|
+
end
|
64
|
+
|
65
|
+
@packet.gen_acct_authenticator(secret)
|
66
|
+
|
67
|
+
retries = @retries_number
|
68
|
+
begin
|
69
|
+
send_packet
|
70
|
+
@received_packet = recv_packet(@reply_timeout)
|
71
|
+
rescue Exception => e
|
72
|
+
retry if (retries -= 1) > 0
|
73
|
+
raise
|
74
|
+
end
|
75
|
+
|
76
|
+
return true
|
77
|
+
end
|
78
|
+
|
79
|
+
def generic_request(code, secret, user_attributes = {})
|
80
|
+
@packet = Packet.new(@dict, Process.pid & 0xff)
|
81
|
+
@packet.code = code
|
82
|
+
@packet.set_attribute('NAS-Identifier', @nas_identifier)
|
83
|
+
@packet.set_attribute('NAS-IP-Address', @nas_ip)
|
84
|
+
|
85
|
+
user_attributes.each_pair do |name, value|
|
86
|
+
@packet.set_attribute(name, value)
|
87
|
+
end
|
88
|
+
|
89
|
+
@packet.gen_acct_authenticator(secret)
|
90
|
+
|
91
|
+
retries = @retries_number
|
92
|
+
begin
|
93
|
+
send_packet
|
94
|
+
@received_packet = recv_packet(@reply_timeout)
|
95
|
+
rescue Exception => e
|
96
|
+
retry if (retries -= 1) > 0
|
97
|
+
raise
|
98
|
+
end
|
99
|
+
|
100
|
+
return true
|
101
|
+
end
|
102
|
+
|
103
|
+
def coa_request(secret, user_attributes = {})
|
104
|
+
generic_request('CoA-Request', secret, user_attributes)
|
105
|
+
end
|
106
|
+
|
107
|
+
def disconnect_request(secret, user_attributes = {})
|
108
|
+
generic_request('Disconnect-Request', secret, user_attributes)
|
109
|
+
end
|
110
|
+
|
111
|
+
def accounting_start(name, secret, sessionid, options = {})
|
112
|
+
accounting_request('Start', name, secret, sessionid, options)
|
113
|
+
end
|
114
|
+
|
115
|
+
def accounting_update(name, secret, sessionid, options = {})
|
116
|
+
accounting_request('Interim-Update', name, secret, sessionid, options)
|
117
|
+
end
|
118
|
+
|
119
|
+
def accounting_stop(name, secret, sessionid, options = {})
|
120
|
+
accounting_request('Stop', name, secret, sessionid, options)
|
44
121
|
end
|
45
122
|
|
46
123
|
def inspect
|
@@ -51,15 +128,14 @@ module Radiustar
|
|
51
128
|
|
52
129
|
def send_packet
|
53
130
|
data = @packet.pack
|
54
|
-
@packet.increment_id
|
55
131
|
@socket.send(data, 0)
|
56
132
|
end
|
57
133
|
|
58
|
-
def recv_packet
|
59
|
-
if select([@socket], nil, nil,
|
60
|
-
|
134
|
+
def recv_packet(timeout)
|
135
|
+
if select([@socket], nil, nil, timeout.to_i) == nil
|
136
|
+
raise "Timed out waiting for response packet from server"
|
61
137
|
end
|
62
|
-
data = @socket.recvfrom(
|
138
|
+
data = @socket.recvfrom(4096) # rfc2865 max packet length
|
63
139
|
Packet.new(@dict, Process.pid & 0xff, data[0])
|
64
140
|
end
|
65
141
|
|
@@ -78,4 +154,4 @@ module Radiustar
|
|
78
154
|
|
79
155
|
end
|
80
156
|
|
81
|
-
end
|
157
|
+
end
|
data/lib/radiustar/vendor.rb
CHANGED
@@ -32,7 +32,7 @@ module Radiustar
|
|
32
32
|
def initialize(name, id)
|
33
33
|
@name = name
|
34
34
|
@id = id
|
35
|
-
@attributes = AttributesCollection.new
|
35
|
+
@attributes = AttributesCollection.new self
|
36
36
|
end
|
37
37
|
|
38
38
|
def add_attribute(name, id, type)
|
@@ -57,4 +57,4 @@ module Radiustar
|
|
57
57
|
|
58
58
|
end
|
59
59
|
|
60
|
-
end
|
60
|
+
end
|
data/radiustar.gemspec
CHANGED
@@ -1,34 +1,36 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.name =
|
5
|
-
s.version = "0.0.
|
4
|
+
s.name = "radiustar"
|
5
|
+
s.version = "0.0.5"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["PJ Davis"]
|
9
|
-
s.date =
|
10
|
-
s.description =
|
11
|
-
s.email =
|
12
|
-
s.extra_rdoc_files = ["History.txt", "README.rdoc", "templates/default.txt"
|
13
|
-
s.files = ["
|
14
|
-
s.homepage =
|
9
|
+
s.date = "2012-02-02"
|
10
|
+
s.description = "Ruby Radius Library"
|
11
|
+
s.email = "pj.davis@gmail.com"
|
12
|
+
s.extra_rdoc_files = ["History.txt", "README.rdoc", "templates/default.txt"]
|
13
|
+
s.files = ["History.txt", "README.rdoc", "Rakefile", "lib/radiustar.rb", "lib/radiustar/dictionary.rb", "lib/radiustar/dictionary/attributes.rb", "lib/radiustar/dictionary/values.rb", "lib/radiustar/packet.rb", "lib/radiustar/radiustar.rb", "lib/radiustar/request.rb", "lib/radiustar/vendor.rb", "radiustar.gemspec", "spec/radiustar_spec.rb", "spec/spec_helper.rb", "spec/value_spec.rb", "templates/default.txt", "templates/dictionary.digium", "templates/dictionary.rfc2865", "templates/gandalf.dictionary", "test/test_radiustar.rb", "version.txt"]
|
14
|
+
s.homepage = "http://github.com/pjdavis/radiustar"
|
15
15
|
s.rdoc_options = ["--main", "README.rdoc"]
|
16
16
|
s.require_paths = ["lib"]
|
17
|
-
s.rubyforge_project =
|
18
|
-
s.rubygems_version =
|
19
|
-
s.summary =
|
17
|
+
s.rubyforge_project = "radiustar"
|
18
|
+
s.rubygems_version = "1.8.15"
|
19
|
+
s.summary = "."
|
20
20
|
s.test_files = ["test/test_radiustar.rb"]
|
21
21
|
|
22
22
|
if s.respond_to? :specification_version then
|
23
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
23
|
s.specification_version = 3
|
25
24
|
|
26
|
-
if Gem::Version.new(Gem::
|
27
|
-
s.
|
25
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
26
|
+
s.add_runtime_dependency(%q<ipaddr_extensions>, [">= 2012.1.13"])
|
27
|
+
s.add_development_dependency(%q<bones>, [">= 3.7.3"])
|
28
28
|
else
|
29
|
-
s.add_dependency(%q<
|
29
|
+
s.add_dependency(%q<ipaddr_extensions>, [">= 2012.1.13"])
|
30
|
+
s.add_dependency(%q<bones>, [">= 3.7.3"])
|
30
31
|
end
|
31
32
|
else
|
32
|
-
s.add_dependency(%q<
|
33
|
+
s.add_dependency(%q<ipaddr_extensions>, [">= 2012.1.13"])
|
34
|
+
s.add_dependency(%q<bones>, [">= 3.7.3"])
|
33
35
|
end
|
34
36
|
end
|
data/spec/radiustar_spec.rb
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
-
|
2
1
|
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
3
2
|
|
4
|
-
describe Radiustar do
|
5
|
-
|
3
|
+
describe Radiustar::Packet do
|
4
|
+
it "gen_authenticator generates a random string without /dev/urandom" do
|
5
|
+
File.stub(:exist?).and_return(false)
|
6
|
+
packet = Radiustar::Packet.new(nil, nil)
|
7
|
+
packet.gen_authenticator.class.should == String
|
8
|
+
end
|
6
9
|
|
10
|
+
if File.exist?("/dev/urandom") # don't fail if specs are running on a platform without /dev/urandom
|
11
|
+
it "gen_authenticator generates a random string with /dev/urandom" do
|
12
|
+
packet = Radiustar::Packet.new(nil, nil)
|
13
|
+
packet.gen_authenticator.class.should == String
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/spec/value_spec.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
|
+
|
3
|
+
describe Radiustar::Value do
|
4
|
+
it "should get numeric value of NAS-Port-Type == Ethernet from dictionary.rfc2865" do
|
5
|
+
dict = Radiustar::Dictionary.new
|
6
|
+
dict.read(File.dirname(__FILE__) + '/../templates/dictionary.rfc2865')
|
7
|
+
attribute = dict.find_attribute_by_name 'NAS-Port-Type'
|
8
|
+
ethernet_value = attribute.find_values_by_name 'Ethernet'
|
9
|
+
ethernet_value.id.should == 15
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# -*- text -*-
|
2
|
+
#
|
3
|
+
# Attributes and values defined in RFC 2865.
|
4
|
+
# http://www.ietf.org/rfc/rfc2865.txt
|
5
|
+
#
|
6
|
+
# $Id$
|
7
|
+
#
|
8
|
+
ATTRIBUTE User-Name 1 string
|
9
|
+
ATTRIBUTE User-Password 2 string encrypt=1
|
10
|
+
ATTRIBUTE CHAP-Password 3 octets
|
11
|
+
ATTRIBUTE NAS-IP-Address 4 ipaddr
|
12
|
+
ATTRIBUTE NAS-Port 5 integer
|
13
|
+
ATTRIBUTE Service-Type 6 integer
|
14
|
+
ATTRIBUTE Framed-Protocol 7 integer
|
15
|
+
ATTRIBUTE Framed-IP-Address 8 ipaddr
|
16
|
+
ATTRIBUTE Framed-IP-Netmask 9 ipaddr
|
17
|
+
ATTRIBUTE Framed-Routing 10 integer
|
18
|
+
ATTRIBUTE Filter-Id 11 string
|
19
|
+
ATTRIBUTE Framed-MTU 12 integer
|
20
|
+
ATTRIBUTE Framed-Compression 13 integer
|
21
|
+
ATTRIBUTE Login-IP-Host 14 ipaddr
|
22
|
+
ATTRIBUTE Login-Service 15 integer
|
23
|
+
ATTRIBUTE Login-TCP-Port 16 integer
|
24
|
+
# Attribute 17 is undefined
|
25
|
+
ATTRIBUTE Reply-Message 18 string
|
26
|
+
ATTRIBUTE Callback-Number 19 string
|
27
|
+
ATTRIBUTE Callback-Id 20 string
|
28
|
+
# Attribute 21 is undefined
|
29
|
+
ATTRIBUTE Framed-Route 22 string
|
30
|
+
ATTRIBUTE Framed-IPX-Network 23 ipaddr
|
31
|
+
ATTRIBUTE State 24 octets
|
32
|
+
ATTRIBUTE Class 25 octets
|
33
|
+
ATTRIBUTE Vendor-Specific 26 octets
|
34
|
+
ATTRIBUTE Session-Timeout 27 integer
|
35
|
+
ATTRIBUTE Idle-Timeout 28 integer
|
36
|
+
ATTRIBUTE Termination-Action 29 integer
|
37
|
+
ATTRIBUTE Called-Station-Id 30 string
|
38
|
+
ATTRIBUTE Calling-Station-Id 31 string
|
39
|
+
ATTRIBUTE NAS-Identifier 32 string
|
40
|
+
ATTRIBUTE Proxy-State 33 octets
|
41
|
+
ATTRIBUTE Login-LAT-Service 34 string
|
42
|
+
ATTRIBUTE Login-LAT-Node 35 string
|
43
|
+
ATTRIBUTE Login-LAT-Group 36 octets
|
44
|
+
ATTRIBUTE Framed-AppleTalk-Link 37 integer
|
45
|
+
ATTRIBUTE Framed-AppleTalk-Network 38 integer
|
46
|
+
ATTRIBUTE Framed-AppleTalk-Zone 39 string
|
47
|
+
|
48
|
+
ATTRIBUTE CHAP-Challenge 60 octets
|
49
|
+
ATTRIBUTE NAS-Port-Type 61 integer
|
50
|
+
ATTRIBUTE Port-Limit 62 integer
|
51
|
+
ATTRIBUTE Login-LAT-Port 63 string
|
52
|
+
|
53
|
+
#
|
54
|
+
# Integer Translations
|
55
|
+
#
|
56
|
+
|
57
|
+
# Service types
|
58
|
+
|
59
|
+
VALUE Service-Type Login-User 1
|
60
|
+
VALUE Service-Type Framed-User 2
|
61
|
+
VALUE Service-Type Callback-Login-User 3
|
62
|
+
VALUE Service-Type Callback-Framed-User 4
|
63
|
+
VALUE Service-Type Outbound-User 5
|
64
|
+
VALUE Service-Type Administrative-User 6
|
65
|
+
VALUE Service-Type NAS-Prompt-User 7
|
66
|
+
VALUE Service-Type Authenticate-Only 8
|
67
|
+
VALUE Service-Type Callback-NAS-Prompt 9
|
68
|
+
VALUE Service-Type Call-Check 10
|
69
|
+
VALUE Service-Type Callback-Administrative 11
|
70
|
+
|
71
|
+
# Framed Protocols
|
72
|
+
|
73
|
+
VALUE Framed-Protocol PPP 1
|
74
|
+
VALUE Framed-Protocol SLIP 2
|
75
|
+
VALUE Framed-Protocol ARAP 3
|
76
|
+
VALUE Framed-Protocol Gandalf-SLML 4
|
77
|
+
VALUE Framed-Protocol Xylogics-IPX-SLIP 5
|
78
|
+
VALUE Framed-Protocol X.75-Synchronous 6
|
79
|
+
|
80
|
+
# Framed Routing Values
|
81
|
+
|
82
|
+
VALUE Framed-Routing None 0
|
83
|
+
VALUE Framed-Routing Broadcast 1
|
84
|
+
VALUE Framed-Routing Listen 2
|
85
|
+
VALUE Framed-Routing Broadcast-Listen 3
|
86
|
+
|
87
|
+
# Framed Compression Types
|
88
|
+
|
89
|
+
VALUE Framed-Compression None 0
|
90
|
+
VALUE Framed-Compression Van-Jacobson-TCP-IP 1
|
91
|
+
VALUE Framed-Compression IPX-Header-Compression 2
|
92
|
+
VALUE Framed-Compression Stac-LZS 3
|
93
|
+
|
94
|
+
# Login Services
|
95
|
+
|
96
|
+
VALUE Login-Service Telnet 0
|
97
|
+
VALUE Login-Service Rlogin 1
|
98
|
+
VALUE Login-Service TCP-Clear 2
|
99
|
+
VALUE Login-Service PortMaster 3
|
100
|
+
VALUE Login-Service LAT 4
|
101
|
+
VALUE Login-Service X25-PAD 5
|
102
|
+
VALUE Login-Service X25-T3POS 6
|
103
|
+
VALUE Login-Service TCP-Clear-Quiet 8
|
104
|
+
|
105
|
+
# Login-TCP-Port (see /etc/services for more examples)
|
106
|
+
|
107
|
+
VALUE Login-TCP-Port Telnet 23
|
108
|
+
VALUE Login-TCP-Port Rlogin 513
|
109
|
+
VALUE Login-TCP-Port Rsh 514
|
110
|
+
|
111
|
+
# Termination Options
|
112
|
+
|
113
|
+
VALUE Termination-Action Default 0
|
114
|
+
VALUE Termination-Action RADIUS-Request 1
|
115
|
+
|
116
|
+
# NAS Port Types
|
117
|
+
|
118
|
+
VALUE NAS-Port-Type Async 0
|
119
|
+
VALUE NAS-Port-Type Sync 1
|
120
|
+
VALUE NAS-Port-Type ISDN 2
|
121
|
+
VALUE NAS-Port-Type ISDN-V120 3
|
122
|
+
VALUE NAS-Port-Type ISDN-V110 4
|
123
|
+
VALUE NAS-Port-Type Virtual 5
|
124
|
+
VALUE NAS-Port-Type PIAFS 6
|
125
|
+
VALUE NAS-Port-Type HDLC-Clear-Channel 7
|
126
|
+
VALUE NAS-Port-Type X.25 8
|
127
|
+
VALUE NAS-Port-Type X.75 9
|
128
|
+
VALUE NAS-Port-Type G.3-Fax 10
|
129
|
+
VALUE NAS-Port-Type SDSL 11
|
130
|
+
VALUE NAS-Port-Type ADSL-CAP 12
|
131
|
+
VALUE NAS-Port-Type ADSL-DMT 13
|
132
|
+
VALUE NAS-Port-Type IDSL 14
|
133
|
+
VALUE NAS-Port-Type Ethernet 15
|
134
|
+
VALUE NAS-Port-Type xDSL 16
|
135
|
+
VALUE NAS-Port-Type Cable 17
|
136
|
+
VALUE NAS-Port-Type Wireless-Other 18
|
137
|
+
VALUE NAS-Port-Type Wireless-802.11 19
|
data/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: radiustar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 21
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- PJ Davis
|
@@ -14,23 +15,40 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
-
default_executable:
|
18
|
+
date: 2012-02-02 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: ipaddr_extensions
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
24
25
|
requirements:
|
25
26
|
- - ">="
|
26
27
|
- !ruby/object:Gem::Version
|
28
|
+
hash: 16097
|
27
29
|
segments:
|
28
|
-
-
|
29
|
-
- 4
|
30
|
+
- 2012
|
30
31
|
- 1
|
31
|
-
|
32
|
-
|
32
|
+
- 13
|
33
|
+
version: 2012.1.13
|
34
|
+
type: :runtime
|
33
35
|
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: bones
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 29
|
45
|
+
segments:
|
46
|
+
- 3
|
47
|
+
- 7
|
48
|
+
- 3
|
49
|
+
version: 3.7.3
|
50
|
+
type: :development
|
51
|
+
version_requirements: *id002
|
34
52
|
description: Ruby Radius Library
|
35
53
|
email: pj.davis@gmail.com
|
36
54
|
executables: []
|
@@ -41,9 +59,7 @@ extra_rdoc_files:
|
|
41
59
|
- History.txt
|
42
60
|
- README.rdoc
|
43
61
|
- templates/default.txt
|
44
|
-
- version.txt
|
45
62
|
files:
|
46
|
-
- .gitignore
|
47
63
|
- History.txt
|
48
64
|
- README.rdoc
|
49
65
|
- Rakefile
|
@@ -58,12 +74,13 @@ files:
|
|
58
74
|
- radiustar.gemspec
|
59
75
|
- spec/radiustar_spec.rb
|
60
76
|
- spec/spec_helper.rb
|
77
|
+
- spec/value_spec.rb
|
61
78
|
- templates/default.txt
|
62
79
|
- templates/dictionary.digium
|
80
|
+
- templates/dictionary.rfc2865
|
63
81
|
- templates/gandalf.dictionary
|
64
82
|
- test/test_radiustar.rb
|
65
83
|
- version.txt
|
66
|
-
has_rdoc: true
|
67
84
|
homepage: http://github.com/pjdavis/radiustar
|
68
85
|
licenses: []
|
69
86
|
|
@@ -74,25 +91,29 @@ rdoc_options:
|
|
74
91
|
require_paths:
|
75
92
|
- lib
|
76
93
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
77
95
|
requirements:
|
78
96
|
- - ">="
|
79
97
|
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
80
99
|
segments:
|
81
100
|
- 0
|
82
101
|
version: "0"
|
83
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
84
104
|
requirements:
|
85
105
|
- - ">="
|
86
106
|
- !ruby/object:Gem::Version
|
107
|
+
hash: 3
|
87
108
|
segments:
|
88
109
|
- 0
|
89
110
|
version: "0"
|
90
111
|
requirements: []
|
91
112
|
|
92
113
|
rubyforge_project: radiustar
|
93
|
-
rubygems_version: 1.
|
114
|
+
rubygems_version: 1.8.15
|
94
115
|
signing_key:
|
95
116
|
specification_version: 3
|
96
|
-
summary:
|
117
|
+
summary: .
|
97
118
|
test_files:
|
98
119
|
- test/test_radiustar.rb
|