00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #include <string.h>
00064 #include <fcntl.h>
00065 #include <errno.h>
00066
00067 #include "gwlib/gwlib.h"
00068 #include "radius/radius_acct.h"
00069 #include "radius/radius_pdu.h"
00070
00071 static Dict *radius_table = NULL;
00072 static Dict *session_table = NULL;
00073 static Dict *client_table = NULL;
00074
00075
00076 #define RADIUS_NAS_PORTS 30
00077
00078 static Mutex *radius_mutex = NULL;
00079 static int run_thread = 0;
00080
00081
00082
00083
00084
00085
00086 static Octstr *our_host = NULL;
00087 static long our_port = 1813;
00088 static Octstr *remote_host = NULL;
00089 static long remote_port = 1813;
00090
00091
00092 static Octstr *secret_nas = NULL;
00093 static Octstr *secret_radius = NULL;
00094
00095
00096 static Octstr *unified_prefix = NULL;
00097
00098
00099 static long remote_timeout = 40000;
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 static int update_tables(RADIUS_PDU *pdu)
00111 {
00112 Octstr *client_ip, *msisdn;
00113 Octstr *type, *session_id;
00114 int ret = 0;
00115 Octstr *rm_item;
00116
00117 client_ip = msisdn = type = session_id = NULL;
00118
00119
00120 if (pdu->type == 0x04) {
00121
00122
00123 type = dict_get(pdu->attr, octstr_imm("Acct-Status-Type"));
00124
00125
00126 session_id = dict_get(pdu->attr, octstr_imm("Acct-Session-Id"));
00127
00128
00129 client_ip = dict_get(pdu->attr, octstr_imm("Framed-IP-Address"));
00130 msisdn = dict_get(pdu->attr, octstr_imm("Calling-Station-Id"));
00131
00132
00133 if (client_ip == NULL || msisdn == NULL) {
00134 warning(0, "RADIUS: NAS did either not send 'Framed-IP-Address' or/and "
00135 "'Calling-Station-Id', dropping mapping but will forward.");
00136
00137 return 1;
00138 }
00139
00140 if (octstr_compare(type, octstr_imm("1")) == 0 && session_id && msisdn) {
00141
00142 if (dict_get(radius_table, client_ip) == NULL &&
00143 dict_get(session_table, session_id) == NULL) {
00144 Octstr *put_msisdn = octstr_duplicate(msisdn);
00145 Octstr *put_client_ip = octstr_duplicate(client_ip);
00146 Octstr *put_session_id = octstr_duplicate(session_id);
00147 Octstr *old_session_id, *old_client_ip;
00148
00149
00150
00151
00152 if ((old_session_id = dict_get(client_table, client_ip)) != NULL &&
00153 (old_client_ip = dict_get(session_table, old_session_id)) != NULL &&
00154 octstr_compare(old_session_id, session_id) != 0) {
00155 rm_item = dict_remove(client_table, client_ip);
00156 octstr_destroy(rm_item);
00157 rm_item = dict_remove(session_table, old_session_id);
00158 octstr_destroy(rm_item);
00159 octstr_destroy(old_session_id);
00160 octstr_destroy(old_client_ip);
00161 }
00162
00163
00164 dict_put(radius_table, client_ip, put_msisdn);
00165 dict_put(session_table, session_id, put_client_ip);
00166 dict_put(client_table, client_ip, put_session_id);
00167
00168 info(0, "RADIUS: Mapping `%s <-> %s' for session id <%s> added.",
00169 octstr_get_cstr(client_ip), octstr_get_cstr(msisdn),
00170 octstr_get_cstr(session_id));
00171 ret = 1;
00172 } else {
00173 warning(0, "RADIUS: Duplicate mapping `%s <-> %s' for session "
00174 "id <%s> received, ignoring.",
00175 octstr_get_cstr(client_ip), octstr_get_cstr(msisdn),
00176 octstr_get_cstr(session_id));
00177 }
00178 } else if (octstr_compare(type, octstr_imm("2")) == 0) {
00179
00180 Octstr *comp_client_ip;
00181 if ((msisdn = dict_get(radius_table, client_ip)) != NULL &&
00182 (comp_client_ip = dict_get(session_table, session_id)) != NULL &&
00183 octstr_compare(client_ip, comp_client_ip) == 0) {
00184 dict_remove(radius_table, client_ip);
00185 rm_item = dict_remove(client_table, client_ip);
00186 octstr_destroy(rm_item);
00187 dict_remove(session_table, session_id);
00188 info(0, "RADIUS: Mapping `%s <-> %s' for session id <%s> removed.",
00189 octstr_get_cstr(client_ip), octstr_get_cstr(msisdn),
00190 octstr_get_cstr(session_id));
00191 octstr_destroy(msisdn);
00192 octstr_destroy(comp_client_ip);
00193
00194 ret = 1;
00195 } else {
00196 warning(0, "RADIUS: Could not find mapping for `%s' session "
00197 "id <%s>, ignoring.",
00198 octstr_get_cstr(client_ip), octstr_get_cstr(session_id));
00199 }
00200
00201 } else {
00202 error(0, "RADIUS: unknown Acct-Status-Type `%s' received, ignoring.",
00203 octstr_get_cstr(type));
00204 }
00205 }
00206
00207 return ret;
00208 }
00209
00210
00211
00212
00213
00214
00215 static void proxy_thread(void *arg)
00216 {
00217 int ss, cs;
00218 int fl;
00219 Octstr *addr = NULL;
00220 int forward;
00221 Octstr *tmp;
00222
00223 run_thread = 1;
00224 ss = cs = -1;
00225
00226
00227
00228 if (remote_host != NULL) {
00229 cs = udp_client_socket();
00230 fl = fcntl(cs, F_GETFL);
00231 fcntl(cs, F_SETFL, fl | O_NONBLOCK);
00232 addr = udp_create_address(remote_host, remote_port);
00233 }
00234
00235
00236 ss = udp_bind(our_port, octstr_get_cstr(our_host));
00237
00238
00239 fl = fcntl(ss, F_GETFL);
00240 fcntl(ss, F_SETFL, fl | O_NONBLOCK);
00241
00242 if (ss == -1)
00243 panic(0, "RADIUS: Couldn't set up server socket for port %ld.", our_port);
00244
00245 while (run_thread) {
00246 RADIUS_PDU *pdu, *r;
00247 Octstr *data, *rdata;
00248 Octstr *from_nas, *from_radius;
00249
00250 pdu = r = NULL;
00251 data = rdata = from_nas = from_radius = NULL;
00252
00253 if (read_available(ss, 100000) < 1)
00254 continue;
00255
00256
00257 if (udp_recvfrom(ss, &data, &from_nas) == -1) {
00258 if (errno == EAGAIN)
00259
00260 continue;
00261
00262 error(0, "RADIUS: Couldn't receive request data from NAS");
00263 continue;
00264 }
00265
00266 tmp = udp_get_ip(from_nas);
00267 info(0, "RADIUS: Got data from NAS <%s:%d>",
00268 octstr_get_cstr(tmp), udp_get_port(from_nas));
00269 octstr_destroy(tmp);
00270 octstr_dump(data, 0);
00271
00272
00273 if ((pdu = radius_pdu_unpack(data)) == NULL) {
00274 warning(0, "RADIUS: Couldn't unpack PDU from NAS, ignoring.");
00275 goto error;
00276 }
00277 info(0, "RADIUS: from NAS: PDU type: %s", pdu->type_name);
00278
00279
00280 if (radius_authenticate_pdu(pdu, &data, secret_nas) == 0) {
00281 warning(0, "RADIUS: Authentication failed for PDU from NAS, ignoring.");
00282 goto error;
00283 }
00284
00285
00286 mutex_lock(radius_mutex);
00287 forward = update_tables(pdu);
00288 mutex_unlock(radius_mutex);
00289
00290
00291 r = radius_pdu_create(0x05, pdu);
00292
00293
00294
00295
00296
00297 r->u.Accounting_Response.identifier = pdu->u.Accounting_Request.identifier;
00298 r->u.Accounting_Response.authenticator =
00299 octstr_duplicate(pdu->u.Accounting_Request.authenticator);
00300
00301
00302 rdata = radius_pdu_pack(r);
00303
00304
00305 radius_authenticate_pdu(r, &rdata, secret_nas);
00306
00307
00308
00309
00310
00311 if ((remote_host != NULL) && forward) {
00312 if (udp_sendto(cs, data, addr) == -1) {
00313 error(0, "RADIUS: Couldn't send to remote RADIUS <%s:%ld>.",
00314 octstr_get_cstr(remote_host), remote_port);
00315 } else
00316 if (read_available(cs, remote_timeout) < 1) {
00317 error(0, "RADIUS: Timeout for response from remote RADIUS <%s:%ld>.",
00318 octstr_get_cstr(remote_host), remote_port);
00319 } else
00320 if (udp_recvfrom(cs, &data, &from_radius) == -1) {
00321 error(0, "RADIUS: Couldn't receive from remote RADIUS <%s:%ld>.",
00322 octstr_get_cstr(remote_host), remote_port);
00323 } else {
00324 info(0, "RADIUS: Got data from remote RADIUS <%s:%d>.",
00325 octstr_get_cstr(udp_get_ip(from_radius)), udp_get_port(from_radius));
00326 octstr_dump(data, 0);
00327
00328
00329
00330 }
00331 }
00332
00333
00334 if (udp_sendto(ss, rdata, from_nas) == -1)
00335 error(0, "RADIUS: Couldn't send response data to NAS <%s:%d>.",
00336 octstr_get_cstr(udp_get_ip(from_nas)), udp_get_port(from_nas));
00337
00338 error:
00339 radius_pdu_destroy(pdu);
00340 radius_pdu_destroy(r);
00341
00342 octstr_destroy(rdata);
00343 octstr_destroy(data);
00344 octstr_destroy(from_nas);
00345
00346 debug("radius.proxy", 0, "RADIUS: Mapping table contains %ld elements",
00347 dict_key_count(radius_table));
00348 debug("radius.proxy", 0, "RADIUS: Session table contains %ld elements",
00349 dict_key_count(session_table));
00350 debug("radius.proxy", 0, "RADIUS: Client table contains %ld elements",
00351 dict_key_count(client_table));
00352
00353 }
00354
00355 octstr_destroy(addr);
00356 }
00357
00358
00359
00360
00361
00362
00363 Octstr *radius_acct_get_msisdn(Octstr *client_ip)
00364 {
00365 Octstr *m, *r;
00366 char *uf;
00367
00368
00369 if (radius_table == NULL || client_ip == NULL)
00370 return NULL;
00371
00372 mutex_lock(radius_mutex);
00373 m = dict_get(radius_table, client_ip);
00374 mutex_unlock(radius_mutex);
00375 r = m ? octstr_duplicate(m) : NULL;
00376
00377
00378 uf = unified_prefix ? octstr_get_cstr(unified_prefix) : NULL;
00379 normalize_number(uf, &r);
00380
00381 return r;
00382 }
00383
00384 void radius_acct_init(CfgGroup *grp)
00385 {
00386 long nas_ports = 0;
00387
00388
00389 if ((our_host = cfg_get(grp, octstr_imm("our-host"))) == NULL) {
00390 our_host = octstr_create("0.0.0.0");
00391 }
00392 if ((remote_host = cfg_get(grp, octstr_imm("remote-host"))) != NULL) {
00393 cfg_get_integer(&remote_port, grp, octstr_imm("remote-port"));
00394 if ((secret_radius = cfg_get(grp, octstr_imm("secret-radius"))) == NULL) {
00395 panic(0, "RADIUS: No shared secret `secret-radius' for remote RADIUS in `radius-acct' provided.");
00396 }
00397 }
00398 cfg_get_integer(&our_port, grp, octstr_imm("our-port"));
00399 cfg_get_integer(&remote_timeout, grp, octstr_imm("remote-timeout"));
00400
00401 if ((cfg_get_integer(&nas_ports, grp, octstr_imm("nas-ports"))) == -1) {
00402 nas_ports = RADIUS_NAS_PORTS;
00403 }
00404
00405 if ((secret_nas = cfg_get(grp, octstr_imm("secret-nas"))) == NULL) {
00406 panic(0, "RADIUS: No shared secret `secret-nas' for NAS in `radius-acct' provided.");
00407 }
00408
00409 unified_prefix = cfg_get(grp, octstr_imm("unified-prefix"));
00410
00411 info(0, "RADIUS: local RADIUS accounting proxy at <%s:%ld>",
00412 octstr_get_cstr(our_host), our_port);
00413 if (remote_host == NULL) {
00414 info(0, "RADIUS: remote RADIUS accounting server is absent");
00415 } else {
00416 info(0, "RADIUS: remote RADIUS accounting server at <%s:%ld>",
00417 octstr_get_cstr(remote_host), remote_port);
00418 }
00419
00420 info(0, "RADIUS: initializing internal hash tables with %ld buckets.", nas_ports);
00421
00422 radius_mutex = mutex_create();
00423
00424
00425 radius_table = dict_create(nas_ports, (void (*)(void *))octstr_destroy);
00426 session_table = dict_create(nas_ports, (void (*)(void *))octstr_destroy);
00427 client_table = dict_create(nas_ports, (void (*)(void *))octstr_destroy);
00428
00429 gwthread_create(proxy_thread, NULL);
00430 }
00431
00432 void radius_acct_shutdown(void)
00433 {
00434 if (radius_mutex == NULL)
00435 return ;
00436
00437 mutex_lock(radius_mutex);
00438 run_thread = 0;
00439 mutex_unlock(radius_mutex);
00440
00441 gwthread_join_every(proxy_thread);
00442
00443 dict_destroy(radius_table);
00444 dict_destroy(session_table);
00445 dict_destroy(client_table);
00446
00447 mutex_destroy(radius_mutex);
00448
00449 octstr_destroy(our_host);
00450 octstr_destroy(remote_host);
00451 octstr_destroy(secret_nas);
00452 octstr_destroy(secret_radius);
00453 octstr_destroy(unified_prefix);
00454
00455 info(0, "RADIUS: accounting proxy stopped.");
00456 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.