nat: Allow the filter to select the reject cause

In preparation for another kind of black-list allow the filter code
to decide how the connection should be rejected. Introduce a new struct
that will carry the reject causes for certain operations.
This commit is contained in:
Holger Hans Peter Freyther 2012-12-17 14:35:03 +01:00
parent adc2e87372
commit bdf764a025
4 changed files with 49 additions and 23 deletions

View File

@ -327,6 +327,11 @@ struct bsc_nat_ussd_con {
struct osmo_timer_list auth_timeout;
};
struct bsc_nat_reject_cause {
int lu_reject_cause;
int cm_reject_cause;
};
/* create and init the structures */
struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token);
struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num);
@ -360,9 +365,11 @@ int bsc_nat_find_paging(struct msgb *msg, const uint8_t **,int *len);
* Content filtering.
*/
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
struct bsc_nat_parsed *, int *con_type, char **imsi);
struct bsc_nat_parsed *, int *con_type, char **imsi,
struct bsc_nat_reject_cause *cause);
int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
struct sccp_connections *con, struct bsc_nat_parsed *parsed);
struct sccp_connections *con, struct bsc_nat_parsed *parsed,
struct bsc_nat_reject_cause *cause);
/**
* SCCP patching and handling

View File

@ -1,8 +1,8 @@
/* BSC Multiplexer/NAT */
/*
* (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2011 by On-Waves
* (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2012 by On-Waves
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* All Rights Reserved
*
@ -416,7 +416,9 @@ static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal)
* 2.) Give up on the BSC side
* 2.1) Depending on the con type reject the service, or just close it
*/
static void bsc_send_con_release(struct bsc_connection *bsc, struct sccp_connections *con)
static void bsc_send_con_release(struct bsc_connection *bsc,
struct sccp_connections *con,
struct bsc_nat_reject_cause *cause)
{
struct msgb *rlsd;
/* 1. release the network */
@ -434,7 +436,7 @@ static void bsc_send_con_release(struct bsc_connection *bsc, struct sccp_connect
/* 2. release the BSC side */
if (con->con_type == NAT_CON_TYPE_LU) {
struct msgb *payload, *udt;
payload = gsm48_create_loc_upd_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause);
if (payload) {
gsm0808_prepend_dtap_header(payload, 0);
@ -465,15 +467,16 @@ static void bsc_send_con_release(struct bsc_connection *bsc, struct sccp_connect
}
static void bsc_send_con_refuse(struct bsc_connection *bsc,
struct bsc_nat_parsed *parsed, int con_type)
struct bsc_nat_parsed *parsed, int con_type,
struct bsc_nat_reject_cause *cause)
{
struct msgb *payload;
struct msgb *refuse;
if (con_type == NAT_CON_TYPE_LU)
payload = gsm48_create_loc_upd_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause);
else if (con_type == NAT_CON_TYPE_CM_SERV_REQ)
payload = gsm48_create_mm_serv_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
payload = gsm48_create_mm_serv_rej(cause->cm_reject_cause);
else {
LOGP(DNAT, LOGL_ERROR, "Unknown connection type: %d\n", con_type);
payload = NULL;
@ -980,6 +983,7 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
struct bsc_connection *con_bsc = NULL;
int con_type;
struct bsc_nat_parsed *parsed;
struct bsc_nat_reject_cause cause;
/* Parse and filter messages */
parsed = bsc_nat_parse(msg);
@ -1010,7 +1014,9 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
struct sccp_connections *con;
switch (parsed->sccp_type) {
case SCCP_MSG_TYPE_CR:
filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &con_type, &imsi);
memset(&cause, 0, sizeof(cause));
filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed,
&con_type, &imsi, &cause);
if (filter < 0) {
bsc_stat_reject(filter, bsc, 0);
goto exit3;
@ -1038,10 +1044,12 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
if (con) {
/* only filter non local connections */
if (!con->con_local) {
filter = bsc_nat_filter_dt(bsc, msg, con, parsed);
memset(&cause, 0, sizeof(cause));
filter = bsc_nat_filter_dt(bsc, msg,
con, parsed, &cause);
if (filter < 0) {
bsc_stat_reject(filter, bsc, 1);
bsc_send_con_release(bsc, con);
bsc_send_con_release(bsc, con, &cause);
con = NULL;
goto exit2;
}
@ -1156,7 +1164,7 @@ exit3:
/* send a SCCP Connection Refused */
if (imsi)
talloc_free(imsi);
bsc_send_con_refuse(bsc, parsed, con_type);
bsc_send_con_refuse(bsc, parsed, con_type, &cause);
talloc_free(parsed);
msgb_free(msg);
return -1;

View File

@ -2,8 +2,8 @@
* Access filtering
*/
/*
* (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2011 by On-Waves
* (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2012 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@ -223,8 +223,8 @@ static int _dt_check_id_resp(struct bsc_connection *bsc,
/* Filter out CR data... */
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
struct bsc_nat_parsed *parsed, int *con_type,
char **imsi)
struct bsc_nat_parsed *parsed, int *con_type,
char **imsi, struct bsc_nat_reject_cause *cause)
{
struct tlv_parsed tp;
struct gsm48_hdr *hdr48;
@ -233,6 +233,8 @@ int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
uint8_t msg_type, proto;
*con_type = NAT_CON_TYPE_NONE;
cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
*imsi = NULL;
if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
@ -292,12 +294,16 @@ int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
}
int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
struct sccp_connections *con, struct bsc_nat_parsed *parsed)
struct sccp_connections *con, struct bsc_nat_parsed *parsed,
struct bsc_nat_reject_cause *cause)
{
uint32_t len;
uint8_t msg_type, proto;
struct gsm48_hdr *hdr48;
cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
if (con->imsi_checked)
return 0;

View File

@ -1,8 +1,8 @@
/*
* BSC NAT Message filtering
*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2012 by On-Waves
*
* All Rights Reserved
*
@ -761,6 +761,7 @@ static void test_cr_filter()
struct bsc_nat_parsed *parsed;
struct bsc_nat_acc_lst *nat_lst, *bsc_lst;
struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry;
struct bsc_nat_reject_cause cause;
struct bsc_nat *nat = bsc_nat_alloc();
struct bsc_connection *bsc = bsc_connection_alloc(nat);
@ -802,7 +803,8 @@ static void test_cr_filter()
abort();
}
res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype, &imsi);
memset(&cause, 0, sizeof(cause));
res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype, &imsi, &cause);
if (res != cr_filter[i].result) {
printf("FAIL: Wrong result %d for test %d.\n", res, i);
abort();
@ -825,6 +827,7 @@ static void test_dt_filter()
int i;
struct msgb *msg = msgb_alloc(4096, "test_dt_filter");
struct bsc_nat_parsed *parsed;
struct bsc_nat_reject_cause cause;
struct bsc_nat *nat = bsc_nat_alloc();
struct bsc_connection *bsc = bsc_connection_alloc(nat);
@ -854,7 +857,8 @@ static void test_dt_filter()
abort();
}
if (bsc_nat_filter_dt(bsc, msg, con, parsed) != 1) {
memset(&cause, 0, sizeof(cause));
if (bsc_nat_filter_dt(bsc, msg, con, parsed, &cause) != 1) {
printf("FAIL: Should have passed..\n");
abort();
}
@ -869,7 +873,8 @@ static void test_dt_filter()
continue;
con->imsi_checked = 0;
bsc_nat_filter_dt(bsc, msg, con, parsed);
memset(&cause, 0, sizeof(cause));
bsc_nat_filter_dt(bsc, msg, con, parsed, &cause);
}
}