bettercap 1.6.1 → 1.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -34
  3. data/bin/bettercap +1 -1
  4. data/lib/bettercap/context.rb +1 -1
  5. data/lib/bettercap/discovery/agents/mdns.rb +61 -0
  6. data/lib/bettercap/discovery/agents/upnp.rb +60 -0
  7. data/lib/bettercap/discovery/agents/wsd.rb +75 -0
  8. data/lib/bettercap/firewalls/linux.rb +0 -4
  9. data/lib/bettercap/logger.rb +63 -34
  10. data/lib/bettercap/network/network.rb +1 -1
  11. data/lib/bettercap/options/core_options.rb +1 -1
  12. data/lib/bettercap/proxy/http/modules/redirect.rb +1 -1
  13. data/lib/bettercap/proxy/http/proxy.rb +1 -9
  14. data/lib/bettercap/proxy/http/sslstrip/strip.rb +5 -5
  15. data/lib/bettercap/sniffer/parsers/asterisk.rb +37 -0
  16. data/lib/bettercap/sniffer/parsers/bfd.rb +159 -0
  17. data/lib/bettercap/sniffer/parsers/dhcp.rb +23 -23
  18. data/lib/bettercap/sniffer/parsers/dict.rb +13 -11
  19. data/lib/bettercap/sniffer/parsers/hsrp.rb +262 -0
  20. data/lib/bettercap/sniffer/parsers/https.rb +17 -19
  21. data/lib/bettercap/sniffer/parsers/mpd.rb +12 -10
  22. data/lib/bettercap/sniffer/parsers/nntp.rb +5 -1
  23. data/lib/bettercap/sniffer/parsers/post.rb +8 -9
  24. data/lib/bettercap/sniffer/parsers/radius.rb +410 -0
  25. data/lib/bettercap/sniffer/parsers/redis.rb +15 -13
  26. data/lib/bettercap/sniffer/parsers/rlogin.rb +20 -19
  27. data/lib/bettercap/sniffer/parsers/snmp.rb +16 -17
  28. data/lib/bettercap/sniffer/parsers/snpp.rb +13 -11
  29. data/lib/bettercap/sniffer/parsers/teamtalk.rb +41 -0
  30. data/lib/bettercap/sniffer/parsers/teamviewer.rb +8 -8
  31. data/lib/bettercap/sniffer/parsers/url.rb +6 -6
  32. data/lib/bettercap/sniffer/parsers/whatsapp.rb +6 -7
  33. data/lib/bettercap/sniffer/parsers/wol.rb +68 -0
  34. data/lib/bettercap/spoofers/arp.rb +3 -3
  35. data/lib/bettercap/spoofers/hsrp.rb +351 -0
  36. data/lib/bettercap/spoofers/mac.rb +126 -0
  37. data/lib/bettercap/version.rb +1 -1
  38. metadata +13 -2
@@ -19,27 +19,25 @@ class Https < Base
19
19
  @@lock = Mutex.new
20
20
 
21
21
  def on_packet( pkt )
22
- begin
23
- # poor man's TLS Client Hello with SNI extension parser :P
24
- if pkt.respond_to?(:tcp_dst) and \
25
- pkt.payload[0] == "\x16" and \
26
- pkt.payload[1] == "\x03" and \
27
- pkt.payload =~ /\x00\x00.{4}\x00.{2}([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6})\x00/
28
- hostname = $1
29
- if pkt.tcp_dst != 443
30
- hostname += ":#{pkt.tcp_dst}"
31
- end
32
-
33
- @@lock.synchronize {
34
- if @@prev.nil? or @@prev != hostname
35
- StreamLogger.log_raw( pkt, 'HTTPS', "https://#{hostname}/" )
36
- @@prev = hostname
37
- end
38
- }
22
+ # poor man's TLS Client Hello with SNI extension parser :P
23
+ if pkt.respond_to?(:tcp_dst) and \
24
+ pkt.payload[0] == "\x16" and \
25
+ pkt.payload[1] == "\x03" and \
26
+ pkt.payload =~ /\x00\x00.{4}\x00.{2}([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6})\x00/
27
+ hostname = $1
28
+ if pkt.tcp_dst != 443
29
+ hostname += ":#{pkt.tcp_dst}"
39
30
  end
