Retrieve connection speed from RADIUS

Hijack Roaring Penguin's RADIUS attributes for that purpose:
* RP-Upstream-Speed-Limit → rx_per_sec
* RP-Downstream-Speed-Limit → tx_per_sec

While the ocserv configuration options use b/s, ocserv uses kb/s
internally. The radius attributes are already expressed in kb/s,
so we don't need to convert them.

Signed-off-by: Dimitri Papadopoulos <3350651-DimitriPapadopoulos@users.noreply.gitlab.com>
This commit is contained in:
Dimitri Papadopoulos 2023-12-05 23:58:48 +01:00 committed by Nikos Mavrogiannopoulos
parent df657e2772
commit ab58d9e9d7
8 changed files with 80 additions and 6 deletions

1
NEWS
View File

@ -1,4 +1,5 @@
* Version 1.2.4 (unreleased)
- Get connection speed limits (traffic shaping) from RADIUS (#554)
- Use "OpenConnect VPN server" as the long package name. Keep "ocserv" as a
short name.
- usage: open issues on GitLab to report bugs.

View File

@ -141,4 +141,21 @@ ATTRIBUTE DNS-Server-IPv6-Address 169 ipv6addr
# Sets IPv6 routes
ATTRIBUTE Framed-IPv6-Prefix 97 ipv6prefix
ATTRIBUTE Route-IPv6-Information 170 ipv6prefix
############################
# Traffic shaping #
############################
VENDOR Roaring-Penguin 10055
BEGIN-VENDOR Roaring-Penguin
# tx speed limit in kb/s
ATTRIBUTE RP-Upstream-Speed-Limit 1 integer
# rx speed limit in kb/s
ATTRIBUTE RP-Downstream-Speed-Limit 2 integer
END-VENDOR Roaring-Penguin
```

View File

@ -41,9 +41,22 @@
# include <radcli/radcli.h>
#endif
#ifndef VENDOR_BIT_SIZE
# define VENDOR_BIT_SIZE 16
# define VENDOR_MASK 0xffff
#else
# define VENDOR_MASK 0xffffffff
#endif
#define VATTRID_SET(a,v) ((a)|((uint64_t)((v)&VENDOR_MASK)) << VENDOR_BIT_SIZE)
#define RAD_GROUP_NAME PW_CLASS
#define RAD_MS_PRIMARY_DNS_SERVER ((311<<16)|(28)) /* RFC 2548 */
#define RAD_MS_SECONDARY_DNS_SERVER ((311<<16)|(29)) /* RFC 2548 */
/* Microsoft - RFC 2548 */
#define MS_PRIMARY_DNS_SERVER VATTRID_SET(28, 311)
#define MS_SECONDARY_DNS_SERVER VATTRID_SET(29, 311)
/* Roaring Penguin */
#define RP_UPSTREAM_SPEED_LIMIT VATTRID_SET(1, 10055)
#define RP_DOWNSTREAM_SPEED_LIMIT VATTRID_SET(2, 10055)
#if defined(LEGACY_RADIUS)
# ifndef PW_DELEGATED_IPV6_PREFIX
@ -431,11 +444,11 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
/* Framed-IP-Netmask */
ipv4 = htonl(vp->lvalue);
inet_ntop(AF_INET, &ipv4, pctx->ipv4_mask, sizeof(pctx->ipv4_mask));
} else if (vp->attribute == RAD_MS_PRIMARY_DNS_SERVER && vp->type == PW_TYPE_IPADDR) {
} else if (vp->attribute == MS_PRIMARY_DNS_SERVER && vp->type == PW_TYPE_IPADDR) {
/* MS-Primary-DNS-Server */
ipv4 = htonl(vp->lvalue);
inet_ntop(AF_INET, &ipv4, pctx->ipv4_dns1, sizeof(pctx->ipv4_dns1));
} else if (vp->attribute == RAD_MS_SECONDARY_DNS_SERVER && vp->type == PW_TYPE_IPADDR) {
} else if (vp->attribute == MS_SECONDARY_DNS_SERVER && vp->type == PW_TYPE_IPADDR) {
/* MS-Secondary-DNS-Server */
ipv4 = htonl(vp->lvalue);
inet_ntop(AF_INET, &ipv4, pctx->ipv4_dns2, sizeof(pctx->ipv4_dns2));
@ -449,8 +462,13 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
pctx->interim_interval_secs = vp->lvalue;
} else if (vp->attribute == PW_SESSION_TIMEOUT && vp->type == PW_TYPE_INTEGER) {
pctx->session_timeout_secs = vp->lvalue;
} else if (vp->attribute == RP_UPSTREAM_SPEED_LIMIT && vp->type == PW_TYPE_INTEGER) {
pctx->rx_per_sec = vp->lvalue;
} else if (vp->attribute == RP_DOWNSTREAM_SPEED_LIMIT && vp->type == PW_TYPE_INTEGER) {
pctx->tx_per_sec = vp->lvalue;
} else {
oc_syslog(LOG_DEBUG, "radius-auth: ignoring server's value %u of type %u", (int)vp->attribute, (int)vp->type);
oc_syslog(LOG_DEBUG, "radius-auth: ignoring server's attribute (%u,%u) of type %u",
(unsigned)ATTRID(vp->attribute), (unsigned)VENDOR(vp->attribute), (unsigned)vp->type);
}
vp = vp->next;
}

View File

@ -61,6 +61,9 @@ struct radius_ctx_st {
char ipv6_dns1[MAX_IP_STR];
char ipv6_dns2[MAX_IP_STR];
uint32_t rx_per_sec;
uint32_t tx_per_sec;
char **routes;
unsigned routes_size;

View File

@ -120,6 +120,15 @@ static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry,
msg->config->has_ipv6_subnet_prefix = 1;
}
if (pctx->rx_per_sec) {
msg->config->has_rx_per_sec = 1;
msg->config->rx_per_sec = pctx->rx_per_sec;
}
if (pctx->tx_per_sec) {
msg->config->has_tx_per_sec = 1;
msg->config->tx_per_sec = pctx->tx_per_sec;
}
return 0;
}

View File

@ -132,7 +132,9 @@ testtime Cleartext-Password := "test"
Framed-IP-Netmask = 255.255.255.0,
Framed-MTU = 1500,
Session-Timeout = 60,
Acct-Interim-Interval = 20
Acct-Interim-Interval = 20,
RP-Upstream-Speed-Limit = 16,
RP-Downstream-Speed-Limit = 64
test1-otp Cleartext-Password := "test1-otp-stage%{string:State}", Tmp-Integer-0 := 3
Service-Type = Framed-User,

View File

@ -282,3 +282,12 @@ ATTRIBUTE MS-Primary-DNS-Server 28 ipaddr
ATTRIBUTE MS-Secondary-DNS-Server 29 ipaddr
END-VENDOR Microsoft
VENDOR Roaring-Penguin 10055
BEGIN-VENDOR Roaring-Penguin
ATTRIBUTE RP-Upstream-Speed-Limit 1 integer
ATTRIBUTE RP-Downstream-Speed-Limit 2 integer
END-VENDOR Roaring-Penguin

View File

@ -161,6 +161,21 @@ if test $? != 0;then
exit 1
fi
grep "Limit RX: 16" ${OUTFILE}
if test $? != 0;then
${OCCTL} -s ${OCCTL_SOCKET} show user ${USERNAME}
echo "occtl show user didn't find upstream speed limit!"
exit 1
fi
grep "Limit TX: 64" ${OUTFILE}
if test $? != 0;then
${OCCTL} -s ${OCCTL_SOCKET} show user ${USERNAME}
echo "occtl show user didn't find downstream speed limit!"
exit 1
fi
echo "Waiting for accounting report"
wait_file_contents ${RADIUSLOG} "Acct-Input-Octets = [1-9]+" 35