mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 22:58:20 +00:00

- This fixes BIT-1769 by logging all requests even in the absence of a reply. The way that request and replying matching were being handled was restructured to mostly ignore the transaction ids because they aren't that helpful for network monitoring and it makes the script structure more complicated. - Add `framed_addr` field to the radius log to indicate if the radius server is hinting at an address for the client. - Add `ttl` field to indicate how quickly the radius server is replying to the network access server. - Fix a bunch of indentation inconsistencies.
147 lines
4 KiB
Text
147 lines
4 KiB
Text
##! Implements base functionality for RADIUS analysis. Generates the radius.log file.
|
|
|
|
module RADIUS;
|
|
|
|
@load ./consts.bro
|
|
@load base/utils/addrs
|
|
|
|
export {
|
|
redef enum Log::ID += { LOG };
|
|
|
|
type Info: record {
|
|
## Timestamp for when the event happened.
|
|
ts : time &log;
|
|
## Unique ID for the connection.
|
|
uid : string &log;
|
|
## The connection's 4-tuple of endpoint addresses/ports.
|
|
id : conn_id &log;
|
|
## The username, if present.
|
|
username : string &log &optional;
|
|
## MAC address, if present.
|
|
mac : string &log &optional;
|
|
## The address given to the network access server, if
|
|
## present. This is only a hint from the RADIUS server
|
|
## and the network access server is not required to honor
|
|
## the address.
|
|
framed_addr : addr &log &optional;
|
|
## Remote IP address, if present. This is collected
|
|
## from the Tunnel-Client-Endpoint attribute.
|
|
remote_ip : addr &log &optional;
|
|
## Connect info, if present.
|
|
connect_info : string &log &optional;
|
|
## Reply message from the server challenge. This is
|
|
## frequently shown to the user authenticating.
|
|
reply_msg : string &log &optional;
|
|
## Successful or failed authentication.
|
|
result : string &log &optional;
|
|
## The duration between the first request and
|
|
## either the "Access-Accept" message or an error.
|
|
## If the field is empty, it means that either
|
|
## the request or response was not seen.
|
|
ttl : interval &log &optional;
|
|
|
|
## Whether this has already been logged and can be ignored.
|
|
logged : bool &default=F;
|
|
};
|
|
|
|
## Event that can be handled to access the RADIUS record as it is sent on
|
|
## to the logging framework.
|
|
global log_radius: event(rec: Info);
|
|
}
|
|
|
|
redef record connection += {
|
|
radius: Info &optional;
|
|
};
|
|
|
|
const ports = { 1812/udp };
|
|
redef likely_server_ports += { ports };
|
|
|
|
event bro_init() &priority=5
|
|
{
|
|
Log::create_stream(RADIUS::LOG, [$columns=Info, $ev=log_radius, $path="radius"]);
|
|
Analyzer::register_for_ports(Analyzer::ANALYZER_RADIUS, ports);
|
|
}
|
|
|
|
event radius_message(c: connection, result: RADIUS::Message) &priority=5
|
|
{
|
|
if ( ! c?$radius )
|
|
{
|
|
c$radius = Info($ts = network_time(),
|
|
$uid = c$uid,
|
|
$id = c$id);
|
|
}
|
|
|
|
switch ( RADIUS::msg_types[result$code] )
|
|
{
|
|
case "Access-Request":
|
|
if ( result?$attributes )
|
|
{
|
|
# User-Name
|
|
if ( ! c$radius?$username && 1 in result$attributes )
|
|
c$radius$username = result$attributes[1][0];
|
|
|
|
# Calling-Station-Id (we expect this to be a MAC)
|
|
if ( ! c$radius?$mac && 31 in result$attributes )
|
|
c$radius$mac = normalize_mac(result$attributes[31][0]);
|
|
|
|
# Tunnel-Client-EndPoint (useful for VPNs)
|
|
if ( ! c$radius?$remote_ip && 66 in result$attributes )
|
|
c$radius$remote_ip = to_addr(result$attributes[66][0]);
|
|
|
|
# Connect-Info
|
|
if ( ! c$radius?$connect_info && 77 in result$attributes )
|
|
c$radius$connect_info = result$attributes[77][0];
|
|
}
|
|
break;
|
|
|
|
case "Access-Challenge":
|
|
if ( result?$attributes )
|
|
{
|
|
# Framed-IP-Address
|
|
if ( ! c$radius?$framed_addr && 8 in result$attributes )
|
|
c$radius$framed_addr = raw_bytes_to_v4_addr(result$attributes[8][0]);
|
|
|
|
if ( ! c$radius?$reply_msg && 18 in result$attributes )
|
|
c$radius$reply_msg = result$attributes[18][0];
|
|
}
|
|
break;
|
|
|
|
case "Access-Accept":
|
|
c$radius$result = "success";
|
|
break;
|
|
|
|
case "Access-Reject":
|
|
c$radius$result = "failed";
|
|
break;
|
|
|
|
# TODO: Support RADIUS accounting. (add port 1813/udp above too)
|
|
#case "Accounting-Request":
|
|
# break;
|
|
#
|
|
#case "Accounting-Response":
|
|
# break;
|
|
}
|
|
}
|
|
|
|
event radius_message(c: connection, result: RADIUS::Message) &priority=-5
|
|
{
|
|
if ( c$radius?$result )
|
|
{
|
|
local ttl = network_time() - c$radius$ts;
|
|
if ( ttl != 0secs )
|
|
c$radius$ttl = ttl;
|
|
|
|
Log::write(RADIUS::LOG, c$radius);
|
|
|
|
delete c$radius;
|
|
}
|
|
}
|
|
|
|
event connection_state_remove(c: connection) &priority=-5
|
|
{
|
|
if ( c?$radius && ! c$radius$logged )
|
|
{
|
|
c$radius$result = "unknown";
|
|
Log::write(RADIUS::LOG, c$radius);
|
|
}
|
|
}
|