40
- rescue; end
41
- end
42
31
 
32
+ @@lock.synchronize {
33
+ if @@prev.nil? or @@prev != hostname
34
+ StreamLogger.log_raw( pkt, 'HTTPS', "https://#{hostname}/" )
35
+ @@prev = hostname
36
+ end
37
+ }
38
+ end
39
+ rescue
40
+ end
43
41
  end
44
42
  end
45
43
  end
@@ -6,6 +6,10 @@ Author : Simone 'evilsocket' Margaritelli
6
6
  Email : evilsocket@gmail.com
7
7
  Blog : https://www.evilsocket.net/
8
8
 
9
+ Music Player Daemon (MPD) authentication parser:
10
+ Author : Brendan Coles
11
+ Email : bcoles[at]gmail.com
12
+
9
13
  This project is released under the GPL 3 license.
10
14
 
11
15
  =end
@@ -18,18 +22,16 @@ class Mpd < Base
18
22
  @name = 'MPD'
19
23
  end
20
24
  def on_packet( pkt )
21
- begin
22
- if pkt.tcp_dst == 6600
23
- lines = pkt.to_s.split(/\r?\n/)
24
- lines.each do |line|
25
- if line =~ /password\s+(.+)$/
26
- pass = $1
27
- StreamLogger.log_raw( pkt, @name, "password=#{pass}" )
28
- end
29
- end
25
+ return unless pkt.tcp_dst == 6600
26
+
27
+ lines = pkt.to_s.split(/\r?\n/)
28
+ lines.each do |line|
29
+ if line =~ /password\s+(.+)$/
30
+ pass = $1
31
+ StreamLogger.log_raw( pkt, @name, "password=#{pass}" )
30
32
  end
31
- rescue
32
33
  end
34
+ rescue
33
35
  end
34
36
  end
35
37
  end
@@ -5,7 +5,11 @@ BETTERCAP
5
5
 
6
6
  Author : Simone 'evilsocket' Margaritelli
7
7
  Email : evilsocket@gmail.com
8
- Blog : http://www.evilsocket.net/
8
+ Blog : https://www.evilsocket.net/
9
+
10
+ NNTP authentication parser:
11
+ Author : Brendan Coles
12
+ Email : bcoles[at]gmail.com
9
13
 
10
14
  This project is released under the GPL 3 license.
11
15
 
@@ -17,16 +17,15 @@ module Parsers
17
17
  class Post < Base
18
18
  def on_packet( pkt )
19
19
  s = pkt.to_s
20
- if s =~ /POST\s+[^\s]+\s+HTTP.+/
21
- begin
22
- req = BetterCap::Proxy::HTTP::Request.parse(pkt.payload)
23
- # the packet could be incomplete
24
- unless req.body.nil? or req.body.empty?
25
- StreamLogger.log_raw( pkt, "POST", req.to_url(1000) )
26
- StreamLogger.log_post( req )
27
- end
28
- rescue; end
20
+ return unless s =~ /POST\s+[^\s]+\s+HTTP.+/
21
+
22
+ req = BetterCap::Proxy::HTTP::Request.parse(pkt.payload)
23
+ # the packet could be incomplete
24
+ unless req.body.nil? or req.body.empty?
25
+ StreamLogger.log_raw( pkt, "POST", req.to_url(1000) )
26
+ StreamLogger.log_post( req )
29
27
  end
28
+ rescue
30
29
  end
31
30
  end
32
31
  end
