From: Arran Cudbard-Bell Date: Sat, 10 Nov 2012 18:49:40 +0000 (+0000) Subject: Allow src ipaddr to be set on a per client basis X-Git-Tag: release_3_0_0_beta1~1577^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4018a1912b3c5f41c17addbe67e42d284fa05a82;p=thirdparty%2Ffreeradius-server.git Allow src ipaddr to be set on a per client basis --- diff --git a/share/dictionary.freeradius.internal b/share/dictionary.freeradius.internal index 11e41a9910f..5f546628ec5 100644 --- a/share/dictionary.freeradius.internal +++ b/share/dictionary.freeradius.internal @@ -178,6 +178,7 @@ ATTRIBUTE Home-Server-Pool 1111 string ATTRIBUTE FreeRADIUS-Client-IP-Address 1120 ipaddr ATTRIBUTE FreeRADIUS-Client-IPv6-Address 1121 ipv6addr + ATTRIBUTE FreeRADIUS-Client-Require-MA 1122 integer VALUE FreeRADIUS-Client-Require-MA no 0 @@ -228,6 +229,11 @@ ATTRIBUTE Cache-Entry-Hits 1142 integer VALUE Cache-Status-Only no 0 VALUE Cache-Status-Only yes 1 +# More dynamic client attributes + +ATTRIBUTE FreeRADIUS-Client-Src-IP-Address 1143 ipaddr +ATTRIBUTE FreeRADIUS-Client-Src-IPv6-Address 1144 ipv6addr + # # Range: 1200-1279 # EAP-SIM (and other EAP type) weirdness. diff --git a/src/include/radius.h b/src/include/radius.h index 47cd17156c4..9fe596e6c73 100644 --- a/src/include/radius.h +++ b/src/include/radius.h @@ -233,6 +233,8 @@ #define PW_MODULE_RETURN_CODE 1108 #define PW_PACKET_ORIGINAL_TIMESTAMP 1109 #define PW_HOME_SERVER_POOL 1111 +#define PW_FREERADIUS_CLIENT_IP_ADDRESS 1120 +#define PW_FREERADIUS_CLIENT_IPV6_ADDRESS 1121 #define PW_RECV_COA_TYPE 1131 #define PW_SEND_COA_TYPE 1132 #define PW_MSCHAP_PASSWORD 1133 @@ -241,6 +243,8 @@ #define PW_CACHE_TTL 1140 #define PW_CACHE_STATUS_ONLY 1141 #define PW_CACHE_ENTRY_HITS 1142 +#define PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS 1143 +#define PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS 1144 /* * Integer Translations diff --git a/src/include/radiusd.h b/src/include/radiusd.h index 4dea3fa636d..b313336251a 100644 --- a/src/include/radiusd.h +++ b/src/include/radiusd.h @@ -74,6 +74,7 @@ typedef struct request_data_t request_data_t; typedef struct radclient { fr_ipaddr_t ipaddr; + fr_ipaddr_t src_ipaddr; int prefix; char *longname; char *secret; diff --git a/src/main/client.c b/src/main/client.c index e9864d547ae..0e08f3b2564 100644 --- a/src/main/client.c +++ b/src/main/client.c @@ -500,6 +500,7 @@ RADCLIENT *client_find_old(const fr_ipaddr_t *ipaddr) static struct in_addr cl_ip4addr; static struct in6_addr cl_ip6addr; +static char *cl_srcipaddr = NULL; #ifdef WITH_TCP static char *hs_proto = NULL; #endif @@ -527,6 +528,9 @@ static const CONF_PARSER client_config[] = { { "netmask", PW_TYPE_INTEGER, offsetof(RADCLIENT, prefix), 0, NULL }, + { "src_ipaddr", PW_TYPE_STRING_PTR, + 0, &cl_srcipaddr, NULL }, + { "require_message_authenticator", PW_TYPE_BOOLEAN, offsetof(RADCLIENT, message_authenticator), 0, "no" }, @@ -601,6 +605,8 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) #ifdef WITH_TCP free(hs_proto); hs_proto = NULL; + free(cl_srcipaddr); + cl_srcipaddr = NULL; #endif return NULL; @@ -721,6 +727,25 @@ static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server) #endif } + /* + * If a src_ipaddr is specified, when we send the return packet + * we will use this address instead of the src from the + * request. + */ + if (cl_srcipaddr) { +#ifdef WITH_UDPFROMTO + if (ip_hton(cl_srcipaddr, c->ipaddr.af, &c->src_ipaddr) < 0) { + cf_log_err(cf_sectiontoitem(cs), "Failed parsing src_ipaddr"); + goto error; + } +#else + DEBUG("WARNING: Server not build with udpfromto, ignoring client src_ipaddr"); +#endif + + free(cl_srcipaddr); + cl_srcipaddr = NULL; + } + if (c->prefix < 0) switch (c->ipaddr.af) { case AF_INET: c->prefix = 32; @@ -970,6 +995,10 @@ static const CONF_PARSER dynamic_config[] = { offsetof(RADCLIENT, ipaddr), 0, NULL }, { "FreeRADIUS-Client-IPv6-Address", PW_TYPE_IPV6ADDR, offsetof(RADCLIENT, ipaddr), 0, NULL }, + { "FreeRADIUS-Client-Src-IP-Address", PW_TYPE_IPADDR, + offsetof(RADCLIENT, src_ipaddr), 0, NULL }, + { "FreeRADIUS-Client-Src-IPv6-Address", PW_TYPE_IPV6ADDR, + offsetof(RADCLIENT, src_ipaddr), 0, NULL }, { "FreeRADIUS-Client-Require-MA", PW_TYPE_BOOLEAN, offsetof(RADCLIENT, message_authenticator), NULL, NULL }, @@ -1055,7 +1084,8 @@ RADCLIENT *client_create(RADCLIENT_LIST *clients, REQUEST *request) memset(c, 0, sizeof(*c)); c->cs = request->client->cs; c->ipaddr.af = AF_UNSPEC; - + c->src_ipaddr.af = AF_UNSPEC; + for (i = 0; dynamic_config[i].name != NULL; i++) { DICT_ATTR *da; VALUE_PAIR *vp; @@ -1087,15 +1117,35 @@ RADCLIENT *client_create(RADCLIENT_LIST *clients, REQUEST *request) switch (dynamic_config[i].type) { case PW_TYPE_IPADDR: - c->ipaddr.af = AF_INET; - c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; - c->prefix = 32; + if (da->type == PW_FREERADIUS_CLIENT_IP_ADDRESS) { + c->ipaddr.af = AF_INET; + c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; + c->prefix = 32; + } else if (da->type == PW_FREERADIUS_CLIENT_SRC_IP_ADDRESS) { +#ifdef WITH_UDPFROMTO + c->src_ipaddr.af = AF_INET; + c->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; +#else + DEBUG("WARNING: Server not build with udpfromto, ignoring FreeRADIUS-Client-Src-IP-Address."); +#endif + } + break; case PW_TYPE_IPV6ADDR: - c->ipaddr.af = AF_INET6; - c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; - c->prefix = 128; + if (da->type == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) { + c->ipaddr.af = AF_INET6; + c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; + c->prefix = 128; + } else if (da->type == PW_FREERADIUS_CLIENT_SRC_IPV6_ADDRESS) { +#ifdef WITH_UDPFROMTO + c->src_ipaddr.af = AF_INET6; + c->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; +#else + DEBUG("WARNING: Server not build with udpfromto, ignoring FreeRADIUS-Client-Src-IPv6-Address."); +#endif + } + break; case PW_TYPE_STRING_PTR: @@ -1147,6 +1197,14 @@ RADCLIENT *client_create(RADCLIENT_LIST *clients, REQUEST *request) if (!client_validate(clients, request->client, c)) { return NULL; } + + if ((c->src_ipaddr.af != AF_UNSPEC) && (c->src_ipaddr.af != c->ipaddr.af)) { + DEBUG("- Cannot add client %s: Client IP and src address are different IP version.", + ip_ntoh(&request->packet->src_ipaddr, + buffer, sizeof(buffer))); + + goto error; + } return c; } diff --git a/src/main/listen.c b/src/main/listen.c index c0e1bcda897..5b1cb3713f1 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -1240,6 +1240,18 @@ static int auth_socket_send(rad_listen_t *listener, REQUEST *request) rad_assert(request->listener == listener); rad_assert(listener->send == auth_socket_send); +#ifdef WITH_UDPFROMTO + /* + * Overwrite the src ip address on the outbound packet + * with the one specified by the client. + * This is useful to work around broken DSR implementations + * and other routing issues. + */ + if (request->client->src_ipaddr.af != AF_UNSPEC) { + request->reply->src_ipaddr = request->client->src_ipaddr; + } +#endif + if (rad_send(request->reply, request->packet, request->client->secret) < 0) { radlog_request(L_ERR, 0, request, "Failed sending reply: %s", @@ -1268,6 +1280,18 @@ static int acct_socket_send(rad_listen_t *listener, REQUEST *request) */ if (request->reply->code == 0) return 0; +#ifdef WITH_UDPFROMTO + /* + * Overwrite the src ip address on the outbound packet + * with the one specified by the client. + * This is useful to work around broken DSR implementations + * and other routing issues. + */ + if (request->client->src_ipaddr.af != AF_UNSPEC) { + request->reply->src_ipaddr = request->client->src_ipaddr; + } +#endif + if (rad_send(request->reply, request->packet, request->client->secret) < 0) { radlog_request(L_ERR, 0, request, "Failed sending reply: %s",