/* ====================================================================
* The Kannel Software License, Version 1.0
*
* Copyright (c) 2001-2005 Kannel Group
* Copyright (c) 1998-2001 WapIT Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Kannel Group (http://www.kannel.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Kannel" and "Kannel Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please
* contact org@kannel.org.
*
* 5. Products derived from this software may not be called "Kannel",
* nor may "Kannel" appear in their name, without prior written
* permission of the Kannel Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Kannel Group. For more information on
* the Kannel Group, please see .
*
* Portions of this software are based upon software originally written at
* WapIT Ltd., Helsinki, Finland for the Kannel project.
*/
/*
* test_radius_acct.c - program to test RADIUS accounting proxy thread
*
* Stipe Tolj
*/
#include
#include
#include "gwlib/gwlib.h"
#include "radius/radius_pdu.h"
/*
* Updates the internal RADIUS mapping table. Returns 1 if the
* mapping has been new and put into the table, otherwise if it's
* a duplicate returns 0.
*/
static int update_table(RADIUS_PDU *pdu, Dict **table)
{
Octstr *client_ip, *msisdn;
Octstr *type;
int ret = 0;
client_ip = msisdn = NULL;
/* only add if we have a Accounting-Request PDU */
if (pdu->type == 0x04) {
/* check if we have a START or STOP event */
type = dict_get(pdu->attr, octstr_imm("Acct-Status-Type"));
/* grep the needed data */
client_ip = dict_get(pdu->attr, octstr_imm("Framed-IP-Address"));
msisdn = dict_get(pdu->attr, octstr_imm("Calling-Station-Id"));
if (octstr_compare(type, octstr_imm("1")) == 0) {
/* START */
if (dict_get(*table, client_ip) == NULL) {
dict_put(*table, client_ip, msisdn);
info(0, "RADIUS: Mapping `%s <-> %s' added.",
octstr_get_cstr(client_ip), octstr_get_cstr(msisdn));
ret = 1;
} else {
warning(0, "RADIUS: Duplicate mapping for `%s <-> %s' received",
octstr_get_cstr(client_ip), octstr_get_cstr(msisdn));
}
}
else if (octstr_compare(type, octstr_imm("2")) == 0) {
/* STOP */
msisdn = dict_get(*table, client_ip);
dict_remove(*table, client_ip);
}
else {
error(0, "RADIUS: unknown Acct-Status-Type `%s' received.",
octstr_get_cstr(type));
}
}
octstr_destroy(client_ip);
octstr_destroy(msisdn);
return ret;
}
static void server(int lport, int pport)
{
int i;
int ss, cs; /* server and client socket */
Octstr *data, *from, *addr;
/* pid_t pid = getpid(); */
Dict *radius_table;
/* create client binding */
cs = udp_client_socket();
addr = udp_create_address(octstr_create("localhost"), pport);
/* create server binding */
ss = udp_bind(lport, "0.0.0.0");
if (ss == -1)
panic(0, "Couldn't set up server socket for port %d.", lport);
/* init hash table */
radius_table = dict_create(30, (void (*)(void *))octstr_destroy);
i = 1;
while (1) {
RADIUS_PDU *pdu, *r;
Octstr *rdata;
int forward = 0;
/* get request */
if (udp_recvfrom(ss, &data, &from) == -1)
panic(0, "Couldn't receive request data from NAS");
info(0, "Got data from NAS <%s:%d>",
octstr_get_cstr(udp_get_ip(from)), udp_get_port(from));
/*
debug("",0,"Saving PDU packet");
f = fopen(octstr_get_cstr(octstr_format("/tmp/radius-pdu.%ld.%d", pid, i)), "w");
octstr_print(f, data);
fclose(f);
*/
pdu = radius_pdu_unpack(data);
info(0, "PDU type: %s", pdu->type_name);
/* XXX authenticator md5 check does not work?! */
/* radius_authenticate_pdu(pdu, data, octstr_imm("radius")); */
/* store to hash table if not present yet */
forward = update_table(pdu, &radius_table);
/* create response PDU for NAS */
r = radius_pdu_create(0x05, pdu);
/*
* create response authenticator
* code+identifier(req)+length+authenticator(req)+(attributes)+secret
*/
r->u.Accounting_Response.identifier = pdu->u.Accounting_Request.identifier;
r->u.Accounting_Response.authenticator =
octstr_duplicate(pdu->u.Accounting_Request.authenticator);
rdata = radius_pdu_pack(r);
/* creates response autenticator in encoded PDU */
radius_authenticate_pdu(r, &rdata, octstr_imm("radius"));
/* forward request to remote RADIUS server only if table updated */
if (forward) {
if (udp_sendto(cs, data, addr) == -1)
panic(0, "Couldn't send to remote RADIUS.");
if (udp_recvfrom(cs, &data, &from) == -1)
panic(0, "Couldn't receive from remote RADIUS.");
info(0, "Got data from remote RADIUS <%s:%d>",
octstr_get_cstr(udp_get_ip(from)), udp_get_port(from));
}
/* send response to NAS */
if (udp_sendto(ss, rdata, from) == -1)
panic(0, "Couldn't send response data to NAS.");
radius_pdu_destroy(pdu);
radius_pdu_destroy(r);
octstr_destroy(rdata);
i++;
debug("",0,"Mapping table contains %ld elements",
dict_key_count(radius_table));
}
}
int main(int argc, char **argv) {
int lport, pport;
gwlib_init();
if (argc != 3)
panic(0, "usage: test_radius_acct ");
lport = atoi(argv[1]);
pport = atoi(argv[2]);
server(lport, pport);
return 0;
}