@@ -0,0 +1,410 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ BETTERCAP
5
+
6
+ Author : Simone 'evilsocket' Margaritelli
7
+ Email : evilsocket@gmail.com
8
+ Blog : https://www.evilsocket.net/
9
+
10
+ RADIUS packet and authentication parser:
11
+ Author : Brendan Coles
12
+ Email : bcoles[at]gmail.com
13
+
14
+ This project is released under the GPL 3 license.
15
+
16
+ =end
17
+
18
+ module BetterCap
19
+ module Parsers
20
+ #
21
+ # RADIUS packet and authentication parser.
22
+ #
23
+ # Supports RADIUS authentication messages over UDP (ports 1812/udp and 1645/udp)
24
+ # Does not support RADIUS over TCP
25
+ # Does not support RADIUS accounting messages (ports 1813/udp and 1646/udp)
26
+ #
27
+ # References:
28
+ # - https://en.wikipedia.org/wiki/RADIUS
29
+ # - https://tools.ietf.org/html/rfc2865#section-3
30
+ # - https://tools.ietf.org/html/rfc2869
31
+ # - https://www.iana.org/assignments/radius-types/radius-types.xhtml
32
+ # - https://technet.microsoft.com/en-us/library/cc958030.aspx
33
+ # - http://www.untruth.org/~josh/security/radius/radius-auth.html
34
+ #
35
+ class Radius < Base
36
+ def initialize
37
+ @name = 'RADIUS'
38
+ end
39
+
40
+ def on_packet( pkt )
41
+ return unless is_radius? pkt
42
+
43
+ log = []
44
+ data = pkt.payload.to_s.unpack('H*').first
45
+
46
+ =begin
47
+
48
+ Packet format from RFC2865, section 3:
49
+
50
+ 0 1 2 3
51
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
52
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53
+ | Code | Identifier | Length |
54
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55
+ | |
56
+ | Authenticator |
57
+ | |
58
+ | |
59
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60
+ | Attributes ...
61
+ +-+-+-+-+-+-+-+-+-+-+-+-+-
62
+
63
+ =end
64
+
65
+ # data[0...2] # RADIUS Codes (decimal):
66
+ # 1 Access-Request
67
+ # 2 Access-Accept
68
+ # 3 Access-Reject
69
+ # 4 Accounting-Request
70
+ # 5 Accounting-Response
71
+ # 11 Access-Challenge
72
+ # 12 Status-Server (experimental)
73
+ # 13 Status-Client (experimental)
74
+ # 255 Reserved
75
+
76
+ code = data[0...2].to_i(16)
77
+
78
+ # We're only interested in Access requests and responses
79
+ case code
80
+ when 1
81
+ type = 'request'
82
+ when 2
83
+ type = 'accept'
84
+ when 3
85
+ type = 'reject'
86
+ when 11
87
+ type = 'challenge'
88
+ else
89
+ return
90
+ end
91
+
92
+ log << "access-#{type}".yellow
93
+ log << "#{'Code'.blue}=#{code}"
94
+
95
+ # data[2...4] # Identifier
96
+ id = data[2...4].to_i(16)
97
+ log << "#{'ID'.blue}=#{id}"
98
+
99
+ # data[4...8] # Length
100
+ length = data[4...8].to_i(16)
101
+
102
+ # data[4...36] # Request/Response Authenticator
103
+ authenticator = data[8...40]
104
+ log << "#{'Authenticator'.blue}=#{authenticator}"
105
+
106
+
107
+ =begin
108
+
109
+ RADIUS attribute format from RFC2865, section 5:
110
+
111
+ 0 1 2
112
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
113
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
114
+ | Type | Length | Value ...
115
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
116
+
117
+ =end
118
+
119
+ # Attribute type label lookup table
120
+ # https://www.iana.org/assignments/radius-types/radius-types.xhtml
121
+ attribute_types = [
122
+ [1, 'User-Name'],
123
+ [2, 'User-Password'],
124
+ [3, 'CHAP-Password'],
125
+ [4, 'NAS-IP-Address'],
126
+ [5, 'NAS-Port'],
127
+ [6, 'Service-Type'],
128
+ [7, 'Framed-Protocol'],
129
+ [8, 'Framed-IP-Address'],
130
+ [9, 'Framed-IP-Netmask'],
131
+ [10, 'Framed-Routing'],
132
+ [11, 'Filter-Id'],
133
+ [12, 'Framed-MTU'],
134
+ [13, 'Framed-Compression'],
135
+ [14, 'Login-IP-Host'],
136
+ [15, 'Login-Service'],
137
+ [16, 'Login-TCP-Port'],
138
+ [17, 'Unassigned'],
139
+ [18, 'Reply-Message'],
140
+ [19, 'Callback-Number'],
141
+ [20, 'Callback-Id'],
142
+ #[21, 'Unassigned'],
143
+ [22, 'Framed-Route'],
144
+ [23, 'Framed-IPX-Network'],
145
+ [24, 'State'],
146
+ [25, 'Class'],
147
+ [26, 'Vendor-Specific'],
148
+ [27, 'Session-Timeout'],
149
+ [28, 'Idle-Timeout'],
150
+ [29, 'Termination-Action'],
151
+ [30, 'Called-Station-Id'],
152
+ [31, 'Calling-Station-Id'],
153
+ [32, 'NAS-Identifier'],
154
+ [33, 'Proxy-State'],
155
+ [34, 'Login-LAT-Service'],
156
+ [35, 'Login-LAT-Node'],
157
+ [36, 'Login-LAT-Group'],
158
+ [37, 'Framed-AppleTalk-Link'],
159
+ [38, 'Framed-AppleTalk-Network'],
160
+ [39, 'Framed-AppleTalk-Zone'],
161
+ [40, 'Acct-Status-Type'],
162
+ [41, 'Acct-Delay-Time'],
163
+ [42, 'Acct-Input-Octets'],
164
+ [43, 'Acct-Output-Octets'],
165
+ [44, 'Acct-Session-Id'],
166
+ [45, 'Acct-Authentic'],
167
+ [46, 'Acct-Session-Time'],
168
+ [47, 'Acct-Input-Packets'],
169
+ [48, 'Acct-Output-Packets'],
170
+ [49, 'Acct-Terminate-Cause'],
171
+ [50, 'Acct-Multi-Session-Id'],
172
+ [51, 'Acct-Link-Count'],
173
+ [52, 'Acct-Input-Gigawords'],
174
+ [53, 'Acct-Output-Gigawords'],
175
+ #[54, 'Unassigned'],
176
+ [55, 'Event-Timestamp'],
177
+ [56, 'Egress-VLANID'],
178
+ [57, 'Ingress-Filters'],
179
+ [58, 'Egress-VLAN-Name'],
180
+ [59, 'User-Priority-Table'],
181
+ [60, 'CHAP-Challenge'],
182
+ [61, 'NAS-Port-Type'],
183
+ [62, 'Port-Limit'],
184
+ [63, 'Login-LAT-Port'],
185
+ [64, 'Tunnel-Type'],
186
+ [65, 'Tunnel-Medium-Type'],
187
+ [66, 'Tunnel-Client-Endpoint'],
188
+ [67, 'Tunnel-Server-Endpoint'],
189
+ [68, 'Acct-Tunnel-Connection'],
190
+ [69, 'Tunnel-Password'],
191
+ [70, 'ARAP-Password'],
192
+ [71, 'ARAP-Features'],
193
+ [72, 'ARAP-Zone-Access'],
194
+ [73, 'ARAP-Security'],
195
+ [74, 'ARAP-Security-Data'],
196
+ [75, 'Password-Retry'],
197
+ [76, 'Prompt'],
198
+ [77, 'Connect-Info'],
199
+ [78, 'Configuration-Token'],
200
+ [79, 'EAP-Message'],
201
+ [80, 'Message-Authenticator'],
202
+ [81, 'Tunnel-Private-Group-ID'],
203
+ [82, 'Tunnel-Assignment-ID'],
204
+ [83, 'Tunnel-Preference'],
205
+ [84, 'ARAP-Challenge-Response'],
206
+ [85, 'Acct-Interim-Interval'],
207
+ [86, 'Acct-Tunnel-Packets-Lost'],
208
+ [87, 'NAS-Port-Id'],
209
+ [88, 'Framed-Pool'],
210
+ [89, 'CUI'],
211
+ [90, 'Tunnel-Client-Auth-ID'],
212
+ [91, 'Tunnel-Server-Auth-ID'],
213
+ [92, 'NAS-Filter-Rule'],
214
+ #[93, 'Unassigned'],
215
+ [94, 'Originating-Line-Info'],
216
+ [95, 'NAS-IPv6-Address'],
217
+ [96, 'Framed-Interface-Id'],
218
+ [97, 'Framed-IPv6-Prefix'],
219
+ [98, 'Login-IPv6-Host'],
220
+ [99, 'Framed-IPv6-Route'],
221
+ [100, 'Framed-IPv6-Pool'],
222
+ [101, 'Error-Cause Attribute'],
223
+ [102, 'EAP-Key-Name'],
224
+ [103, 'Digest-Response'],
225
+ [104, 'Digest-Realm'],
226
+ [105, 'Digest-Nonce'],
227
+ [106, 'Digest-Response-Auth'],
228
+ [107, 'Digest-Nextnonce'],
229
+ [108, 'Digest-Method'],
230
+ [109, 'Digest-URI'],
231
+ [110, 'Digest-Qop'],
232
+ [111, 'Digest-Algorithm'],
233
+ [112, 'Digest-Entity-Body-Hash'],
234
+ [113, 'Digest-CNonce'],
235
+ [114, 'Digest-Nonce-Count'],
236
+ [115, 'Digest-Username'],
237
+ [116, 'Digest-Opaque'],
238
+ [117, 'Digest-Auth-Param'],
239
+ [118, 'Digest-AKA-Auts'],
240
+ [119, 'Digest-Domain'],
241
+ [120, 'Digest-Stale'],
242
+ [121, 'Digest-HA1'],
243
+ [122, 'SIP-AOR'],
244
+ [123, 'Delegated-IPv6-Prefix'],
245
+ [124, 'MIP6-Feature-Vector'],
246
+ [125, 'MIP6-Home-Link-Prefix'],
247
+ [126, 'Operator-Name'],
248
+ [127, 'Location-Information'],
249
+ [128, 'Location-Data'],
250
+ [129, 'Basic-Location-Policy-Rules'],
251
+ [130, 'Extended-Location-Policy-Rules'],
252
+ [131, 'Location-Capable'],
253
+ [132, 'Requested-Location-Info'],
254
+ [133, 'Framed-Management-Protocol'],
255
+ [134, 'Management-Transport-Protection'],
256
+ [135, 'Management-Policy-Id'],
257
+ [136, 'Management-Privilege-Level'],
258
+ [137, 'PKM-SS-Cert'],
259
+ [138, 'PKM-CA-Cert'],
260
+ [139, 'PKM-Config-Settings'],
261
+ [140, 'PKM-Cryptosuite-List'],
262
+ [141, 'PKM-SAID'],
263
+ [142, 'PKM-SA-Descriptor'],
264
+ [143, 'PKM-Auth-Key'],
265
+ [144, 'DS-Lite-Tunnel-Name'],
266
+ [145, 'Mobile-Node-Identifier'],
267
+ [146, 'Service-Selection'],
268
+ [147, 'PMIP6-Home-LMA-IPv6-Address'],
269
+ [148, 'PMIP6-Visited-LMA-IPv6-Address'],
270
+ [149, 'PMIP6-Home-LMA-IPv4-Address'],
271
+ [150, 'PMIP6-Visited-LMA-IPv4-Address'],
272
+ [151, 'PMIP6-Home-HN-Prefix'],
273
+ [152, 'PMIP6-Visited-HN-Prefix'],
274
+ [153, 'PMIP6-Home-Interface-ID'],
275
+ [154, 'PMIP6-Visited-Interface-ID'],
276
+ [155, 'PMIP6-Home-IPv4-HoA'],
277
+ [156, 'PMIP6-Visited-IPv4-HoA'],
278
+ [157, 'PMIP6-Home-DHCP4-Server-Address'],
279
+ [158, 'PMIP6-Visited-DHCP4-Server-Address'],
280
+ [159, 'PMIP6-Home-DHCP6-Server-Address'],
281
+ [160, 'PMIP6-Visited-DHCP6-Server-Address'],
282
+ [161, 'PMIP6-Home-IPv4-Gateway'],
283
+ [162, 'PMIP6-Visited-IPv4-Gateway'],
284
+ [163, 'EAP-Lower-Layer'],
285
+ [164, 'GSS-Acceptor-Service-Name'],
286
+ [165, 'GSS-Acceptor-Host-Name'],
287
+ [166, 'GSS-Acceptor-Service-Specifics'],
288
+ [167, 'GSS-Acceptor-Realm-Name'],
289
+ [168, 'Framed-IPv6-Address'],
290
+ [169, 'DNS-Server-IPv6-Address'],
291
+ [170, 'Route-IPv6-Information'],
292
+ [171, 'Delegated-IPv6-Prefix-Pool'],
293
+ [172, 'Stateful-IPv6-Address-Pool'],
294
+ [173, 'IPv6-6rd-Configuration'],
295
+ [174, 'Allowed-Called-Station-Id'],
296
+ [175, 'EAP-Peer-Id'],
297
+ [176, 'EAP-Server-Id'],
298
+ [177, 'Mobility-Domain-Id'],
299
+ [178, 'Preauth-Timeout'],
300
+ [179, 'Network-Id-Name'],
301
+ [180, 'EAPoL-Announcement'],
302
+ [181, 'WLAN-HESSID'],
303
+ [182, 'WLAN-Venue-Info'],
304
+ [183, 'WLAN-Venue-Language'],
305
+ [184, 'WLAN-Venue-Name'],
306
+ [185, 'WLAN-Reason-Code'],
307
+ [186, 'WLAN-Pairwise-Cipher'],
308
+ [187, 'WLAN-Group-Cipher'],
309
+ [188, 'WLAN-AKM-Suite'],
310
+ [189, 'WLAN-Group-Mgmt-Cipher'],
311
+ [190, 'WLAN-RF-Band'],
312
+ #[191, 'Unassigned'],
313
+ #[192-223, 'Experimental Use'],
314
+ #[224-240, 'Implementation Specific'],
315
+ #[241, 'Extended-Attribute-1'],
316
+ #[241.1, 'Frag-Status'],
317
+ #[241.2, 'Proxy-State-Length'],
318
+ #[241.3, 'Response-Length'],
319
+ #[241.4, 'Original-Packet-Code'],
320
+ #[241.5, 'IP-Port-Limit-Info'],
321
+ #[241.6, 'IP-Port-Range'],
322
+ #[241.7, 'IP-Port-Forwarding-Map'],
323
+ #[241.{8-25}, 'Unassigned'],
324
+ #[241.26, 'Extended-Vendor-Specific-1'],
325
+ #[241.{27-240}, 'Unassigned'],
326
+ #[241.{241-255}, 'Reserved'],
327
+ #[242, 'Extended-Attribute-2'],
328
+ #[242.{1-25}, 'Unassigned'],
329
+ #[242.26, 'Extended-Vendor-Specific-2'],
330
+ #[242.{27-240}, 'Unassigned'],
331
+ #[242.{241-255}, 'Reserved'],
332
+ #[243, 'Extended-Attribute-3'],
333
+ #[243.{1-25}, 'Unassigned'],
334
+ #[243.26, 'Extended-Vendor-Specific-3'],
335
+ #[243.{27-240}, 'Unassigned'],
336
+ #[243.{241-255}, 'Reserved'],
337
+ #[244, 'Extended-Attribute-4'],
338
+ #[244.{1-25}, 'Unassigned'],
339
+ #[244.26, 'Extended-Vendor-Specific-4'],
340
+ #[244.{27-240}, 'Unassigned'],
341
+ #[244.{241-255}, 'Reserved'],
342
+ #[245, 'Extended-Attribute-5'],
343
+ #[245.1, 'SAML-Assertion'],
344
+ #[245.2, 'SAML-Protocol'],
345
+ #[245.{3-25}, 'Unassigned'],
346
+ #[245.26, 'Extended-Vendor-Specific-5'],
347
+ #[245.{27-240}, 'Unassigned'],
348
+ #[245.{241-255}, 'Reserved'],
349
+ #[246, 'Extended-Attribute-6'],
350
+ #[246.{1-25}, 'Unassigned'],
351
+ #[246.26, 'Extended-Vendor-Specific-6'],
352
+ #[246.{27-240}, 'Unassigned'],
353
+ #[246.{241-255}, 'Reserved'],
354
+ #[247-255, 'Reserved']
355
+ ]
356
+
357
+ # data[40..-1] # RADIUS Attributes
358
+ attributes = data[40..(length * 2)]
359
+
360
+ attributes_hash = []
361
+ start = 0
362
+ while start < attributes.length
363
+ # attributes[0...2] # Attribute type
364
+ att_type = attributes[start...(start + 2)].to_i(16)
365
+
366
+ # attributes[2...4] # Attribute length (including type, length and value fields)
367
+ att_length = attributes[(start + 2)...(start + 4)].to_i(16)
368
+
369
+ # Break if attribute is malformed
370
+ break if att_length == 0
371
+
372
+ # attributes[4...??] # Attribute value
373
+ att_value = attributes[(start + 4)...(start + (att_length * 2))]
374
+
375
+ attributes_hash << [att_type, att_value]
376
+ start = start + (att_length * 2)
377
+ end
378
+
379
+ attributes_hash.each do |type,value|
380
+ # Lookup attribute label
381
+ att_label = attribute_types.select {|id,name| id == type}.flatten[1].to_s
382
+ att_label = "(#{type})" if att_label == ''
383
+
384
+ # Display printable ASCII, where possible
385
+ if [value].pack('H*').to_s =~ /\A[a-zA-Z0-9_\-+\.,"' ]*\z/
386
+ log << "#{att_label.blue}='#{[value].pack('H*').yellow}'"
387
+ # Convert values containing IPv4 addresses to dotted decimal
388
+ elsif value.length == 8 && att_label =~ /IP/
389
+ ip = value.scan(/\w{2}/).map{ |c| c.to_i(16).to_s(10) }.join('.')
390
+ log << "#{att_label.blue}='#{ip.yellow}'"
391
+ else
392
+ log << "#{att_label.blue}=#{value}"
393
+ end
394
+ end
395
+
396
+ StreamLogger.log_raw pkt, @name, log.join(' ')
397
+ rescue
398
+ end
399
+
400
+ private
401
+
402
+ def is_radius?(pkt)
403
+ return ( pkt.respond_to?('udp_src') && pkt.respond_to?('udp_dst') && \
404
+ ( pkt.udp_src == 1812 || pkt.udp_dst == 1812 || \
405
+ pkt.udp_src == 1645 || pkt.udp_dst == 1645 ) && \
406
+ pkt.payload.length >= 20 )
407
+ end
408
+ end
409
+ end
410
+ end