diff options
| author | Denys Fedoryshchenko <denys.f@collabora.com> | 2026-01-24 20:13:41 +0200 |
|---|---|---|
| committer | Denys Fedoryshchenko <denys.f@collabora.com> | 2026-01-24 20:14:44 +0200 |
| commit | 027bff94665e3e9779e34117947f0e0bec1eb8b6 (patch) | |
| tree | 7364fa61e399c926b22cd367fc86093cae8d33c3 | |
| parent | a4c79494f2b8aefecb4d4db25f7c3a7442a4f0fd (diff) | |
| download | accel-ppp-027bff94665e3e9779e34117947f0e0bec1eb8b6.tar.gz accel-ppp-027bff94665e3e9779e34117947f0e0bec1eb8b6.zip | |
radius: Add optional validation of Framed-Route
Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
| -rw-r--r-- | accel-pppd/accel-ppp.conf | 1 | ||||
| -rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 5 | ||||
| -rw-r--r-- | accel-pppd/radius/radius.c | 20 |
3 files changed, 26 insertions, 0 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index a812c547..329c3adc 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -209,6 +209,7 @@ interface=eth0 [radius] #dictionary=/usr/local/share/accel-ppp/radius/dictionary +#framed-route-strict=0 nas-identifier=accel-ppp nas-ip-address=127.0.0.1 gw-ip-address=192.168.100.1 diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5 index 3b56b3cf..cefc74ed 100644 --- a/accel-pppd/accel-ppp.conf.5 +++ b/accel-pppd/accel-ppp.conf.5 @@ -1099,6 +1099,11 @@ If enabled, checks that the NAS-Identifier or NAS-IP-Address in DM/CoA requests If this option is given and .B 1 is specified then radius module will include Message-Authenticator attribute in Access-Request packets. +.TP +.BI "framed-route-strict=" 0|1 +If enabled, only accepts Framed-Route destinations that are valid IPv4 network prefixes +for the specified mask (host bits must be zero). This enforces RFC-style network prefixes. +Default is 0 (disabled). .SH [log] .br Configuration of log and log_file modules. diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index 4710a70f..f32a30ce 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -60,6 +60,7 @@ const char *conf_attr_tunnel_type; int conf_acct_delay_start; int conf_blast_protection; +int conf_framed_route_strict; static LIST_HEAD(sessions); static pthread_rwlock_t sessions_lock = PTHREAD_RWLOCK_INITIALIZER; @@ -108,6 +109,8 @@ static int parse_framed_route_v4(const char *str, struct framed_route *fr) struct in_addr mask_addr; uint8_t plen; uint32_t prio; + uint32_t mask = 0; + uint32_t addr_hbo; // Take a steady breath and skip leading RFC-style spaces so everything starts clean. ptr = str + u_parse_spaces(str); @@ -117,6 +120,7 @@ static int parse_framed_route_v4(const char *str, struct framed_route *fr) // Happy path: CIDR tells us exactly what we need. fr->dst = dst.s_addr; fr->mask = plen; + mask = plen ? (0xffffffffu << (32 - plen)) : 0; ptr += len; } else { // If CIDR didn't show up, we gently switch to plain IPv4 and optional mask. @@ -132,18 +136,29 @@ static int parse_framed_route_v4(const char *str, struct framed_route *fr) if (len) { if (ipv4_mask_to_prefix(mask_addr, &fr->mask)) return -1; + mask = ntohl(mask_addr.s_addr); ptr += len; } else { len = u_parse_u8(ptr, &plen); if (!len || plen > 32) return -1; fr->mask = plen; + mask = plen ? (0xffffffffu << (32 - plen)) : 0; ptr += len; } } else fr->mask = 32; } + if (!mask) + mask = fr->mask ? (0xffffffffu << (32 - fr->mask)) : 0; + + if (conf_framed_route_strict) { + addr_hbo = ntohl(fr->dst); + if (addr_hbo & ~mask) + return -1; + } + // If the string ends here, we can relax: no gateway or metric specified. ptr += u_parse_spaces(ptr); if (u_parse_endstr(ptr)) { @@ -1326,6 +1341,11 @@ dae_allow_unlock: } else { conf_blast_protection = 0; } + opt = conf_get_opt("radius", "framed-route-strict"); + if (opt && atoi(opt) > 0) + conf_framed_route_strict = 1; + else + conf_framed_route_strict = 0; return 0; } |
