radiustar 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|