remove remaining bits of osmo-bsc_nat

osmo-bsc_nat is too heavily tied into legacy SCCPlite code, as it
is not using libosmo-sigtran/osmo_ss7 so far.  It's also full of
customer-specific code and it's shared use of some libbsc code here
has been complicating osmo-bsc development.

The current plan is to continue to use osmo-bsc_nat from openbsc.git
for those legacy users that need it, and not use osmo-bsc_nat in
new 3GPP AoIP setups.  Should we ever get a strong demand for an AoIP
based bsc_nat, we can still revisit this later.

Change-Id: Ia05dc76336a64a7f08962843b9a7cc19f2c83387
This commit is contained in:
Harald Welte 2018-05-26 21:10:13 +02:00
parent 7b897dfea5
commit 1c9b8b1917
39 changed files with 2 additions and 10806 deletions

View File

@ -49,10 +49,6 @@ PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 0.9.0)
PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.9.0)
PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.3.0)
#NOTE: osmo-bsc does not depend on libosmo-legacy-mgcp anymore, but we still
# need the dependancy for osmo-bsc-nat, which still uses the old API.
PKG_CHECK_MODULES(LIBOSMOLEGACYMGCP, libosmo-legacy-mgcp >= 1.3.0)
dnl checks for header files
AC_HEADER_STDC
@ -182,8 +178,6 @@ AC_OUTPUT(
tests/gsm0408/Makefile
tests/channel/Makefile
tests/bsc/Makefile
tests/bsc-nat/Makefile
tests/bsc-nat-trie/Makefile
tests/abis/Makefile
tests/subscr/Makefile
tests/nanobts_omlattr/Makefile

1
debian/control vendored
View File

@ -16,7 +16,6 @@ Build-Depends: debhelper (>=9),
libosmo-sigtran-dev (>= 0.8.0),
libosmo-abis-dev (>= 0.3.2),
libosmo-netif-dev (>= 0.1.0),
libosmo-legacy-mgcp-dev (>= 1.0.0),
libosmo-mgcp-client-dev (>= 1.2.0)
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/osmo-bsc.git

View File

@ -1 +0,0 @@
678012512671923:6:6:

View File

@ -1,13 +0,0 @@
nat
bsc 0
token lol
location_area_code 1234
description bsc
max-endpoints 32
paging forbidden 0
bsc 1
token wat
location_area_code 5678
description bsc
max-endpoints 32
paging forbidden 0

View File

@ -1,66 +0,0 @@
!
! OsmoBSCNAT (0.12.0.266-2daa9) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging timestamp 0
logging level all debug
logging level rll notice
logging level cc notice
logging level mm notice
logging level rr notice
logging level rsl notice
logging level nm info
logging level mncc notice
logging level pag notice
logging level meas notice
logging level sccp notice
logging level msc notice
logging level mgcp notice
logging level ho notice
logging level db notice
logging level ref notice
logging level gprs debug
logging level ns info
logging level bssgp debug
logging level llc debug
logging level sndcp debug
logging level nat notice
logging level ctrl notice
logging level smpp debug
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
!
line vty
no login
!
mgcp
bind ip 0.0.0.0
bind port 2427
rtp bts-base 4000
rtp net-base 16000
rtp ip-dscp 0
no rtcp-omit
sdp audio-payload number 126
sdp audio-payload name AMR/8000
loop 0
number endpoints 1
call-agent ip 127.0.0.1
rtp transcoder-base 0
transcoder-remote-base 4000
nat
msc ip 127.0.0.1
msc port 5000
timeout auth 2
timeout ping 20
timeout pong 5
ip-dscp 0
bscs-config-file bscs.cfg
access-list bla imsi-allow ^11$

View File

@ -7,9 +7,6 @@ noinst_HEADERS = \
arfcn_range_encode.h \
bsc_msc.h \
bsc_msg_filter.h \
bsc_nat.h \
bsc_nat_callstats.h \
bsc_nat_sccp.h \
bsc_rll.h \
bsc_subscriber.h \
bsc_subscr_conn_fsm.h \
@ -32,7 +29,6 @@ noinst_HEADERS = \
meas_feed.h \
meas_rep.h \
misdn.h \
nat_rewrite_trie.h \
network_listen.h \
openbscdefines.h \
osmo_bsc.h \

View File

@ -1,469 +0,0 @@
/*
* (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
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BSC_NAT_H
#define BSC_NAT_H
#include <osmocom/legacy_mgcp/mgcp.h>
#include "bsc_msg_filter.h"
#include <osmocom/core/select.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/msgfile.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/statistics.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <regex.h>
#include <stdbool.h>
#define DIR_BSC 1
#define DIR_MSC 2
#define PAGIN_GROUP_UNASSIGNED -1
struct sccp_source_reference;
struct nat_sccp_connection;
struct bsc_nat_parsed;
struct bsc_nat;
struct bsc_nat_ussd_con;
struct nat_rewrite_rule;
/*
* Is this terminated to the MSC, to the local machine (release
* handling for IMSI filtering) or to a USSD provider?
*/
enum {
NAT_CON_END_MSC,
NAT_CON_END_LOCAL,
NAT_CON_END_USSD,
};
/*
* Pending command entry
*/
struct bsc_cmd_list {
struct llist_head list_entry;
struct osmo_timer_list timeout;
/* The NATed ID used on the bsc_con*/
int nat_id;
/* The command from the control connection */
struct ctrl_cmd *cmd;
};
/*
* Per BSC data structure
*/
struct bsc_connection {
struct llist_head list_entry;
/* do we know anything about this BSC? */
int authenticated;
uint8_t last_rand[16];
/* the fd we use to communicate */
struct osmo_wqueue write_queue;
/* incoming message buffer */
struct msgb *pending_msg;
/* the BSS associated */
struct bsc_config *cfg;
/* a timeout node */
struct osmo_timer_list id_timeout;
/* pong timeout */
struct osmo_timer_list ping_timeout;
struct osmo_timer_list pong_timeout;
/* mgcp related code */
char *_endpoint_status;
int number_multiplexes;
int max_endpoints;
int last_endpoint;
int next_transaction;
uint32_t pending_dlcx_count;
struct llist_head pending_dlcx;
/* track the pending commands for this BSC */
struct llist_head cmd_pending;
int last_id;
/* a back pointer */
struct bsc_nat *nat;
};
/**
* Stats per BSC
*/
struct bsc_config_stats {
struct rate_ctr_group *ctrg;
};
enum bsc_cfg_ctr {
BCFG_CTR_SCCP_CONN,
BCFG_CTR_SCCP_CALLS,
BCFG_CTR_NET_RECONN,
BCFG_CTR_DROPPED_SCCP,
BCFG_CTR_DROPPED_CALLS,
BCFG_CTR_REJECTED_CR,
BCFG_CTR_REJECTED_MSG,
BCFG_CTR_ILL_PACKET,
BCFG_CTR_CON_TYPE_LU,
BCFG_CTR_CON_CMSERV_RQ,
BCFG_CTR_CON_PAG_RESP,
BCFG_CTR_CON_SSA,
BCFG_CTR_CON_OTHER,
};
/**
* One BSC entry in the config
*/
struct bsc_config {
struct llist_head entry;
uint8_t key[16];
uint8_t key_present;
char *token;
int nr;
char *description;
/* imsi white and blacklist */
char *acc_lst_name;
int forbid_paging;
int paging_group;
/* audio handling */
int max_endpoints;
/* used internally for reload handling */
bool remove;
bool token_updated;
/* backpointer */
struct bsc_nat *nat;
struct bsc_config_stats stats;
struct llist_head lac_list;
/* Osmux is enabled/disabled per BSC */
int osmux;
/* Use a jitterbuffer on the bts-side receiver */
bool bts_use_jibuf;
/* Minimum and maximum buffer size for the jitter buffer, in ms */
uint32_t bts_jitter_delay_min;
uint32_t bts_jitter_delay_max;
/* Enabled if explicitly configured through VTY: */
bool bts_use_jibuf_override;
bool bts_jitter_delay_min_override;
bool bts_jitter_delay_max_override;
};
struct bsc_lac_entry {
struct llist_head entry;
uint16_t lac;
};
struct bsc_nat_paging_group {
struct llist_head entry;
/* list of lac entries */
struct llist_head lists;
int nr;
};
/**
* BSCs point of view of endpoints
*/
struct bsc_endpoint {
/* the operation that is carried out */
int transaction_state;
/* the pending transaction id */
char *transaction_id;
/* the bsc we are talking to */
struct bsc_connection *bsc;
};
/**
* Statistic for the nat.
*/
struct bsc_nat_statistics {
struct {
struct osmo_counter *conn;
struct osmo_counter *calls;
} sccp;
struct {
struct osmo_counter *reconn;
struct osmo_counter *auth_fail;
} bsc;
struct {
struct osmo_counter *reconn;
} msc;
struct {
struct osmo_counter *reconn;
} ussd;
};
/**
* the structure of the "nat" network
*/
struct bsc_nat {
/* active SCCP connections that need patching */
struct llist_head sccp_connections;
/* active BSC connections that need patching */
struct llist_head bsc_connections;
/* access lists */
struct llist_head access_lists;
/* paging groups */
struct llist_head paging_groups;
/* known BSC's */
struct llist_head bsc_configs;
int num_bsc;
int bsc_ip_dscp;
/* MGCP config */
struct mgcp_config *mgcp_cfg;
uint8_t mgcp_msg[4096];
int mgcp_length;
int mgcp_ipa;
int sdp_ensure_amr_mode_set;
/* msc things */
struct llist_head dests;
struct bsc_msc_dest *main_dest;
struct bsc_msc_connection *msc_con;
char *token;
/* timeouts */
int auth_timeout;
int ping_timeout;
int pong_timeout;
struct bsc_endpoint *bsc_endpoints;
/* path to file with BSC config */
char *include_file;
char *include_base;
char *resolved_path;
/* filter */
char *acc_lst_name;
/* Barring of subscribers with a rb tree */
struct rb_root imsi_black_list;
char *imsi_black_list_fn;
/* number rewriting */
char *num_rewr_name;
struct llist_head num_rewr;
char *num_rewr_post_name;
struct llist_head num_rewr_post;
char *smsc_rewr_name;
struct llist_head smsc_rewr;
char *tpdest_match_name;
struct llist_head tpdest_match;
char *sms_clear_tp_srr_name;
struct llist_head sms_clear_tp_srr;
char *sms_num_rewr_name;
struct llist_head sms_num_rewr;
/* more rewriting */
char *num_rewr_trie_name;
struct nat_rewrite *num_rewr_trie;
/* USSD messages we want to match */
char *ussd_lst_name;
char *ussd_query;
regex_t ussd_query_re;
char *ussd_token;
char *ussd_local;
struct osmo_fd ussd_listen;
struct bsc_nat_ussd_con *ussd_con;
/* for maintainenance */
int blocked;
/* statistics */
struct bsc_nat_statistics stats;
/* control interface */
struct ctrl_handle *ctrl;
};
struct bsc_nat_ussd_con {
struct osmo_wqueue queue;
struct bsc_nat *nat;
int authorized;
struct msgb *pending_msg;
struct osmo_timer_list auth_timeout;
};
/* create and init the structures */
struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token,
unsigned int number);
struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num);
struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len);
void bsc_config_free(struct bsc_config *);
void bsc_config_add_lac(struct bsc_config *cfg, int lac);
void bsc_config_del_lac(struct bsc_config *cfg, int lac);
int bsc_config_handles_lac(struct bsc_config *cfg, int lac);
struct bsc_nat *bsc_nat_alloc(void);
struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat);
void bsc_nat_set_msc_ip(struct bsc_nat *bsc, const char *ip);
void sccp_connection_destroy(struct nat_sccp_connection *);
void bsc_close_connection(struct bsc_connection *);
const char *bsc_con_type_to_string(int type);
/**
* parse the given message into the above structure
*/
struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg);
/**
* filter based on IP Access header in both directions
*/
int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *parsed);
int bsc_nat_vty_init(struct bsc_nat *nat);
int bsc_nat_find_paging(struct msgb *msg, const uint8_t **,int *len);
/**
* SCCP patching and handling
*/
struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed);
int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed);
void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_connection *);
struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *, struct sccp_source_reference *);
/**
* MGCP/Audio handling
*/
int bsc_mgcp_nr_multiplexes(int max_endpoints);
int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length);
int bsc_mgcp_assign_patch(struct nat_sccp_connection *, struct msgb *msg);
void bsc_mgcp_init(struct nat_sccp_connection *);
void bsc_mgcp_dlcx(struct nat_sccp_connection *);
void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
int bsc_mgcp_nat_init(struct bsc_nat *nat);
struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(char *input, int length, int endp, const char *ip,
int port, int osmux, int *first_payload_type, int mode_set);
void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]);
uint32_t bsc_mgcp_extract_ci(const char *resp);
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int id);
int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg);
int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg);
int bsc_nat_msc_is_connected(struct bsc_nat *nat);
int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn);
struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, struct msgb *msg, uint32_t *len);
/** USSD filtering */
int bsc_ussd_init(struct bsc_nat *nat);
int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, struct msgb *msg);
int bsc_ussd_close_connections(struct bsc_nat *nat);
struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *, const char *imsi);
/** paging group handling */
struct bsc_nat_paging_group *bsc_nat_paging_group_num(struct bsc_nat *nat, int group);
struct bsc_nat_paging_group *bsc_nat_paging_group_create(struct bsc_nat *nat, int group);
void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *);
void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *grp, int lac);
void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *grp, int lac);
/**
* Number rewriting support below
*/
struct bsc_nat_num_rewr_entry {
struct llist_head list;
regex_t msisdn_reg;
regex_t num_reg;
char *replace;
uint8_t is_prefix_lookup;
};
void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const struct osmo_config_list *);
void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg);
void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg);
struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat,
const char *bind_addr, int port);
void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending);
int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg);
int bsc_nat_extract_lac(struct bsc_connection *bsc, struct nat_sccp_connection *con,
struct bsc_nat_parsed *parsed, struct msgb *msg);
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
struct bsc_nat_parsed *, int *con_type, char **imsi,
struct bsc_filter_reject_cause *cause);
int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed,
struct bsc_filter_reject_cause *cause);
/**
* CTRL interface helper
*/
void bsc_nat_inform_reject(struct bsc_connection *bsc, const char *imsi);
/*
* Use for testing
*/
void bsc_nat_free(struct bsc_nat *nat);
#endif

View File

@ -1,55 +0,0 @@
/*
* (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
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BSC_NAT_CALLSTATS_H
#define BSC_NAT_CALLSTATS_H
#include <osmocom/core/linuxlist.h>
#include <osmocom/sccp/sccp_types.h>
struct bsc_nat_call_stats {
struct llist_head entry;
struct sccp_source_reference remote_ref;
struct sccp_source_reference src_ref; /* as seen by the MSC */
/* mgcp options */
uint32_t ci;
int bts_rtp_port;
int net_rtp_port;
struct in_addr bts_addr;
struct in_addr net_addr;
/* as witnessed by the NAT */
uint32_t net_ps;
uint32_t net_os;
uint32_t bts_pr;
uint32_t bts_or;
uint32_t bts_expected;
uint32_t bts_jitter;
int bts_loss;
uint32_t trans_id;
int msc_endpoint;
};
#endif

View File

@ -1,105 +0,0 @@
/* NAT utilities using SCCP types */
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BSC_NAT_SCCP_H
#define BSC_NAT_SCCP_H
#include "bsc_msg_filter.h"
#include <osmocom/sccp/sccp_types.h>
/*
* For the NAT we will need to analyze and later patch
* the received message. This would require us to parse
* the IPA and SCCP header twice. Instead of doing this
* we will have one analyze structure and have the patching
* and filter operate on the same structure.
*/
struct bsc_nat_parsed {
/* ip access prototype */
int ipa_proto;
/* source local reference */
struct sccp_source_reference *src_local_ref;
/* destination local reference */
struct sccp_source_reference *dest_local_ref;
/* original value */
struct sccp_source_reference original_dest_ref;
/* called ssn number */
int called_ssn;
/* calling ssn number */
int calling_ssn;
/* sccp message type */
int sccp_type;
/* bssap type, e.g. 0 for BSS Management */
int bssap;
/* the gsm0808 message type */
int gsm_type;
};
/*
* Per SCCP source local reference patch table. It needs to
* be updated on new SCCP connections, connection confirm and reject,
* and on the loss of the BSC connection.
*/
struct nat_sccp_connection {
struct llist_head list_entry;
struct bsc_connection *bsc;
struct bsc_msc_connection *msc_con;
struct sccp_source_reference real_ref;
struct sccp_source_reference patched_ref;
struct sccp_source_reference remote_ref;
int has_remote_ref;
/* status */
int con_local;
int authorized;
struct bsc_filter_state filter_state;
uint16_t lac;
uint16_t ci;
/* remember which Transactions we run over the bypass */
char ussd_ti[8];
/*
* audio handling. Remember if we have ever send a CRCX,
* remember the endpoint used by the MSC and BSC.
*/
int msc_endp;
int bsc_endp;
/* timeout handling */
struct timespec creation_time;
};
#endif

View File

@ -1,47 +0,0 @@
/*
* (C) 2013 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NAT_REWRITE_FILE_H
#define NAT_REWRITE_FILE_H
#include <osmocom/core/linuxrbtree.h>
struct vty;
struct nat_rewrite_rule {
/* For digits 0-9 and + */
struct nat_rewrite_rule *rules[11];
char empty;
char prefix[14];
char rewrite[6];
};
struct nat_rewrite {
struct nat_rewrite_rule rule;
size_t prefixes;
};
struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename);
struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *, const char *prefix);
void nat_rewrite_dump(struct nat_rewrite *rewr);
void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewr);
#endif

View File

@ -19,9 +19,10 @@
*/
#include <osmocom/bsc/bsc_msg_filter.h>
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/stats.h>

View File

@ -23,7 +23,6 @@
#include <osmocom/bsc/bsc_msg_filter.h>
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_msc.h>
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/debug.h>

View File

@ -20,7 +20,6 @@
*
*/
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/crypt/auth.h>

View File

@ -1,51 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
-I$(top_builddir) \
$(NULL)
AM_CFLAGS = \
-Wall \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOSCCP_CFLAGS) \
$(LIBOSMOLEGACYMGCP_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
$(NULL)
bin_PROGRAMS = \
osmo-bsc_nat \
$(NULL)
osmo_bsc_nat_SOURCES = \
bsc_filter.c \
bsc_mgcp_utils.c \
bsc_nat.c \
bsc_nat_utils.c \
bsc_nat_vty.c \
bsc_sccp.c \
bsc_ussd.c \
bsc_nat_ctrl.c \
bsc_nat_rewrite.c \
bsc_nat_rewrite_trie.c \
bsc_nat_filter.c \
$(NULL)
osmo_bsc_nat_LDADD = \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(LIBOSMOSCCP_LIBS) \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOSIGTRAN_LIBS) \
$(LIBRARY_GSM) \
-lrt \
$(NULL)

View File

@ -1,220 +0,0 @@
/* BSC Multiplexer/NAT */
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_nat_sccp.h>
#include <osmocom/bsc/ipaccess.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/sccp/sccp.h>
/*
* The idea is to have a simple struct describing a IPA packet with
* SCCP SSN and the GSM 08.08 payload and decide. We will both have
* a white and a blacklist of packets we want to handle.
*
* TODO: Implement a "NOT" in the filter language.
*/
#define ALLOW_ANY -1
#define FILTER_TO_BSC 1
#define FILTER_TO_MSC 2
#define FILTER_TO_BOTH 3
struct bsc_pkt_filter {
int ipa_proto;
int dest_ssn;
int bssap;
int gsm;
int filter_dir;
};
static struct bsc_pkt_filter black_list[] = {
/* filter reset messages to the MSC */
{ IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC },
/* filter reset ack messages to the BSC */
{ IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC },
/* filter ip access */
{ IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC },
};
static struct bsc_pkt_filter white_list[] = {
/* allow IPAC_PROTO_SCCP messages to both sides */
{ IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
/* allow MGCP messages to both sides */
{ IPAC_PROTO_MGCP_OLD, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
};
struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg)
{
struct sccp_parse_result result;
struct bsc_nat_parsed *parsed;
struct ipaccess_head *hh;
/* quick fail */
if (msg->len < 4)
return NULL;
parsed = talloc_zero(msg, struct bsc_nat_parsed);
if (!parsed)
return NULL;
/* more init */
parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1;
parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1;
/* start parsing */
hh = (struct ipaccess_head *) msg->data;
parsed->ipa_proto = hh->proto;
msg->l2h = &hh->data[0];
/* do a size check on the input */
if (ntohs(hh->len) != msgb_l2len(msg)) {
LOGP(DLINP, LOGL_ERROR, "Wrong input length?\n");
talloc_free(parsed);
return NULL;
}
/* analyze sccp down here */
if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
memset(&result, 0, sizeof(result));
if (sccp_parse_header(msg, &result) != 0) {
talloc_free(parsed);
return 0;
}
if (msg->l3h && msgb_l3len(msg) < 3) {
LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n");
talloc_free(parsed);
return 0;
}
parsed->sccp_type = sccp_determine_msg_type(msg);
parsed->src_local_ref = result.source_local_reference;
parsed->dest_local_ref = result.destination_local_reference;
if (parsed->dest_local_ref)
parsed->original_dest_ref = *parsed->dest_local_ref;
parsed->called_ssn = result.called.ssn;
parsed->calling_ssn = result.calling.ssn;
/* in case of connection confirm we have no payload */
if (msg->l3h) {
parsed->bssap = msg->l3h[0];
parsed->gsm_type = msg->l3h[2];
}
}
return parsed;
}
int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed)
{
int i;
/* go through the blacklist now */
for (i = 0; i < ARRAY_SIZE(black_list); ++i) {
/* ignore the rule? */
if (black_list[i].filter_dir != FILTER_TO_BOTH
&& black_list[i].filter_dir != dir)
continue;
/* the proto is not blacklisted */
if (black_list[i].ipa_proto != ALLOW_ANY
&& black_list[i].ipa_proto != parsed->ipa_proto)
continue;
if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
/* the SSN is not blacklisted */
if (black_list[i].dest_ssn != ALLOW_ANY
&& black_list[i].dest_ssn != parsed->called_ssn)
continue;
/* bssap */
if (black_list[i].bssap != ALLOW_ANY
&& black_list[i].bssap != parsed->bssap)
continue;
/* gsm */
if (black_list[i].gsm != ALLOW_ANY
&& black_list[i].gsm != parsed->gsm_type)
continue;
/* blacklisted */
LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
return 1;
} else {
/* blacklisted, we have no content sniffing yet */
LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
return 1;
}
}
/* go through the whitelust now */
for (i = 0; i < ARRAY_SIZE(white_list); ++i) {
/* ignore the rule? */
if (white_list[i].filter_dir != FILTER_TO_BOTH
&& white_list[i].filter_dir != dir)
continue;
/* the proto is not whitelisted */
if (white_list[i].ipa_proto != ALLOW_ANY
&& white_list[i].ipa_proto != parsed->ipa_proto)
continue;
if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
/* the SSN is not whitelisted */
if (white_list[i].dest_ssn != ALLOW_ANY
&& white_list[i].dest_ssn != parsed->called_ssn)
continue;
/* bssap */
if (white_list[i].bssap != ALLOW_ANY
&& white_list[i].bssap != parsed->bssap)
continue;
/* gsm */
if (white_list[i].gsm != ALLOW_ANY
&& white_list[i].gsm != parsed->gsm_type)
continue;
/* whitelisted */
LOGP(DNAT, LOGL_INFO, "Whitelisted with rule %d\n", i);
return 0;
} else {
/* whitelisted */
return 0;
}
}
return 1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,531 +0,0 @@
/*
* (C) 2011-2012 by Holger Hans Peter Freyther
* (C) 2011-2012 by On-Waves
* (C) 2011 by Daniel Willmann
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/talloc.h>
#include <osmocom/ctrl/control_cmd.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/vty/misc.h>
#include <osmocom/bsc/ctrl.h>
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_msg_filter.h>
#include <osmocom/bsc/vty.h>
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/debug.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define NAT_MAX_CTRL_ID 65535
static struct bsc_nat *g_nat;
static int bsc_id_unused(int id, struct bsc_connection *bsc)
{
struct bsc_cmd_list *pending;
llist_for_each_entry(pending, &bsc->cmd_pending, list_entry) {
if (pending->nat_id == id)
return 0;
}
return 1;
}
static int get_next_free_bsc_id(struct bsc_connection *bsc)
{
int new_id, overflow = 0;
new_id = bsc->last_id;
do {
new_id++;
if (new_id == NAT_MAX_CTRL_ID) {
new_id = 1;
overflow++;
}
if (bsc_id_unused(new_id, bsc)) {
bsc->last_id = new_id;
return new_id;
}
} while (overflow != 2);
return -1;
}
void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending)
{
llist_del(&pending->list_entry);
osmo_timer_del(&pending->timeout);
talloc_free(pending);
}
static struct bsc_cmd_list *bsc_get_pending(struct bsc_connection *bsc, char *id_str)
{
struct bsc_cmd_list *cmd_entry;
int id = atoi(id_str);
if (id == 0)
return NULL;
llist_for_each_entry(cmd_entry, &bsc->cmd_pending, list_entry) {
if (cmd_entry->nat_id == id) {
return cmd_entry;
}
}
return NULL;
}
int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg)
{
struct ctrl_cmd *cmd;
struct bsc_cmd_list *pending;
char *var;
cmd = ctrl_cmd_parse(bsc, msg);
msgb_free(msg);
if (!cmd) {
cmd = talloc_zero(bsc, struct ctrl_cmd);
if (!cmd) {
LOGP(DNAT, LOGL_ERROR, "OOM!\n");
return -ENOMEM;
}
cmd->type = CTRL_TYPE_ERROR;
cmd->id = "err";
cmd->reply = "Failed to parse command.";
goto err;
}
if (bsc->cfg && !llist_empty(&bsc->cfg->lac_list)) {
if (cmd->variable) {
var = talloc_asprintf(cmd, "net.0.bsc.%i.%s", bsc->cfg->nr,
cmd->variable);
if (!var) {
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "OOM";
goto err;
}
talloc_free(cmd->variable);
cmd->variable = var;
}
/* We have to handle TRAPs before matching pending */
if (cmd->type == CTRL_TYPE_TRAP) {
ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd);
talloc_free(cmd);
return 0;
}
/* Find the pending command */
pending = bsc_get_pending(bsc, cmd->id);
if (pending) {
osmo_talloc_replace_string(cmd, &cmd->id, pending->cmd->id);
if (!cmd->id) {
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "OOM";
goto err;
}
ctrl_cmd_send(&pending->cmd->ccon->write_queue, cmd);
bsc_nat_ctrl_del_pending(pending);
} else {
/* We need to handle TRAPS here */
if ((cmd->type != CTRL_TYPE_ERROR) &&
(cmd->type != CTRL_TYPE_TRAP)) {
LOGP(DNAT, LOGL_NOTICE, "Got control message "
"from BSC without pending entry\n");
cmd->type = CTRL_TYPE_ERROR;
cmd->reply = "No request outstanding";
goto err;
}
}
}
talloc_free(cmd);
return 0;
err:
ctrl_cmd_send(&bsc->write_queue, cmd);
talloc_free(cmd);
return 0;
}
static void pending_timeout_cb(void *data)
{
struct bsc_cmd_list *pending = data;
LOGP(DNAT, LOGL_ERROR, "Command timed out\n");
pending->cmd->type = CTRL_TYPE_ERROR;
pending->cmd->reply = "Command timed out";
ctrl_cmd_send(&pending->cmd->ccon->write_queue, pending->cmd);
bsc_nat_ctrl_del_pending(pending);
}
static void ctrl_conn_closed_cb(struct ctrl_connection *connection)
{
struct bsc_connection *bsc;
struct bsc_cmd_list *pending, *tmp;
llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) {
llist_for_each_entry_safe(pending, tmp, &bsc->cmd_pending, list_entry) {
if (pending->cmd->ccon == connection)
bsc_nat_ctrl_del_pending(pending);
}
}
}
static int extract_bsc_nr_variable(char *variable, unsigned int *nr, char **bsc_variable)
{
char *nr_str, *tmp, *saveptr = NULL;
tmp = strtok_r(variable, ".", &saveptr);
tmp = strtok_r(NULL, ".", &saveptr);
tmp = strtok_r(NULL, ".", &saveptr);
nr_str = strtok_r(NULL, ".", &saveptr);
if (!nr_str)
return 0;
*nr = atoi(nr_str);
tmp = strtok_r(NULL, "\0", &saveptr);
if (!tmp)
return 0;
*bsc_variable = tmp;
return 1;
}
static int forward_to_bsc(struct ctrl_cmd *cmd)
{
int ret = CTRL_CMD_HANDLED;
struct ctrl_cmd *bsc_cmd = NULL;
struct bsc_connection *bsc;
struct bsc_cmd_list *pending = NULL;
unsigned int nr;
char *bsc_variable;
/* Skip over the beginning (bsc.) */
if (!extract_bsc_nr_variable(cmd->variable, &nr, &bsc_variable)) {
cmd->reply = "command incomplete";
goto err;
}
llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) {
if (!bsc->cfg)
continue;
if (!bsc->authenticated)
continue;
if (bsc->cfg->nr != nr)
continue;
/* Add pending command to list */
pending = talloc_zero(bsc, struct bsc_cmd_list);
if (!pending) {
cmd->reply = "OOM";
goto err;
}
pending->nat_id = get_next_free_bsc_id(bsc);
if (pending->nat_id < 0) {
cmd->reply = "No free ID found";
goto err;
}
bsc_cmd = ctrl_cmd_cpy(bsc, cmd);
if (!bsc_cmd) {
cmd->reply = "Could not forward command";
goto err;
}
talloc_free(bsc_cmd->id);
bsc_cmd->id = talloc_asprintf(bsc_cmd, "%i", pending->nat_id);
if (!bsc_cmd->id) {
cmd->reply = "OOM";
goto err;
}
talloc_free(bsc_cmd->variable);
bsc_cmd->variable = talloc_strdup(bsc_cmd, bsc_variable);
if (!bsc_cmd->variable) {
cmd->reply = "OOM";
goto err;
}
if (ctrl_cmd_send(&bsc->write_queue, bsc_cmd)) {
cmd->reply = "Sending failed";
goto err;
}
/* caller owns cmd param and will destroy it after we return */
pending->cmd = ctrl_cmd_cpy(pending, cmd);
if (!pending->cmd) {
cmd->reply = "Could not answer command";
goto err;
}
cmd->ccon->closed_cb = ctrl_conn_closed_cb;
pending->cmd->ccon = cmd->ccon;
/* Setup the timeout */
osmo_timer_setup(&pending->timeout, pending_timeout_cb,
pending);
/* TODO: Make timeout configurable */
osmo_timer_schedule(&pending->timeout, 10, 0);
llist_add_tail(&pending->list_entry, &bsc->cmd_pending);
goto done;
}
/* We end up here if there's no bsc to handle our LAC */
cmd->reply = "no BSC with this nr";
err:
ret = CTRL_CMD_ERROR;
talloc_free(pending);
done:
talloc_free(bsc_cmd);
return ret;
}
CTRL_CMD_DEFINE(fwd_cmd, "net 0 bsc *");
static int get_fwd_cmd(struct ctrl_cmd *cmd, void *data)
{
return forward_to_bsc(cmd);
}
static int set_fwd_cmd(struct ctrl_cmd *cmd, void *data)
{
return forward_to_bsc(cmd);
}
static int verify_fwd_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
{
return 0;
}
static int extract_bsc_cfg_variable(struct ctrl_cmd *cmd, struct bsc_config **cfg,
char **bsc_variable)
{
unsigned int nr;
if (!extract_bsc_nr_variable(cmd->variable, &nr, bsc_variable)) {
cmd->reply = "command incomplete";
return 0;
}
*cfg = bsc_config_num(g_nat, nr);
if (!*cfg) {
cmd->reply = "Unknown BSC";
return 0;
}
return 1;
}
CTRL_CMD_DEFINE(net_cfg_cmd, "net 0 bsc_cfg *");
static int get_net_cfg_cmd(struct ctrl_cmd *cmd, void *data)
{
char *bsc_variable;
struct bsc_config *bsc_cfg;
if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable))
return CTRL_CMD_ERROR;
if (strcmp(bsc_variable, "access-list-name") == 0) {
cmd->reply = talloc_asprintf(cmd, "%s",
bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : "");
return CTRL_CMD_REPLY;
}
cmd->reply = "unknown command";
return CTRL_CMD_ERROR;
}
static int set_net_cfg_cmd(struct ctrl_cmd *cmd, void *data)
{
char *bsc_variable;
struct bsc_config *bsc_cfg;
if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable))
return CTRL_CMD_ERROR;
if (strcmp(bsc_variable, "access-list-name") == 0) {
osmo_talloc_replace_string(bsc_cfg, &bsc_cfg->acc_lst_name, cmd->value);
cmd->reply = talloc_asprintf(cmd, "%s",
bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : "");
return CTRL_CMD_REPLY;
} else if (strcmp(bsc_variable, "no-access-list-name") == 0) {
talloc_free(bsc_cfg->acc_lst_name);
bsc_cfg->acc_lst_name = NULL;
cmd->reply = "";
return CTRL_CMD_REPLY;
}
cmd->reply = "unknown command";
return CTRL_CMD_ERROR;
}
static int verify_net_cfg_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
{
return 0;
}
CTRL_CMD_DEFINE(net_cfg_acc_cmd, "net 0 add allow access-list *");
static const char *extract_acc_name(const char *var)
{
char *str;
str = strstr(var, "net.0.add.allow.access-list.");
if (!str)
return NULL;
str += strlen("net.0.add.allow.access-list.");
if (strlen(str) == 0)
return NULL;
return str;
}
static int get_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data)
{
cmd->reply = "Append only";
return CTRL_CMD_ERROR;
}
static int set_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data)
{
const char *access_name = extract_acc_name(cmd->variable);
struct bsc_msg_acc_lst *acc;
struct bsc_msg_acc_lst_entry *entry;
const char *value = cmd->value;
int rc;
/* Should have been caught by verify_net_cfg_acc_cmd */
acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name);
if (!acc) {
cmd->reply = "Access list not found";
return CTRL_CMD_ERROR;
}
entry = bsc_msg_acc_lst_entry_create(acc);
if (!entry) {
cmd->reply = "OOM";
return CTRL_CMD_ERROR;
}
rc = gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, 1, &value);
if (rc != 0) {
cmd->reply = "Failed to compile expression";
return CTRL_CMD_ERROR;
}
cmd->reply = "IMSI allow added to access list";
return CTRL_CMD_REPLY;
}
static int verify_net_cfg_acc_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
{
const char *access_name = extract_acc_name(cmd->variable);
struct bsc_msg_acc_lst *acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name);
if (!acc) {
cmd->reply = "Access list not known";
return -1;
}
return 0;
}
CTRL_CMD_DEFINE_WO_NOVRF(net_save_cmd, "net 0 save-configuration");
static int set_net_save_cmd(struct ctrl_cmd *cmd, void *data)
{
int rc = osmo_vty_save_config_file();
cmd->reply = talloc_asprintf(cmd, "%d", rc);
if (!cmd->reply) {
cmd->reply = "OOM";
return CTRL_CMD_ERROR;
}
return CTRL_CMD_REPLY;
}
struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat,
const char *bind_addr, int port)
{
struct ctrl_handle *ctrl;
int rc;
ctrl = bsc_controlif_setup(NULL, bind_addr, OSMO_CTRL_PORT_BSC_NAT);
if (!ctrl) {
fprintf(stderr, "Failed to initialize the control interface. Exiting.\n");
return NULL;
}
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_fwd_cmd);
if (rc) {
fprintf(stderr, "Failed to install the control command. Exiting.\n");
goto error;
}
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_cmd);
if (rc) {
fprintf(stderr, "Failed to install the net cfg command. Exiting.\n");
goto error;
}
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_acc_cmd);
if (rc) {
fprintf(stderr, "Failed to install the net acc command. Exiting.\n");
goto error;
}
rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_save_cmd);
if (rc) {
fprintf(stderr, "Failed to install the net save command. Exiting.\n");
goto error;
}
g_nat = nat;
return ctrl;
error:
osmo_fd_unregister(&ctrl->listen_fd);
close(ctrl->listen_fd.fd);
talloc_free(ctrl);
return NULL;
}
void bsc_nat_inform_reject(struct bsc_connection *conn, const char *imsi)
{
struct ctrl_cmd *cmd;
cmd = ctrl_cmd_create(conn, CTRL_TYPE_TRAP);
if (!cmd) {
LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n");
return;
}
cmd->id = "0";
cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.notification-rejection-v1",
conn->cfg->nr);
cmd->reply = talloc_asprintf(cmd, "imsi=%s", imsi);
ctrl_cmd_send_to_all(conn->cfg->nat->ctrl, cmd);
talloc_free(cmd);
}

View File

@ -1,119 +0,0 @@
/*
* (C) 2010-2015 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
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_nat_sccp.h>
#include <osmocom/bsc/bsc_msg_filter.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/protocol/gsm_04_11.h>
#include <osmocom/sccp/sccp.h>
/* 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_filter_reject_cause *cause)
{
struct bsc_filter_request req;
struct tlv_parsed tp;
struct gsm48_hdr *hdr48;
int hdr48_len;
int len;
*con_type = FLT_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) {
LOGP(DNAT, LOGL_ERROR,
"Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type);
return -1;
}
/* the parsed has had some basic l3 length check */
len = msg->l3h[1];
if (msgb_l3len(msg) - 3 < len) {
LOGP(DNAT, LOGL_ERROR,
"The CR Data has not enough space...\n");
return -1;
}
msg->l4h = &msg->l3h[3];
len -= 1;
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0);
if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n");
return -1;
}
hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
if (hdr48_len < sizeof(*hdr48)) {
LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n");
return -1;
}
hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
req.ctx = bsc;
req.black_list = &bsc->nat->imsi_black_list;
req.access_lists = &bsc->nat->access_lists;
req.local_lst_name = bsc->cfg->acc_lst_name;
req.global_lst_name = bsc->nat->acc_lst_name;
req.bsc_nr = bsc->cfg->nr;
return bsc_msg_filter_initial(hdr48, hdr48_len, &req, con_type, imsi, cause);
}
int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed,
struct bsc_filter_reject_cause *cause)
{
uint32_t len;
struct gsm48_hdr *hdr48;
struct bsc_filter_request req;
cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
if (con->filter_state.imsi_checked)
return 0;
/* only care about DTAP messages */
if (parsed->bssap != BSSAP_MSG_DTAP)
return 0;
hdr48 = bsc_unpack_dtap(parsed, msg, &len);
if (!hdr48)
return -1;
req.ctx = con;
req.black_list = &bsc->nat->imsi_black_list;
req.access_lists = &bsc->nat->access_lists;
req.local_lst_name = bsc->cfg->acc_lst_name;
req.global_lst_name = bsc->nat->acc_lst_name;
req.bsc_nr = bsc->cfg->nr;
return bsc_msg_filter_data(hdr48, len, &req, &con->filter_state, cause);
}

View File

@ -1,730 +0,0 @@
/*
* Message rewriting functionality
*/
/*
* (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2013 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_nat_sccp.h>
#include <osmocom/bsc/bsc_msc.h>
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/ipaccess.h>
#include <osmocom/bsc/nat_rewrite_trie.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/ipa.h>
#include <osmocom/gsm/mncc.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/protocol/gsm_04_11.h>
#include <osmocom/sccp/sccp.h>
static char *trie_lookup(struct nat_rewrite *trie, const char *number,
regoff_t off, void *ctx)
{
struct nat_rewrite_rule *rule;
if (!trie) {
LOGP(DCC, LOGL_ERROR,
"Asked to do a table lookup but no table.\n");
return NULL;
}
rule = nat_rewrite_lookup(trie, number);
if (!rule) {
LOGP(DCC, LOGL_DEBUG,
"Couldn't find a prefix rule for %s\n", number);
return NULL;
}
return talloc_asprintf(ctx, "%s%s", rule->rewrite, &number[off]);
}
static char *match_and_rewrite_number(void *ctx, const char *number,
const char *imsi, struct llist_head *list,
struct nat_rewrite *trie)
{
struct bsc_nat_num_rewr_entry *entry;
char *new_number = NULL;
/* need to find a replacement and then fix it */
llist_for_each_entry(entry, list, list) {
regmatch_t matches[2];
/* check the IMSI match */
if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
continue;
/* this regexp matches... */
if (regexec(&entry->num_reg, number, 2, matches, 0) == 0
&& matches[1].rm_eo != -1) {
if (entry->is_prefix_lookup)
new_number = trie_lookup(trie, number,
matches[1].rm_so, ctx);
else
new_number = talloc_asprintf(ctx, "%s%s",
entry->replace,
&number[matches[1].rm_so]);
}
if (new_number)
break;
}
return new_number;
}
static char *rewrite_isdn_number(struct bsc_nat *nat, struct llist_head *rewr_list,
void *ctx, const char *imsi,
struct gsm_mncc_number *called)
{
char int_number[sizeof(called->number) + 2];
char *number = called->number;
if (llist_empty(&nat->num_rewr)) {
LOGP(DCC, LOGL_DEBUG, "Rewrite rules empty.\n");
return NULL;
}
/* only ISDN plan */
if (called->plan != 1) {
LOGP(DCC, LOGL_DEBUG, "Called plan is not 1 it was %d\n",
called->plan);
return NULL;
}
/* international, prepend */
if (called->type == 1) {
int_number[0] = '+';
memcpy(&int_number[1], number, strlen(number) + 1);
number = int_number;
}
return match_and_rewrite_number(ctx, number,
imsi, rewr_list, nat->num_rewr_trie);
}
static void update_called_number(struct gsm_mncc_number *called,
const char *chosen_number)
{
if (strncmp(chosen_number, "00", 2) == 0) {
called->type = 1;
osmo_strlcpy(called->number, chosen_number + 2,
sizeof(called->number));
} else {
/* rewrite international to unknown */
if (called->type == 1)
called->type = 0;
osmo_strlcpy(called->number, chosen_number,
sizeof(called->number));
}
}
/**
* Rewrite non global numbers... according to rules based on the IMSI
*/
static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg,
struct bsc_nat_parsed *parsed, const char *imsi,
struct gsm48_hdr *hdr48, const uint32_t len)
{
struct tlv_parsed tp;
unsigned int payload_len;
struct gsm_mncc_number called;
struct msgb *out;
char *new_number_pre = NULL, *new_number_post = NULL, *chosen_number;
uint8_t *outptr;
const uint8_t *msgptr;
int sec_len;
/* decode and rewrite the message */
payload_len = len - sizeof(*hdr48);
tlv_parse(&tp, &gsm48_att_tlvdef, hdr48->data, payload_len, 0, 0);
/* no number, well let us ignore it */
if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD))
return NULL;
memset(&called, 0, sizeof(called));
gsm48_decode_called(&called,
TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1);
/* check if it looks international and stop */
LOGP(DCC, LOGL_DEBUG,
"Pre-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n",
imsi, called.plan, called.type, called.number);
new_number_pre = rewrite_isdn_number(nat, &nat->num_rewr, msg, imsi, &called);
if (!new_number_pre) {
LOGP(DCC, LOGL_DEBUG, "No IMSI(%s) match found, returning message.\n",
imsi);
return NULL;
}
if (strlen(new_number_pre) > sizeof(called.number)) {
LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n",
new_number_pre);
talloc_free(new_number_pre);
return NULL;
}
update_called_number(&called, new_number_pre);
/* another run through the re-write engine with other rules */
LOGP(DCC, LOGL_DEBUG,
"Post-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n",
imsi, called.plan, called.type, called.number);
new_number_post = rewrite_isdn_number(nat, &nat->num_rewr_post, msg,
imsi, &called);
chosen_number = new_number_post ? new_number_post : new_number_pre;
if (strlen(chosen_number) > sizeof(called.number)) {
LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n",
chosen_number);
talloc_free(new_number_pre);
talloc_free(new_number_post);
return NULL;
}
/*
* Need to create a new message now based on the old onew
* with a new number. We can sadly not patch this in place
* so we will need to regenerate it.
*/
out = msgb_alloc_headroom(4096, 128, "changed-setup");
if (!out) {
LOGP(DCC, LOGL_ERROR, "Failed to allocate.\n");
talloc_free(new_number_pre);
talloc_free(new_number_post);
return NULL;
}
/* copy the header */
outptr = msgb_put(out, sizeof(*hdr48));
memcpy(outptr, hdr48, sizeof(*hdr48));
/* copy everything up to the number */
sec_len = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 2 - &hdr48->data[0];
outptr = msgb_put(out, sec_len);
memcpy(outptr, &hdr48->data[0], sec_len);
/* create the new number */
update_called_number(&called, chosen_number);
LOGP(DCC, LOGL_DEBUG,
"Chosen number for IMSI(%s) is Plan(%d) Type(%d) Number(%s)\n",
imsi, called.plan, called.type, called.number);
gsm48_encode_called(out, &called);
/* copy thre rest */
msgptr = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) +
TLVP_LEN(&tp, GSM48_IE_CALLED_BCD);
sec_len = payload_len - (msgptr - &hdr48->data[0]);
outptr = msgb_put(out, sec_len);
memcpy(outptr, msgptr, sec_len);
talloc_free(new_number_pre);
talloc_free(new_number_post);
return out;
}
/**
* Find a new SMSC address, returns an allocated string that needs to be
* freed or is NULL.
*/
static char *find_new_smsc(struct bsc_nat *nat, void *ctx, const char *imsi,
const char *smsc_addr, const char *dest_nr)
{
struct bsc_nat_num_rewr_entry *entry;
char *new_number = NULL;
uint8_t dest_match = llist_empty(&nat->tpdest_match);
/* We will find a new number now */
llist_for_each_entry(entry, &nat->smsc_rewr, list) {
regmatch_t matches[2];
/* check the IMSI match */
if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
continue;
/* this regexp matches... */
if (regexec(&entry->num_reg, smsc_addr, 2, matches, 0) == 0 &&
matches[1].rm_eo != -1)
new_number = talloc_asprintf(ctx, "%s%s",
entry->replace,
&smsc_addr[matches[1].rm_so]);
if (new_number)
break;
}
if (!new_number)
return NULL;
/*
* now match the number against another list
*/
llist_for_each_entry(entry, &nat->tpdest_match, list) {
/* check the IMSI match */
if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
continue;
if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) == 0) {
dest_match = 1;
break;
}
}
if (!dest_match) {
talloc_free(new_number);
return NULL;
}
return new_number;
}
/**
* Clear the TP-SRR from the TPDU header
*/
static uint8_t sms_new_tpdu_hdr(struct bsc_nat *nat, const char *imsi,
const char *dest_nr, uint8_t hdr)
{
struct bsc_nat_num_rewr_entry *entry;
/* We will find a new number now */
llist_for_each_entry(entry, &nat->sms_clear_tp_srr, list) {
/* check the IMSI match */
if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
continue;
if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) != 0)
continue;
/* matched phone number and imsi */
return hdr & ~0x20;
}
return hdr;
}
/**
* Check if we need to rewrite the number. For this SMS.
*/
static char *sms_new_dest_nr(struct bsc_nat *nat, void *ctx,
const char *imsi, const char *dest_nr)
{
return match_and_rewrite_number(ctx, dest_nr, imsi,
&nat->sms_num_rewr, NULL);
}
/**
* This is a helper for GSM 04.11 8.2.5.2 Destination address element
*/
static bool sms_encode_addr_element(struct msgb *out, const char *new_number,
int format, int tp_data)
{
int new_addr_len;
uint8_t new_addr[26];
/*
* Copy the new number. We let libosmocore encode it, then set
* the extension followed after the length. Depending on if
* we want to write RP we will let the TLV code add the
* length for us or we need to use strlen... This is not very clear
* as of 03.40 and 04.11.
*/
new_addr_len = gsm48_encode_bcd_number(new_addr, ARRAY_SIZE(new_addr),
1, new_number);
if (new_addr_len < 0)
return false;
new_addr[1] = format;
if (tp_data) {
uint8_t *data = msgb_put(out, new_addr_len);
memcpy(data, new_addr, new_addr_len);
data[0] = strlen(new_number);
} else {
msgb_lv_put(out, new_addr_len - 1, new_addr + 1);
}
return true;
}
static struct msgb *sms_create_new(uint8_t type, uint8_t ref,
struct gsm48_hdr *old_hdr48,
const uint8_t *orig_addr_ptr,
int orig_addr_len, const char *new_number,
const uint8_t *data_ptr, int data_len,
uint8_t tpdu_first_byte,
const int old_dest_len, const char *new_dest_nr)
{
struct gsm48_hdr *new_hdr48;
struct msgb *out;
/*
* We need to re-create the patched structure. This is why we have
* saved the above pointers.
*/
out = msgb_alloc_headroom(4096, 128, "changed-smsc");
if (!out) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n");
return NULL;
}
out->l2h = out->data;
msgb_v_put(out, GSM411_MT_RP_DATA_MO);
msgb_v_put(out, ref);
msgb_lv_put(out, orig_addr_len, orig_addr_ptr);
if (!sms_encode_addr_element(out, new_number, 0x91, 0)) {
LOGP(DNAT, LOGL_ERROR, "Failed to encode SMS address.\n");
return NULL;
}
/* Patch the TPDU from here on */
/**
* Do we need to put a new TP-Destination-Address (TP-DA) here or
* can we copy the old thing? For the TP-DA we need to find out the
* new size.
*/
if (new_dest_nr) {
uint8_t *data, *new_size;
/* reserve the size and write the header */
new_size = msgb_put(out, 1);
out->l3h = new_size + 1;
msgb_v_put(out, tpdu_first_byte);
msgb_v_put(out, data_ptr[1]);
/* encode the new number and put it */
if (strncmp(new_dest_nr, "00", 2) == 0) {
if (!sms_encode_addr_element(out, new_dest_nr + 2, 0x91, 1)) {
LOGP(DNAT, LOGL_ERROR, "Failed to encode SMS address.\n");
return NULL;
}
} else {
if (!sms_encode_addr_element(out, new_dest_nr, 0x81, 1)) {
LOGP(DNAT, LOGL_ERROR, "Failed to encode SMS address.\n");
return NULL;
}
}
/* Copy the rest after the TP-DS */
data = msgb_put(out, data_len - 2 - 1 - old_dest_len);
memcpy(data, &data_ptr[2 + 1 + old_dest_len], data_len - 2 - 1 - old_dest_len);
/* fill in the new size */
new_size[0] = msgb_l3len(out);
} else {
msgb_v_put(out, data_len);
msgb_tv_fixed_put(out, tpdu_first_byte, data_len - 1, &data_ptr[1]);
}
/* prepend GSM 04.08 header */
new_hdr48 = (struct gsm48_hdr *) msgb_push(out, sizeof(*new_hdr48) + 1);
memcpy(new_hdr48, old_hdr48, sizeof(*old_hdr48));
new_hdr48->data[0] = msgb_l2len(out);
return out;
}
/**
* Parse the SMS and check if it needs to be rewritten
*/
static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg,
struct bsc_nat_parsed *parsed, const char *imsi,
struct gsm48_hdr *hdr48, const uint32_t len)
{
unsigned int payload_len;
unsigned int cp_len;
uint8_t ref;
uint8_t orig_addr_len, *orig_addr_ptr;
uint8_t dest_addr_len, *dest_addr_ptr;
uint8_t data_len, *data_ptr;
char smsc_addr[30];
uint8_t dest_len, orig_dest_len;
char _dest_nr[30];
char *dest_nr;
char *new_dest_nr;
char *new_number = NULL;
uint8_t tpdu_hdr;
struct msgb *out;
payload_len = len - sizeof(*hdr48);
if (payload_len < 1) {
LOGP(DNAT, LOGL_ERROR, "SMS too short for things. %d\n", payload_len);
return NULL;
}
cp_len = hdr48->data[0];
if (payload_len + 1 < cp_len) {
LOGP(DNAT, LOGL_ERROR, "SMS RPDU can not fit in: %d %d\n", cp_len, payload_len);
return NULL;
}
if (hdr48->data[1] != GSM411_MT_RP_DATA_MO)
return NULL;
if (cp_len < 5) {
LOGP(DNAT, LOGL_ERROR, "RD-DATA can not fit in the CP len: %d\n", cp_len);
return NULL;
}
/* RP */
ref = hdr48->data[2];
orig_addr_len = hdr48->data[3];
orig_addr_ptr = &hdr48->data[4];
/* the +1 is for checking if the following element has some space */
if (cp_len < 3 + orig_addr_len + 1) {
LOGP(DNAT, LOGL_ERROR, "RP-Originator addr does not fit: %d\n", orig_addr_len);
return NULL;
}
dest_addr_len = hdr48->data[3 + orig_addr_len + 1];
dest_addr_ptr = &hdr48->data[3 + orig_addr_len + 2];
if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1) {
LOGP(DNAT, LOGL_ERROR, "RP-Destination addr does not fit: %d\n", dest_addr_len);
return NULL;
}
gsm48_decode_bcd_number(smsc_addr, ARRAY_SIZE(smsc_addr), dest_addr_ptr - 1, 1);
data_len = hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 1];
data_ptr = &hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 2];
if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1 + data_len) {
LOGP(DNAT, LOGL_ERROR, "RP-Data does not fit: %d\n", data_len);
return NULL;
}
if (data_len < 3) {
LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT is too short.\n");
return NULL;
}
/* TP-PDU starts here */
if ((data_ptr[0] & 0x03) != GSM340_SMS_SUBMIT_MS2SC)
return NULL;
/*
* look into the phone number. The length is in semi-octets, we will
* need to add the byte for the number type as well.
*/
orig_dest_len = data_ptr[2];
dest_len = ((orig_dest_len + 1) / 2) + 1;
if (data_len < dest_len + 3 || dest_len < 2) {
LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT can not have TP-DestAddr.\n");
return NULL;
}
if ((data_ptr[3] & 0x80) == 0) {
LOGP(DNAT, LOGL_ERROR, "TP-DestAddr has extension. Not handled.\n");
return NULL;
}
if ((data_ptr[3] & 0x0F) == 0) {
LOGP(DNAT, LOGL_ERROR, "TP-DestAddr is of unknown type.\n");
return NULL;
}
/**
* Besides of what I think I read in GSM 03.40 and 04.11 the TP-DA
* contains the semi-octets as length (strlen), change it to the
* the number of bytes, but then change it back.
*/
data_ptr[2] = dest_len;
gsm48_decode_bcd_number(_dest_nr + 2, ARRAY_SIZE(_dest_nr) - 2,
&data_ptr[2], 1);
data_ptr[2] = orig_dest_len;
if ((data_ptr[3] & 0x70) == 0x10) {
_dest_nr[0] = _dest_nr[1] = '0';
dest_nr = &_dest_nr[0];
} else {
dest_nr = &_dest_nr[2];
}
/**
* Call functions to rewrite the data
*/
tpdu_hdr = sms_new_tpdu_hdr(nat, imsi, dest_nr, data_ptr[0]);
new_number = find_new_smsc(nat, msg, imsi, smsc_addr, dest_nr);
new_dest_nr = sms_new_dest_nr(nat, msg, imsi, dest_nr);
if (tpdu_hdr == data_ptr[0] && !new_number && !new_dest_nr)
return NULL;
out = sms_create_new(GSM411_MT_RP_DATA_MO, ref, hdr48,
orig_addr_ptr, orig_addr_len,
new_number ? new_number : smsc_addr,
data_ptr, data_len, tpdu_hdr,
dest_len, new_dest_nr);
talloc_free(new_number);
talloc_free(new_dest_nr);
return out;
}
struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *parsed, const char *imsi)
{
struct gsm48_hdr *hdr48;
uint32_t len;
uint8_t msg_type, proto;
struct msgb *new_msg = NULL, *sccp;
uint8_t link_id;
if (!imsi || strlen(imsi) < 5)
return msg;
/* only care about DTAP messages */
if (parsed->bssap != BSSAP_MSG_DTAP)
return msg;
if (!parsed->dest_local_ref)
return msg;
hdr48 = bsc_unpack_dtap(parsed, msg, &len);
if (!hdr48)
return msg;
link_id = msg->l3h[1];
proto = gsm48_hdr_pdisc(hdr48);
msg_type = gsm48_hdr_msg_type(hdr48);
if (proto == GSM48_PDISC_CC && msg_type == GSM48_MT_CC_SETUP)
new_msg = rewrite_setup(nat, msg, parsed, imsi, hdr48, len);
else if (proto == GSM48_PDISC_SMS && msg_type == GSM411_MT_CP_DATA)
new_msg = rewrite_sms(nat, msg, parsed, imsi, hdr48, len);
if (!new_msg)
return msg;
/* wrap with DTAP, SCCP, then IPA. TODO: Stop copying */
gsm0808_prepend_dtap_header(new_msg, link_id);
sccp = sccp_create_dt1(parsed->dest_local_ref, new_msg->data, new_msg->len);
talloc_free(new_msg);
if (!sccp) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n");
return msg;
}
ipa_prepend_header(sccp, IPAC_PROTO_SCCP);
/* the parsed hangs off from msg but it needs to survive */
talloc_steal(sccp, parsed);
msgb_free(msg);
return sccp;
}
static void num_rewr_free_data(struct bsc_nat_num_rewr_entry *entry)
{
regfree(&entry->msisdn_reg);
regfree(&entry->num_reg);
talloc_free(entry->replace);
}
void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head,
const struct osmo_config_list *list)
{
struct bsc_nat_num_rewr_entry *entry, *tmp;
struct osmo_config_entry *cfg_entry;
/* free the old data */
llist_for_each_entry_safe(entry, tmp, head, list) {
num_rewr_free_data(entry);
llist_del(&entry->list);
talloc_free(entry);
}
if (!list)
return;
llist_for_each_entry(cfg_entry, &list->entry, list) {
char *regexp;
if (cfg_entry->text[0] == '+') {
LOGP(DNAT, LOGL_ERROR,
"Plus is not allowed in the number\n");
continue;
}
entry = talloc_zero(ctx, struct bsc_nat_num_rewr_entry);
if (!entry) {
LOGP(DNAT, LOGL_ERROR,
"Allocation of the num_rewr entry failed.\n");
continue;
}
entry->replace = talloc_strdup(entry, cfg_entry->text);
if (!entry->replace) {
LOGP(DNAT, LOGL_ERROR,
"Failed to copy the replacement text.\n");
talloc_free(entry);
continue;
}
if (strcmp("prefix_lookup", entry->replace) == 0)
entry->is_prefix_lookup = 1;
/* we will now build a regexp string */
if (cfg_entry->mcc[0] == '^') {
regexp = talloc_strdup(entry, cfg_entry->mcc);
} else {
regexp = talloc_asprintf(entry, "^%s%s",
cfg_entry->mcc[0] == '*' ?
"[0-9][0-9][0-9]" : cfg_entry->mcc,
cfg_entry->mnc[0] == '*' ?
"[0-9][0-9]" : cfg_entry->mnc);
}
if (!regexp) {
LOGP(DNAT, LOGL_ERROR, "Failed to create a regexp string.\n");
talloc_free(entry);
continue;
}
if (regcomp(&entry->msisdn_reg, regexp, 0) != 0) {
LOGP(DNAT, LOGL_ERROR,
"Failed to compile regexp '%s'\n", regexp);
talloc_free(regexp);
talloc_free(entry);
continue;
}
talloc_free(regexp);
if (regcomp(&entry->num_reg, cfg_entry->option, REG_EXTENDED) != 0) {
LOGP(DNAT, LOGL_ERROR,
"Failed to compile regexp '%s'\n", cfg_entry->option);
regfree(&entry->msisdn_reg);
talloc_free(entry);
continue;
}
/* we have copied the number */
llist_add_tail(&entry->list, head);
}
}

View File

@ -1,259 +0,0 @@
/* Handling for loading a re-write file/database */
/*
* (C) 2013 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/bsc/nat_rewrite_trie.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/vty.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define CHECK_IS_DIGIT_OR_FAIL(prefix, pos) \
if (!isdigit(prefix[pos]) && prefix[pos] != '+') { \
LOGP(DNAT, LOGL_ERROR, \
"Prefix(%s) contains non ascii text at(%d=%c)\n", \
prefix, pos, prefix[pos]); \
goto fail; \
}
#define TO_INT(c) \
((c) == '+' ? 10 : ((c - '0') % 10))
static void insert_rewrite_node(struct nat_rewrite_rule *rule, struct nat_rewrite *root)
{
struct nat_rewrite_rule *new = &root->rule;
const int len = strlen(rule->prefix);
int i;
if (len <= 0) {
LOGP(DNAT, LOGL_ERROR, "An empty prefix does not make sense.\n");
goto fail;
}
for (i = 0; i < len - 1; ++i) {
int pos;
/* check if the input is valid */
CHECK_IS_DIGIT_OR_FAIL(rule->prefix, i);
/* check if the next node is already valid */
pos = TO_INT(rule->prefix[i]);
if (!new->rules[pos]) {
new->rules[pos] = talloc_zero(root, struct nat_rewrite_rule);
if (!new->rules[pos]) {
LOGP(DNAT, LOGL_ERROR,
"Failed to allocate memory.\n");
goto fail;
}
new->rules[pos]->empty = 1;
}
/* we continue here */
new = new->rules[pos];
}
/* new now points to the place where we want to add it */
int pos;
/* check if the input is valid */
CHECK_IS_DIGIT_OR_FAIL(rule->prefix, (len - 1));
/* check if the next node is already valid */
pos = TO_INT(rule->prefix[len - 1]);
if (!new->rules[pos])
new->rules[pos] = rule;
else if (new->rules[pos]->empty) {
/* copy over entries */
new->rules[pos]->empty = 0;
memcpy(new->rules[pos]->prefix, rule->prefix, sizeof(rule->prefix));
memcpy(new->rules[pos]->rewrite, rule->rewrite, sizeof(rule->rewrite));
talloc_free(rule);
} else {
LOGP(DNAT, LOGL_ERROR,
"Prefix(%s) is already installed\n", rule->prefix);
goto fail;
}
root->prefixes += 1;
return;
fail:
talloc_free(rule);
return;
}
static void handle_line(struct nat_rewrite *rewrite, char *line)
{
char *split;
struct nat_rewrite_rule *rule;
size_t size_prefix, size_end, len;
/* Find the ',' in the line */
len = strlen(line);
split = strstr(line, ",");
if (!split) {
LOGP(DNAT, LOGL_ERROR, "Line doesn't contain ','\n");
return;
}
/* Check if there is space for the rewrite rule */
size_prefix = split - line;
if (len - size_prefix <= 2) {
LOGP(DNAT, LOGL_ERROR, "No rewrite available.\n");
return;
}
/* Continue after the ',' to the end */
split = &line[size_prefix + 1];
size_end = strlen(split) - 1;
/* Check if both strings can fit into the static array */
if (size_prefix > sizeof(rule->prefix) - 1) {
LOGP(DNAT, LOGL_ERROR,
"Prefix is too long with %zu\n", size_prefix);
return;
}
if (size_end > sizeof(rule->rewrite) - 1) {
LOGP(DNAT, LOGL_ERROR,
"Rewrite is too long with %zu on %s\n",
size_end, &line[size_prefix + 1]);
return;
}
/* Now create the entry and insert it into the trie */
rule = talloc_zero(rewrite, struct nat_rewrite_rule);
if (!rule) {
LOGP(DNAT, LOGL_ERROR, "Can not allocate memory\n");
return;
}
memcpy(rule->prefix, line, size_prefix);
assert(size_prefix < sizeof(rule->prefix));
rule->prefix[size_prefix] = '\0';
memcpy(rule->rewrite, split, size_end);
assert(size_end < sizeof(rule->rewrite));
rule->rewrite[size_end] = '\0';
/* now insert and balance the tree */
insert_rewrite_node(rule, rewrite);
}
struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename)
{
FILE *file;
char *line = NULL;
size_t n = 0;
struct nat_rewrite *res;
file = fopen(filename, "r");
if (!file)
return NULL;
res = talloc_zero(ctx, struct nat_rewrite);
if (!res) {
fclose(file);
return NULL;
}
/* mark the root as empty */
res->rule.empty = 1;
while (getline(&line, &n, file) != -1) {
handle_line(res, line);
}
free(line);
fclose(file);
return res;
}
/**
* Simple find that tries to do a longest match...
*/
struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *rewrite,
const char *prefix)
{
struct nat_rewrite_rule *rule = &rewrite->rule;
struct nat_rewrite_rule *last = NULL;
const int len = OSMO_MIN(strlen(prefix), (sizeof(rule->prefix) - 1));
int i;
for (i = 0; rule && i < len; ++i) {
int pos;
CHECK_IS_DIGIT_OR_FAIL(prefix, i);
pos = TO_INT(prefix[i]);
rule = rule->rules[pos];
if (rule && !rule->empty)
last = rule;
}
return last;
fail:
return NULL;
}
static void nat_rewrite_dump_rec(struct nat_rewrite_rule *rule)
{
int i;
if (!rule->empty)
printf("%s,%s\n", rule->prefix, rule->rewrite);
for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) {
if (!rule->rules[i])
continue;
nat_rewrite_dump_rec(rule->rules[i]);
}
}
void nat_rewrite_dump(struct nat_rewrite *rewrite)
{
nat_rewrite_dump_rec(&rewrite->rule);
}
static void nat_rewrite_dump_rec_vty(struct vty *vty, struct nat_rewrite_rule *rule)
{
int i;
if (!rule->empty)
vty_out(vty, "%s,%s%s", rule->prefix, rule->rewrite, VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) {
if (!rule->rules[i])
continue;
nat_rewrite_dump_rec_vty(vty, rule->rules[i]);
}
}
void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewrite)
{
nat_rewrite_dump_rec_vty(vty, &rewrite->rule);
}

View File

@ -1,535 +0,0 @@
/* BSC Multiplexer/NAT Utilities */
/*
* (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_nat_sccp.h>
#include <osmocom/bsc/bsc_msg_filter.h>
#include <osmocom/bsc/bsc_msc.h>
#include <osmocom/bsc/gsm_data.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/ipaccess.h>
#include <osmocom/bsc/vty.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/stats.h>
#include <osmocom/gsm/gsm0808.h>
#include <osmocom/gsm/ipa.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/protocol/gsm_04_11.h>
#include <osmocom/sccp/sccp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
static const struct rate_ctr_desc bsc_cfg_ctr_description[] = {
[BCFG_CTR_SCCP_CONN] = { "sccp.conn", "SCCP Connections "},
[BCFG_CTR_SCCP_CALLS] = { "sccp.calls", "SCCP Assignment Commands "},
[BCFG_CTR_NET_RECONN] = { "net.reconnects", "Network reconnects "},
[BCFG_CTR_DROPPED_SCCP] = { "dropped.sccp", "Dropped SCCP connections."},
[BCFG_CTR_DROPPED_CALLS] = { "dropped.calls", "Dropped active calls. "},
[BCFG_CTR_REJECTED_CR] = { "rejected.cr", "Rejected CR due filter "},
[BCFG_CTR_REJECTED_MSG] = { "rejected.msg", "Rejected MSG due filter "},
[BCFG_CTR_ILL_PACKET] = { "rejected.ill", "Rejected due parse error "},
[BCFG_CTR_CON_TYPE_LU] = { "conn.lu", "Conn Location Update "},
[BCFG_CTR_CON_CMSERV_RQ] = { "conn.rq", "Conn CM Service Req "},
[BCFG_CTR_CON_PAG_RESP] = { "conn.pag", "Conn Paging Response "},
[BCFG_CTR_CON_SSA] = { "conn.ssa", "Conn USSD "},
[BCFG_CTR_CON_OTHER] = { "conn.other", "Conn Other "},
};
static const struct rate_ctr_group_desc bsc_cfg_ctrg_desc = {
.group_name_prefix = "nat.bsc",
.group_description = "NAT BSC Statistics",
.num_ctr = ARRAY_SIZE(bsc_cfg_ctr_description),
.ctr_desc = bsc_cfg_ctr_description,
.class_id = OSMO_STATS_CLASS_PEER,
};
struct bsc_nat *bsc_nat_alloc(void)
{
struct bsc_nat *nat = talloc_zero(tall_bsc_ctx, struct bsc_nat);
if (!nat)
return NULL;
nat->main_dest = talloc_zero(nat, struct bsc_msc_dest);
if (!nat->main_dest) {
talloc_free(nat);
return NULL;
}
INIT_LLIST_HEAD(&nat->sccp_connections);
INIT_LLIST_HEAD(&nat->bsc_connections);
INIT_LLIST_HEAD(&nat->paging_groups);
INIT_LLIST_HEAD(&nat->bsc_configs);
INIT_LLIST_HEAD(&nat->access_lists);
INIT_LLIST_HEAD(&nat->dests);
INIT_LLIST_HEAD(&nat->num_rewr);
INIT_LLIST_HEAD(&nat->num_rewr_post);
INIT_LLIST_HEAD(&nat->smsc_rewr);
INIT_LLIST_HEAD(&nat->tpdest_match);
INIT_LLIST_HEAD(&nat->sms_clear_tp_srr);
INIT_LLIST_HEAD(&nat->sms_num_rewr);
nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn");
nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls");
nat->stats.bsc.reconn = osmo_counter_alloc("nat.bsc.conn");
nat->stats.bsc.auth_fail = osmo_counter_alloc("nat.bsc.auth_fail");
nat->stats.msc.reconn = osmo_counter_alloc("nat.msc.conn");
nat->stats.ussd.reconn = osmo_counter_alloc("nat.ussd.conn");
nat->auth_timeout = 2;
nat->ping_timeout = 20;
nat->pong_timeout = 5;
llist_add(&nat->main_dest->list, &nat->dests);
nat->main_dest->ip = talloc_strdup(nat, "127.0.0.1");
nat->main_dest->port = 5000;
return nat;
}
void bsc_nat_free(struct bsc_nat *nat)
{
struct bsc_config *cfg, *tmp;
struct bsc_msg_acc_lst *lst, *tmp_lst;
llist_for_each_entry_safe(cfg, tmp, &nat->bsc_configs, entry)
bsc_config_free(cfg);
llist_for_each_entry_safe(lst, tmp_lst, &nat->access_lists, list)
bsc_msg_acc_lst_delete(lst);
bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL);
bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, NULL);
bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, NULL);
bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_num_rewr, NULL);
bsc_nat_num_rewr_entry_adapt(nat, &nat->tpdest_match, NULL);
osmo_counter_free(nat->stats.sccp.conn);
osmo_counter_free(nat->stats.sccp.calls);
osmo_counter_free(nat->stats.bsc.reconn);
osmo_counter_free(nat->stats.bsc.auth_fail);
osmo_counter_free(nat->stats.msc.reconn);
osmo_counter_free(nat->stats.ussd.reconn);
talloc_free(nat->mgcp_cfg);
talloc_free(nat);
}
void bsc_nat_set_msc_ip(struct bsc_nat *nat, const char *ip)
{
osmo_talloc_replace_string(nat, &nat->main_dest->ip, ip);
}
struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat)
{
struct bsc_connection *con = talloc_zero(nat, struct bsc_connection);
if (!con)
return NULL;
con->nat = nat;
osmo_wqueue_init(&con->write_queue, 100);
INIT_LLIST_HEAD(&con->cmd_pending);
INIT_LLIST_HEAD(&con->pending_dlcx);
return con;
}
struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token,
unsigned int number)
{
struct bsc_config *conf = talloc_zero(nat, struct bsc_config);
if (!conf)
return NULL;
conf->token = talloc_strdup(conf, token);
conf->nr = number;
conf->nat = nat;
conf->max_endpoints = 32;
conf->paging_group = PAGIN_GROUP_UNASSIGNED;
INIT_LLIST_HEAD(&conf->lac_list);
llist_add_tail(&conf->entry, &nat->bsc_configs);
++nat->num_bsc;
conf->stats.ctrg = rate_ctr_group_alloc(conf, &bsc_cfg_ctrg_desc, conf->nr);
if (!conf->stats.ctrg) {
llist_del(&conf->entry);
talloc_free(conf);
return NULL;
}
return conf;
}
struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len)
{
struct bsc_config *conf;
llist_for_each_entry(conf, &nat->bsc_configs, entry) {
/*
* Add the '\0' of the token for the memcmp, the IPA messages
* for some reason added null termination.
*/
const int token_len = strlen(conf->token) + 1;
if (token_len == len && memcmp(conf->token, token, token_len) == 0)
return conf;
}
return NULL;
}
void bsc_config_free(struct bsc_config *cfg)
{
llist_del(&cfg->entry);
rate_ctr_group_free(cfg->stats.ctrg);
cfg->nat->num_bsc--;
OSMO_ASSERT(cfg->nat->num_bsc >= 0);
talloc_free(cfg);
}
static void _add_lac(void *ctx, struct llist_head *list, int _lac)
{
struct bsc_lac_entry *lac;
llist_for_each_entry(lac, list, entry)
if (lac->lac == _lac)
return;
lac = talloc_zero(ctx, struct bsc_lac_entry);
if (!lac) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n");
return;
}
lac->lac = _lac;
llist_add_tail(&lac->entry, list);
}
static void _del_lac(struct llist_head *list, int _lac)
{
struct bsc_lac_entry *lac;
llist_for_each_entry(lac, list, entry)
if (lac->lac == _lac) {
llist_del(&lac->entry);
talloc_free(lac);
return;
}
}
void bsc_config_add_lac(struct bsc_config *cfg, int _lac)
{
_add_lac(cfg, &cfg->lac_list, _lac);
}
void bsc_config_del_lac(struct bsc_config *cfg, int _lac)
{
_del_lac(&cfg->lac_list, _lac);
}
struct bsc_nat_paging_group *bsc_nat_paging_group_create(struct bsc_nat *nat, int group)
{
struct bsc_nat_paging_group *pgroup;
pgroup = talloc_zero(nat, struct bsc_nat_paging_group);
if (!pgroup) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate a paging group.\n");
return NULL;
}
pgroup->nr = group;
INIT_LLIST_HEAD(&pgroup->lists);
llist_add_tail(&pgroup->entry, &nat->paging_groups);
return pgroup;
}
void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *pgroup)
{
llist_del(&pgroup->entry);
talloc_free(pgroup);
}
struct bsc_nat_paging_group *bsc_nat_paging_group_num(struct bsc_nat *nat, int group)
{
struct bsc_nat_paging_group *pgroup;
llist_for_each_entry(pgroup, &nat->paging_groups, entry)
if (pgroup->nr == group)
return pgroup;
return NULL;
}
void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *pgroup, int lac)
{
_add_lac(pgroup, &pgroup->lists, lac);
}
void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *pgroup, int lac)
{
_del_lac(&pgroup->lists, lac);
}
int bsc_config_handles_lac(struct bsc_config *cfg, int lac_nr)
{
struct bsc_nat_paging_group *pgroup;
struct bsc_lac_entry *entry;
llist_for_each_entry(entry, &cfg->lac_list, entry)
if (entry->lac == lac_nr)
return 1;
/* now lookup the paging group */
pgroup = bsc_nat_paging_group_num(cfg->nat, cfg->paging_group);
if (!pgroup)
return 0;
llist_for_each_entry(entry, &pgroup->lists, entry)
if (entry->lac == lac_nr)
return 1;
return 0;
}
void sccp_connection_destroy(struct nat_sccp_connection *conn)
{
LOGP(DNAT, LOGL_DEBUG, "Destroy 0x%x <-> 0x%x mapping for con %p\n",
sccp_src_ref_to_int(&conn->real_ref),
sccp_src_ref_to_int(&conn->patched_ref), conn->bsc);
bsc_mgcp_dlcx(conn);
llist_del(&conn->list_entry);
talloc_free(conn);
}
int bsc_nat_find_paging(struct msgb *msg,
const uint8_t **out_data, int *out_leng)
{
int data_length;
const uint8_t *data;
struct tlv_parsed tp;
if (!msg->l3h || msgb_l3len(msg) < 3) {
LOGP(DNAT, LOGL_ERROR, "Paging message is too short.\n");
return -1;
}
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n");
return -2;
}
data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
/* No need to try a different BSS */
if (data[0] == CELL_IDENT_BSS) {
return -3;
} else if (data[0] != CELL_IDENT_LAC) {
LOGP(DNAT, LOGL_ERROR, "Unhandled cell ident discrminator: %d\n", data[0]);
return -4;
}
*out_data = &data[1];
*out_leng = data_length - 1;
return 0;
}
int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length)
{
struct msgb *msg;
if (length > 4096 - 128) {
LOGP(DLINP, LOGL_ERROR, "Can not send message of that size.\n");
return -1;
}
msg = msgb_alloc_headroom(4096, 128, "to-bsc");
if (!msg) {
LOGP(DLINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
return -1;
}
/* copy the data */
msg->l3h = msgb_put(msg, length);
memcpy(msg->l3h, data, length);
return bsc_write(bsc, msg, IPAC_PROTO_MGCP_OLD);
}
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
{
return bsc_do_write(&bsc->write_queue, msg, proto);
}
int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int proto)
{
/* prepend the header */
ipa_prepend_header(msg, proto);
return bsc_write_msg(queue, msg);
}
int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg)
{
if (osmo_wqueue_enqueue(queue, msg) != 0) {
LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the write.\n");
msgb_free(msg);
return -1;
}
return 0;
}
struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed,
struct msgb *msg, uint32_t *len)
{
/* gsm_type is actually the size of the dtap */
*len = parsed->gsm_type;
if (*len < msgb_l3len(msg) - 3) {
LOGP(DNAT, LOGL_ERROR, "Not enough space for DTAP.\n");
return NULL;
}
if (msgb_l3len(msg) - 3 < msg->l3h[2]) {
LOGP(DNAT, LOGL_ERROR,
"GSM48 payload does not fit: %d %d\n",
msg->l3h[2], msgb_l3len(msg) - 3);
return NULL;
}
msg->l4h = &msg->l3h[3];
return (struct gsm48_hdr *) msg->l4h;
}
static const char *con_types [] = {
[FLT_CON_TYPE_NONE] = "n/a",
[FLT_CON_TYPE_LU] = "Location Update",
[FLT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req",
[FLT_CON_TYPE_PAG_RESP] = "Paging Response",
[FLT_CON_TYPE_SSA] = "Supplementar Service Activation",
[FLT_CON_TYPE_LOCAL_REJECT] = "Local Reject",
[FLT_CON_TYPE_OTHER] = "Other",
};
const char *bsc_con_type_to_string(int type)
{
return con_types[type];
}
int bsc_nat_msc_is_connected(struct bsc_nat *nat)
{
return nat->msc_con->is_connected;
}
static const int con_to_ctr[] = {
[FLT_CON_TYPE_NONE] = -1,
[FLT_CON_TYPE_LU] = BCFG_CTR_CON_TYPE_LU,
[FLT_CON_TYPE_CM_SERV_REQ] = BCFG_CTR_CON_CMSERV_RQ,
[FLT_CON_TYPE_PAG_RESP] = BCFG_CTR_CON_PAG_RESP,
[FLT_CON_TYPE_SSA] = BCFG_CTR_CON_SSA,
[FLT_CON_TYPE_LOCAL_REJECT] = -1,
[FLT_CON_TYPE_OTHER] = BCFG_CTR_CON_OTHER,
};
int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn)
{
return con_to_ctr[conn->filter_state.con_type];
}
int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg)
{
int rc;
rc = write(bfd->fd, msg->data, msg->len);
if (rc != msg->len)
LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n");
return rc;
}
static void extract_lac(const uint8_t *data, uint16_t *lac, uint16_t *ci)
{
memcpy(lac, &data[0], sizeof(*lac));
memcpy(ci, &data[2], sizeof(*ci));
*lac = ntohs(*lac);
*ci = ntohs(*ci);
}
int bsc_nat_extract_lac(struct bsc_connection *bsc,
struct nat_sccp_connection *con,
struct bsc_nat_parsed *parsed, struct msgb *msg)
{
int data_length;
const uint8_t *data;
struct tlv_parsed tp;
uint16_t lac, ci;
if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
LOGP(DNAT, LOGL_ERROR, "Can only extract LAC from Complete Layer3\n");
return -1;
}
if (!msg->l3h || msgb_l3len(msg) < 3) {
LOGP(DNAT, LOGL_ERROR, "Complete Layer3 mssage is too short.\n");
return -1;
}
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)) {
LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n");
return -2;
}
data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER);
data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER);
/* Attemt to get the LAC/CI from it */
if (data[0] == CELL_IDENT_WHOLE_GLOBAL) {
if (data_length != 8) {
LOGP(DNAT, LOGL_ERROR,
"Ident too short: %d\n", data_length);
return -3;
}
extract_lac(&data[1 + 3], &lac, &ci);
} else if (data[0] == CELL_IDENT_LAC_AND_CI) {
if (data_length != 5) {
LOGP(DNAT, LOGL_ERROR,
"Ident too short: %d\n", data_length);
return -3;
}
extract_lac(&data[1], &lac, &ci);
} else {
LOGP(DNAT, LOGL_ERROR,
"Unhandled cell identifier: %d\n", data[0]);
return -1;
}
con->lac = lac;
con->ci = ci;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,247 +0,0 @@
/* SCCP patching and handling routines */
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/bsc/debug.h>
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_nat_sccp.h>
#include <osmocom/sccp/sccp.h>
#include <osmocom/core/talloc.h>
#include <string.h>
#include <time.h>
static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2)
{
return memcmp(ref1, ref2, sizeof(*ref1)) == 0;
}
/*
* SCCP patching below
*/
/* check if we are using this ref for patched already */
static int sccp_ref_is_free(struct sccp_source_reference *ref, struct bsc_nat *nat)
{
struct nat_sccp_connection *conn;
llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
if (equal(ref, &conn->patched_ref))
return -1;
}
return 0;
}
/* copied from sccp.c */
static int assign_src_local_reference(struct sccp_source_reference *ref, struct bsc_nat *nat)
{
static uint32_t last_ref = 0x50000;
int wrapped = 0;
do {
struct sccp_source_reference reference;
reference.octet1 = (last_ref >> 0) & 0xff;
reference.octet2 = (last_ref >> 8) & 0xff;
reference.octet3 = (last_ref >> 16) & 0xff;
++last_ref;
/* do not use the reversed word and wrap around */
if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) {
LOGP(DNAT, LOGL_NOTICE, "Wrapped searching for a free code\n");
last_ref = 0;
++wrapped;
}
if (sccp_ref_is_free(&reference, nat) == 0) {
*ref = reference;
return 0;
}
} while (wrapped != 2);
LOGP(DNAT, LOGL_ERROR, "Finding a free reference failed\n");
return -1;
}
struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc,
struct bsc_nat_parsed *parsed)
{
struct nat_sccp_connection *conn;
/* Some commercial BSCs like to reassign there SRC ref */
llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
if (conn->bsc != bsc)
continue;
if (!equal(parsed->src_local_ref, &conn->real_ref))
continue;
/* the BSC has reassigned the SRC ref and we failed to keep track */
memset(&conn->remote_ref, 0, sizeof(conn->remote_ref));
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n",
bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref));
bsc_mgcp_dlcx(conn);
llist_del(&conn->list_entry);
talloc_free(conn);
return NULL;
} else {
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
bsc_mgcp_dlcx(conn);
return conn;
}
}
conn = talloc_zero(bsc->nat, struct nat_sccp_connection);
if (!conn) {
LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
return NULL;
}
conn->bsc = bsc;
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
conn->real_ref = *parsed->src_local_ref;
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
talloc_free(conn);
return NULL;
}
bsc_mgcp_init(conn);
llist_add_tail(&conn->list_entry, &bsc->nat->sccp_connections);
rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_SCCP_CONN]);
osmo_counter_inc(bsc->cfg->nat->stats.sccp.conn);
LOGP(DNAT, LOGL_DEBUG, "Created 0x%x <-> 0x%x mapping for con %p\n",
sccp_src_ref_to_int(&conn->real_ref),
sccp_src_ref_to_int(&conn->patched_ref), bsc);
return conn;
}
int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed)
{
if (!parsed->dest_local_ref || !parsed->src_local_ref) {
LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n");
return -1;
}
sccp->remote_ref = *parsed->src_local_ref;
sccp->has_remote_ref = 1;
LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n",
sccp_src_ref_to_int(&sccp->patched_ref),
sccp_src_ref_to_int(&sccp->remote_ref), sccp->bsc);
return 0;
}
void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
{
struct nat_sccp_connection *conn;
llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
if (equal(parsed->src_local_ref, &conn->patched_ref)) {
sccp_connection_destroy(conn);
return;
}
}
LOGP(DNAT, LOGL_ERROR, "Can not remove connection: 0x%x\n",
sccp_src_ref_to_int(parsed->src_local_ref));
}
/*
* We have a message from the MSC to the BSC. The MSC is using
* an address that was assigned by the MUX, we need to update the
* dest reference to the real network.
*/
struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg,
struct bsc_nat_parsed *parsed,
struct bsc_nat *nat)
{
struct nat_sccp_connection *conn;
if (!parsed->dest_local_ref) {
LOGP(DNAT, LOGL_ERROR, "MSG should contain dest_local_ref.\n");
return NULL;
}
llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
if (!equal(parsed->dest_local_ref, &conn->patched_ref))
continue;
/* Change the dest address to the real one */
*parsed->dest_local_ref = conn->real_ref;
return conn;
}
return NULL;
}
/*
* These are message to the MSC. We will need to find the BSC
* Connection by either the SRC or the DST local reference.
*
* In case of a CR we need to work by the SRC local reference
* in all other cases we need to work by the destination local
* reference..
*/
struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *msg,
struct bsc_nat_parsed *parsed,
struct bsc_connection *bsc)
{
struct nat_sccp_connection *conn;
llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
if (conn->bsc != bsc)
continue;
if (parsed->src_local_ref) {
if (equal(parsed->src_local_ref, &conn->real_ref)) {
*parsed->src_local_ref = conn->patched_ref;
return conn;
}
} else if (parsed->dest_local_ref) {
if (equal(parsed->dest_local_ref, &conn->remote_ref))
return conn;
} else {
LOGP(DNAT, LOGL_ERROR, "Header has neither loc/dst ref.\n");
return NULL;
}
}
return NULL;
}
struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *nat,
struct sccp_source_reference *ref)
{
struct nat_sccp_connection *conn;
llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
if (equal(ref, &conn->real_ref))
return conn;
}
return NULL;
}

View File

@ -1,452 +0,0 @@
/* USSD Filter Code */
/*
* (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2011 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/core/socket.h>
#include <osmocom/bsc/bsc_nat.h>
#include <osmocom/bsc/bsc_nat_sccp.h>
#include <osmocom/bsc/bsc_msg_filter.h>
#include <osmocom/bsc/ipaccess.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm0480.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/gsm/ipa.h>
#include <osmocom/gsm/gsm0480.h>
#include <osmocom/sccp/sccp.h>
#include <osmocom/abis/ipa.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#define USSD_LAC_IE 0
#define USSD_CI_IE 1
static void ussd_auth_con(struct tlv_parsed *, struct bsc_nat_ussd_con *);
static struct bsc_nat_ussd_con *bsc_nat_ussd_alloc(struct bsc_nat *nat)
{
struct bsc_nat_ussd_con *con;
con = talloc_zero(nat, struct bsc_nat_ussd_con);
if (!con)
return NULL;
con->nat = nat;
return con;
}
static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con)
{
if (con->nat->ussd_con == con) {
bsc_ussd_close_connections(con->nat);
con->nat->ussd_con = NULL;
}
close(con->queue.bfd.fd);
osmo_fd_unregister(&con->queue.bfd);
osmo_timer_del(&con->auth_timeout);
osmo_wqueue_clear(&con->queue);
msgb_free(con->pending_msg);
talloc_free(con);
}
static void ussd_pong(struct bsc_nat_ussd_con *conn)
{
struct msgb *msg;
msg = msgb_alloc_headroom(4096, 128, "pong message");
if (!msg) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate pong msg\n");
return;
}
msgb_v_put(msg, IPAC_MSGT_PONG);
bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS);
}
static int forward_sccp(struct bsc_nat *nat, struct msgb *msg)
{
struct nat_sccp_connection *con;
struct bsc_nat_parsed *parsed;
parsed = bsc_nat_parse(msg);
if (!parsed) {
LOGP(DNAT, LOGL_ERROR, "Can not parse msg from USSD.\n");
msgb_free(msg);
return -1;
}
if (!parsed->dest_local_ref) {
LOGP(DNAT, LOGL_ERROR, "No destination local reference.\n");
msgb_free(msg);
return -1;
}
con = bsc_nat_find_con_by_bsc(nat, parsed->dest_local_ref);
if (!con || !con->bsc) {
LOGP(DNAT, LOGL_ERROR, "No active connection found.\n");
msgb_free(msg);
return -1;
}
talloc_free(parsed);
bsc_write_msg(&con->bsc->write_queue, msg);
return 0;
}
static int ussd_read_cb(struct osmo_fd *bfd)
{
struct bsc_nat_ussd_con *conn = bfd->data;
struct msgb *msg = NULL;
struct ipaccess_head *hh;
int ret;
ret = ipa_msg_recv_buffered(bfd->fd, &msg, &conn->pending_msg);
if (ret <= 0) {
if (ret == -EAGAIN)
return 0;
LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n");
bsc_nat_ussd_destroy(conn);
return -1;
}
LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n",
osmo_hexdump(msg->data, msg->len), msg->l2h[0]);
hh = (struct ipaccess_head *) msg->data;
if (hh->proto == IPAC_PROTO_IPACCESS) {
if (msg->l2h[0] == IPAC_MSGT_ID_RESP) {
struct tlv_parsed tvp;
int ret;
ret = ipa_ccm_idtag_parse(&tvp,
(unsigned char *) msg->l2h + 2,
msgb_l2len(msg) - 2);
if (ret < 0) {
LOGP(DNAT, LOGL_ERROR, "ignoring IPA response "
"message with malformed TLVs\n");
msgb_free(msg);
return ret;
}
if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME))
ussd_auth_con(&tvp, conn);
} else if (msg->l2h[0] == IPAC_MSGT_PING) {
LOGP(DNAT, LOGL_DEBUG, "Got USSD ping request.\n");
ussd_pong(conn);
} else {
LOGP(DNAT, LOGL_NOTICE, "Got unknown IPACCESS message 0x%02x.\n", msg->l2h[0]);
}
msgb_free(msg);
} else if (hh->proto == IPAC_PROTO_SCCP) {
forward_sccp(conn->nat, msg);
} else {
msgb_free(msg);
}
return 0;
}
static void ussd_auth_cb(void *_data)
{
LOGP(DNAT, LOGL_ERROR, "USSD module didn't authenticate\n");
bsc_nat_ussd_destroy((struct bsc_nat_ussd_con *) _data);
}
static void ussd_auth_con(struct tlv_parsed *tvp, struct bsc_nat_ussd_con *conn)
{
const char *token;
int len;
if (!conn->nat->ussd_token) {
LOGP(DNAT, LOGL_ERROR, "No USSD token set. Closing\n");
bsc_nat_ussd_destroy(conn);
return;
}
token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME);
/* last byte should be a NULL */
if (strlen(conn->nat->ussd_token) != len - 1)
goto disconnect;
/* compare everything including the null byte */
if (memcmp(conn->nat->ussd_token, token, len) != 0)
goto disconnect;
/* it is authenticated now */
if (conn->nat->ussd_con && conn->nat->ussd_con != conn)
bsc_nat_ussd_destroy(conn->nat->ussd_con);
LOGP(DNAT, LOGL_ERROR, "USSD token specified. USSD provider is connected.\n");
osmo_timer_del(&conn->auth_timeout);
conn->authorized = 1;
conn->nat->ussd_con = conn;
return;
disconnect:
LOGP(DNAT, LOGL_ERROR, "Wrong USSD token by client: %d\n",
conn->queue.bfd.fd);
bsc_nat_ussd_destroy(conn);
}
static void ussd_start_auth(struct bsc_nat_ussd_con *conn)
{
struct msgb *msg;
osmo_timer_setup(&conn->auth_timeout, ussd_auth_cb, conn);
osmo_timer_schedule(&conn->auth_timeout, conn->nat->auth_timeout, 0);
msg = msgb_alloc_headroom(4096, 128, "auth message");
if (!msg) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate auth msg\n");
return;
}
msgb_v_put(msg, IPAC_MSGT_ID_GET);
bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS);
}
static int ussd_listen_cb(struct osmo_fd *bfd, unsigned int what)
{
struct bsc_nat_ussd_con *conn;
struct bsc_nat *nat;
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
int fd;
if (!(what & BSC_FD_READ))
return 0;
fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (fd < 0) {
perror("accept");
return fd;
}
nat = (struct bsc_nat *) bfd->data;
osmo_counter_inc(nat->stats.ussd.reconn);
conn = bsc_nat_ussd_alloc(nat);
if (!conn) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate USSD con struct.\n");
close(fd);
return -1;
}
osmo_wqueue_init(&conn->queue, 10);
conn->queue.bfd.data = conn;
conn->queue.bfd.fd = fd;
conn->queue.bfd.when = BSC_FD_READ;
conn->queue.read_cb = ussd_read_cb;
conn->queue.write_cb = bsc_write_cb;
if (osmo_fd_register(&conn->queue.bfd) < 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to register USSD fd.\n");
bsc_nat_ussd_destroy(conn);
return -1;
}
LOGP(DNAT, LOGL_NOTICE, "USSD Connection on %d with IP: %s\n",
fd, inet_ntoa(sa.sin_addr));
/* do authentication */
ussd_start_auth(conn);
return 0;
}
int bsc_ussd_init(struct bsc_nat *nat)
{
nat->ussd_listen.cb = ussd_listen_cb;
nat->ussd_listen.data = nat;
return osmo_sock_init_ofd(&nat->ussd_listen, AF_INET, SOCK_STREAM, IPPROTO_TCP,
nat->ussd_local, 5001, OSMO_SOCK_F_BIND);
}
static int forward_ussd_simple(struct nat_sccp_connection *con, struct msgb *input)
{
struct msgb *copy;
struct bsc_nat_ussd_con *ussd;
if (!con->bsc->nat->ussd_con)
return -1;
copy = msgb_alloc_headroom(4096, 128, "forward bts");
if (!copy) {
LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n");
return -1;
}
/* copy the data into the copy */
copy->l2h = msgb_put(copy, msgb_l2len(input));
memcpy(copy->l2h, input->l2h, msgb_l2len(input));
/* send it out */
ussd = con->bsc->nat->ussd_con;
bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP);
return 0;
}
static int forward_ussd(struct nat_sccp_connection *con, const struct ussd_request *req,
struct msgb *input)
{
struct msgb *msg, *copy;
struct ipac_msgt_sccp_state *state;
struct bsc_nat_ussd_con *ussd;
uint16_t lac, ci;
if (!con->bsc->nat->ussd_con)
return -1;
msg = msgb_alloc_headroom(4096, 128, "forward ussd");
if (!msg) {
LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n");
return -1;
}
copy = msgb_alloc_headroom(4096, 128, "forward bts");
if (!copy) {
LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n");
msgb_free(msg);
return -1;
}
copy->l2h = msgb_put(copy, msgb_l2len(input));
memcpy(copy->l2h, input->l2h, msgb_l2len(input));
msg->l2h = msgb_put(msg, 1);
msg->l2h[0] = IPAC_MSGT_SCCP_OLD;
/* fill out the data */
state = (struct ipac_msgt_sccp_state *) msgb_put(msg, sizeof(*state));
state->trans_id = req->transaction_id;
state->invoke_id = req->invoke_id;
memcpy(&state->src_ref, &con->remote_ref, sizeof(con->remote_ref));
memcpy(&state->dst_ref, &con->real_ref, sizeof(con->real_ref));
memcpy(state->imsi, con->filter_state.imsi, strlen(con->filter_state.imsi));
/* add additional tag/values */
lac = htons(con->lac);
ci = htons(con->ci);
msgb_tv_fixed_put(msg, USSD_LAC_IE, sizeof(lac), (const uint8_t *) &lac);
msgb_tv_fixed_put(msg, USSD_CI_IE, sizeof(ci), (const uint8_t *) &ci);
ussd = con->bsc->nat->ussd_con;
bsc_do_write(&ussd->queue, msg, IPAC_PROTO_IPACCESS);
bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP);
return 0;
}
int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed,
struct msgb *msg)
{
uint32_t len;
uint8_t msg_type;
uint8_t proto;
uint8_t ti;
struct gsm48_hdr *hdr48;
struct bsc_msg_acc_lst *lst;
struct ussd_request req;
/*
* various checks to avoid the decoding work. Right now we only want to
* decode if the connection was created for USSD, we do have a USSD access
* list, a query, a IMSI and such...
*/
if (con->filter_state.con_type != FLT_CON_TYPE_SSA)
return 0;
if (!con->filter_state.imsi)
return 0;
/* We have not verified the IMSI yet */
if (!con->authorized)
return 0;
if (!con->bsc->nat->ussd_lst_name)
return 0;
if (!con->bsc->nat->ussd_query)
return 0;
if (parsed->bssap != BSSAP_MSG_DTAP)
return 0;
if (strlen(con->filter_state.imsi) > GSM23003_IMSI_MAX_DIGITS)
return 0;
hdr48 = bsc_unpack_dtap(parsed, msg, &len);
if (!hdr48)
return 0;
proto = gsm48_hdr_pdisc(hdr48);
msg_type = gsm48_hdr_msg_type(hdr48);
ti = gsm48_hdr_trans_id_no_ti(hdr48);
if (proto != GSM48_PDISC_NC_SS)
return 0;
if (msg_type == GSM0480_MTYPE_REGISTER) {
/* now check if it is a IMSI we care about */
lst = bsc_msg_acc_lst_find(&con->bsc->nat->access_lists,
con->bsc->nat->ussd_lst_name);
if (!lst)
return 0;
if (bsc_msg_acc_lst_check_allow(lst, con->filter_state.imsi) != 0)
return 0;
/* now decode the message and see if we really want to handle it */
memset(&req, 0, sizeof(req));
if (gsm0480_decode_ussd_request(hdr48, len, &req) != 1)
return 0;
if (req.text[0] == 0xff)
return 0;
if (regexec(&con->bsc->nat->ussd_query_re,
req.text, 0, NULL, 0) == REG_NOMATCH)
return 0;
/* found a USSD query for our subscriber */
LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n",
con->filter_state.imsi);
con->ussd_ti[ti] = 1;
if (forward_ussd(con, &req, msg) != 0)
return 0;
return 1;
} else if (msg_type == GSM0480_MTYPE_FACILITY && con->ussd_ti[ti]) {
LOGP(DNAT, LOGL_NOTICE, "Forwarding message part of TI: %d %s\n",
ti, con->filter_state.imsi);
if (forward_ussd_simple(con, msg) != 0)
return 0;
return 1;
}
return 0;
}

View File

@ -5,8 +5,6 @@ SUBDIRS = \
abis \
subscr \
nanobts_omlattr \
bsc-nat \
bsc-nat-trie \
bssap \
handover \
$(NULL)

View File

@ -1,19 +0,0 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) \
$(LIBOSMOLEGACYMGCP_CFLAGS) \
$(NULL)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
EXTRA_DIST = bsc_nat_trie_test.ok prefixes.csv
noinst_PROGRAMS = bsc_nat_trie_test
bsc_nat_trie_test_SOURCES = bsc_nat_trie_test.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c
bsc_nat_trie_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -lrt \
$(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMOLEGACYMGCP_LIBS) \
$(LIBRARY_GSM) \
$(NULL)

View File

@ -1,95 +0,0 @@
/*
* (C) 2013 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/bsc/nat_rewrite_trie.h>
#include <osmocom/bsc/debug.h>
#include <osmocom/core/application.h>
#include <osmocom/core/backtrace.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <string.h>
static const struct log_info_cat log_categories[] = {
};
static const struct log_info log_info = {
.cat = log_categories,
.num_cat = ARRAY_SIZE(log_categories),
};
int main(int argc, char **argv)
{
struct nat_rewrite *trie;
void *tall_ctx = talloc_named_const(NULL, 1, "bsc_nat_trie_test");
osmo_init_logging2(tall_ctx, &log_info);
printf("Testing the trie\n");
trie = nat_rewrite_parse(NULL, "prefixes.csv");
OSMO_ASSERT(trie);
/* verify that it has been parsed */
OSMO_ASSERT(trie->prefixes == 17);
printf("Dumping the internal trie\n");
nat_rewrite_dump(trie);
/* now do the matching... */
OSMO_ASSERT(!nat_rewrite_lookup(trie, ""));
OSMO_ASSERT(!nat_rewrite_lookup(trie, "2"));
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1")->rewrite, "1") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12")->rewrite, "2") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123")->rewrite, "3") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234")->rewrite, "4") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345")->rewrite, "5") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123456")->rewrite, "6") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234567")->rewrite, "7") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678")->rewrite, "8") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123456789")->rewrite, "9") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234567890")->rewrite, "10") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "13")->rewrite, "11") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "14")->rewrite, "12") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "15")->rewrite, "13") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "16")->rewrite, "14") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "823455")->rewrite, "15") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "82")->rewrite, "16") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "+49123445")->rewrite, "17") == 0);
/* match a prefix */
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "121")->rewrite, "2") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1292323")->rewrite, "2") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678901")->rewrite, "10") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "160")->rewrite, "14") == 0);
OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678901123452123123")->rewrite, "10") == 0);
/* invalid input */
OSMO_ASSERT(!nat_rewrite_lookup(trie, "12abc"));
talloc_free(trie);
trie = nat_rewrite_parse(NULL, "does_not_exist.csv");
OSMO_ASSERT(!trie);
printf("Done with the tests.\n");
return 0;
}

View File

@ -1,20 +0,0 @@
Testing the trie
Dumping the internal trie
1,1
12,2
123,3
1234,4
12345,5
123456,6
1234567,7
12345678,8
123456789,9
1234567890,10
13,11
14,12
15,13
16,14
82,16
823455,15
+49123,17
Done with the tests.

View File

@ -1,25 +0,0 @@
1,1
12,2
123,3
1234,4
12345,5
123456,6
1234567,7
12345678,8
123456789,9
1234567890,10
13,11
14,12
15,13
16,14
823455,15
82,16
+49123,17
1ABC,18
12345678901234567890,19
,20
14A,21
124,324324324234
1234567890,10
no line
99,
Can't render this file because it has a wrong number of fields in line 24.

View File

@ -1,58 +0,0 @@
AM_CPPFLAGS = \
$(all_includes) \
-I$(top_srcdir)/include \
$(NULL)
AM_CFLAGS = \
-Wall \
-ggdb3 \
$(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOSCCP_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) \
$(LIBOSMONETIF_CFLAGS) \
$(LIBOSMOLEGACYMGCP_CFLAGS) \
$(COVERAGE_CFLAGS) \
$(NULL)
AM_LDFLAGS = \
$(COVERAGE_LDFLAGS) \
$(NULL)
EXTRA_DIST = \
bsc_nat_test.ok \
bsc_data.c \
barr.cfg \
barr_dup.cfg \
prefixes.csv \
$(NULL)
noinst_PROGRAMS = \
bsc_nat_test \
$(NULL)
bsc_nat_test_SOURCES = \
bsc_nat_test.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_filter.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_sccp.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_nat_utils.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_mgcp_utils.c \
$(top_srcdir)/src/osmo-bsc_nat/bsc_nat_filter.c
bsc_nat_test_LDADD = \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) \
$(LIBOSMOSCCP_LIBS) \
$(LIBOSMOVTY_LIBS) \
$(LIBOSMOABIS_LIBS) \
$(LIBOSMONETIF_LIBS) \
$(LIBOSMOCTRL_LIBS) \
$(LIBOSMOLEGACYMGCP_LIBS) \
$(LIBRARY_GSM) \
-lrt \
$(NULL)

View File

@ -1,12 +0,0 @@
12123124:3:2:
12123123:3:1:
12123128:3:6:
12123125:3:3:
12123127:3:5:
12123126:3:4:
12123120:3:4:
12123119:3:4:
12123118:3:4:
12123117:3:4:
12123116:3:4:
12123115:3:4:

View File

@ -1,2 +0,0 @@
12123124:3:2:
12123124:3:2:

View File

@ -1,275 +0,0 @@
/* test data */
/* BSC -> MSC, CR */
static const uint8_t bsc_cr[] = {
0x00, 0x2e, 0xfd,
0x01, 0x00, 0x00, 0x15, 0x02, 0x02, 0x04, 0x02,
0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3,
0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4,
0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
static const uint8_t bsc_cr_patched[] = {
0x00, 0x2e, 0xfd,
0x01, 0x00, 0x00, 0x05, 0x02, 0x02, 0x04, 0x02,
0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3,
0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4,
0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00 };
/* CC, MSC -> BSC */
static const uint8_t msc_cc[] = {
0x00, 0x0a, 0xfd,
0x02, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x02,
0x01, 0x00 };
static const uint8_t msc_cc_patched[] = {
0x00, 0x0a, 0xfd,
0x02, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x02,
0x01, 0x00 };
/* Classmark, BSC -> MSC */
static const uint8_t bsc_dtap[] = {
0x00, 0x17, 0xfd,
0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00,
0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13,
0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 };
static const uint8_t bsc_dtap_patched[] = {
0x00, 0x17, 0xfd,
0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00,
0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13,
0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 };
/* Clear command, MSC -> BSC */
static const uint8_t msc_dtap[] = {
0x00, 0x0d, 0xfd,
0x06, 0x00, 0x00, 0x05, 0x00, 0x01, 0x06, 0x00,
0x04, 0x20, 0x04, 0x01, 0x09 };
static const uint8_t msc_dtap_patched[] = {
0x00, 0x0d, 0xfd,
0x06, 0x00, 0x00, 0x15, 0x00, 0x01, 0x06, 0x00,
0x04, 0x20, 0x04, 0x01, 0x09 };
/*RLSD, MSC -> BSC */
static const uint8_t msc_rlsd[] = {
0x00, 0x0a, 0xfd,
0x04, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x00,
0x01, 0x00 };
static const uint8_t msc_rlsd_patched[] = {
0x00, 0x0a, 0xfd,
0x04, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x00,
0x01, 0x00 };
/* RLC, BSC -> MSC */
static const uint8_t bsc_rlc[] = {
0x00, 0x07, 0xfd,
0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x15 };
static const uint8_t bsc_rlc_patched[] = {
0x00, 0x07, 0xfd,
0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x05 };
/* a paging command */
static const uint8_t paging_by_lac_cmd[] = {
0x00, 0x22, 0xfd, 0x09,
0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x02, 0x00,
0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x12, 0x00,
0x10, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, 0x02,
0x01, 0x50, 0x02, 0x30, 0x1a, 0x03, 0x05, 0x20,
0x15 };
/* an assignment command */
static const uint8_t ass_cmd[] = {
0x00, 0x12, 0xfd, 0x06,
0x00, 0x00, 0x49, 0x00, 0x01, 0x0b, 0x00, 0x09,
0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00,
0x01 };
/* identity response */
static const uint8_t id_resp[] = {
0x00, 0x15, 0xfd, 0x06, 0x01, 0x1c, 0xdc,
0x00, 0x01, 0x0e, 0x01, 0x00, 0x0b, 0x05, 0x59,
0x08, 0x29, 0x40, 0x21, 0x03, 0x07, 0x48, 0x66,
0x31
};
/* sms code msg */
static const uint8_t smsc_rewrite[] = {
0x00, 0x30, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00,
0x01, 0x29, 0x01, 0x03, 0x26, 0x09, 0x01, 0x23,
0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08,
0x00, 0x10, 0x50, 0x17, 0x21, 0x0c, 0x0f, 0x81,
0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5,
0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca,
0xbf, 0xeb, 0x20
};
static const uint8_t smsc_rewrite_patched[] = {
0x00, 0x31, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00,
0x01, 0x2a, 0x01, 0x03, 0x27, 0x09, 0x01, 0x24,
0x00, 0x0c, 0x00, 0x08, 0x91, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0xf7, 0x17, 0x01, 0x0c, 0x0f,
0x81, 0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46,
0xf5, 0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c,
0xca, 0xbf, 0xeb, 0x20
};
static const uint8_t smsc_rewrite_patched_hdr[] = {
0x00, 0x30, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00,
0x01, 0x29, 0x01, 0x03, 0x26, 0x09, 0x01, 0x23,
0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08,
0x00, 0x10, 0x50, 0x17, 0x01, 0x0c, 0x0f, 0x81,
0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5,
0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca,
0xbf, 0xeb, 0x20
};
static const uint8_t smsc_rewrite_num_patched[] = {
0x00, 0x2f, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00,
0x01, 0x28, 0x01, 0x03, 0x25, 0x09, 0x01, 0x22,
0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08,
0x00, 0x10, 0x50, 0x16, 0x21, 0x0c, 0x0d, 0x91,
0x23, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5,
0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca,
0xbf, 0xeb, 0x20
};
static const uint8_t smsc_rewrite_num_patched_tp_srr[] = {
0x00, 0x2f, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00,
0x01, 0x28, 0x01, 0x03, 0x25, 0x09, 0x01, 0x22,
0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08,
0x00, 0x10, 0x50, 0x16, 0x01, 0x0c, 0x0d, 0x91,
0x23, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5,
0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca,
0xbf, 0xeb, 0x20
};
/*
* MGCP messages
*/
/* nothing to patch */
static const char crcx[] = "CRCX 23265295 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n";
static const char crcx_patched[] = "CRCX 23265295 1e@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n";
/* patch the ip and port */
static const char crcx_resp[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98 3\r\na=rtpmap:98 AMR/8000\r\n";
static const char crcx_resp_patched[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 10.0.0.1\r\nm=audio 999 RTP/AVP 98 3\r\na=rtpmap:98 AMR/8000\r\na=fmtp:98 mode-set=2\r\n";
/* patch the ip and port */
static const char mdcx[] = "MDCX 23330829 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 172.16.18.2\r\nt=0 0\r\nm=audio 4410 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n";
static const char mdcx_patched[] = "MDCX 23330829 1e@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 10.0.0.23\r\nt=0 0\r\nm=audio 6666 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n";
static const char mdcx_resp[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n";
static const char mdcx_resp_patched[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 10.0.0.23\r\nm=audio 5555 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\na=fmtp:98 mode-set=2\r\n";
/* different line ending */
static const char mdcx_resp2[] = "200 33330829\n\nv=0\nc=IN IP4 172.16.18.2\nm=audio 4002 RTP/AVP 98\na=rtpmap:98 AMR/8000\n";
static const char mdcx_resp_patched2[] = "200 33330829\n\nv=0\nc=IN IP4 10.0.0.23\nm=audio 5555 RTP/AVP 98\na=rtpmap:98 AMR/8000\na=fmtp:98 mode-set=2\n";
static const char mdcx_resp_patched2_noamr[] = "200 33330829\n\nv=0\nc=IN IP4 10.0.0.23\nm=audio 5555 RTP/AVP 98\na=rtpmap:98 AMR/8000\n";
struct mgcp_patch_test {
const char *orig;
const char *patch;
const char *ip;
const int port;
const int payload_type;
const int ensure_mode_set;
};
static const struct mgcp_patch_test mgcp_messages[] = {
{
.orig = crcx,
.patch = crcx_patched,
.ip = "0.0.0.0",
.port = 2323,
.ensure_mode_set = 1,
},
{
.orig = crcx_resp,
.patch = crcx_resp_patched,
.ip = "10.0.0.1",
.port = 999,
.payload_type = 98,
.ensure_mode_set = 1,
},
{
.orig = mdcx,
.patch = mdcx_patched,
.ip = "10.0.0.23",
.port = 6666,
.payload_type = 126,
.ensure_mode_set = 1,
},
{
.orig = mdcx_resp,
.patch = mdcx_resp_patched,
.ip = "10.0.0.23",
.port = 5555,
.payload_type = 98,
.ensure_mode_set = 1,
},
{
.orig = mdcx_resp2,
.patch = mdcx_resp_patched2,
.ip = "10.0.0.23",
.port = 5555,
.payload_type = 98,
.ensure_mode_set = 1,
},
{
.orig = mdcx_resp2,
.patch = mdcx_resp_patched2_noamr,
.ip = "10.0.0.23",
.port = 5555,
.payload_type = 98,
.ensure_mode_set = 0,
},
};
/* CC Setup messages */
static const uint8_t cc_setup_national[] = {
0x00, 0x20, 0xfd, 0x06, 0x01, 0x12,
0x6d, 0x00, 0x01, 0x19, 0x01, 0x00, 0x16, 0x03,
0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05,
0x81, 0x5e, 0x06, 0x81, 0x10, 0x27, 0x33, 0x63,
0x66, 0x15, 0x02, 0x11, 0x01
};
static const uint8_t cc_setup_national_patched[] = {
0x00, 0x21, 0xfd, 0x06, 0x01, 0x12,
0x6d, 0x00, 0x01, 0x1a, 0x01, 0x00, 0x17, 0x03,
0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05,
0x81, 0x5e, 0x07, 0x91, 0x94, 0x71, 0x32, 0x33,
0x66, 0xf6, 0x15, 0x02, 0x11, 0x01
};
/* patch the phone number of cc_setup_national_patched */
static const uint8_t cc_setup_national_patched_patched[] = {
0x00, 0x21, 0xfd, 0x06, 0x01, 0x12,
0x6d, 0x00, 0x01, 0x1a, 0x01, 0x00, 0x17, 0x03,
0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05,
0x81, 0x5e, 0x07, 0x91, 0x63, 0x71, 0x32, 0x33,
0x66, 0xf6, 0x15, 0x02, 0x11, 0x01
};
static const uint8_t cc_setup_international[] = {
0x00, 0x22, 0xfd, 0x06, 0x01, 0x13,
0xe7, 0x00, 0x01, 0x1b, 0x01, 0x00, 0x18, 0x03,
0x45, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05,
0x81, 0x5e, 0x08, 0x81, 0x00, 0x94, 0x71, 0x33,
0x63, 0x66, 0x03, 0x15, 0x02, 0x11, 0x01
};
static const uint8_t cc_setup_national_again[] = {
0x00, 0x22, 0xfd, 0x06, 0x01, 0x12, 0x6d, 0x00,
0x01, 0x1b, 0x01, 0x00, 0x18, 0x03, 0x05, 0x04,
0x06, 0x60, 0x04, 0x02, 0x00, 0x05, 0x81, 0x5e,
0x08, 0x81, 0x63, 0x94, 0x71, 0x32, 0x33, 0x66,
0xf6, 0x15, 0x02, 0x11, 0x01
};

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +0,0 @@
Testing BSS Filtering.
Going to test item: 0
Going to test item: 1
Going to test item: 2
Going to test item: 3
Going to test item: 4
Going to test item: 5
Going to test item: 6
Going to test item: 7
Going to test item: 8
Going to test item: 9
Going to test item: 10
Going to test item: 11
Going to test item: 12
Testing connection tracking.
Testing paging by lac.
Testing MGCP.
Testing finding of a BSC Connection
Testing rewriting MGCP messages.
Testing MGCP response parsing.
Testing SMSC rewriting.
Attempting to only rewrite the HDR
Attempting to change nothing.
Testing SMS TP-DA rewriting.
IMSI: 12123115 CM: 3 LU: 4
IMSI: 12123116 CM: 3 LU: 4
IMSI: 12123117 CM: 3 LU: 4
IMSI: 12123118 CM: 3 LU: 4
IMSI: 12123119 CM: 3 LU: 4
IMSI: 12123120 CM: 3 LU: 4
IMSI: 12123123 CM: 3 LU: 1
IMSI: 12123124 CM: 3 LU: 2
IMSI: 12123125 CM: 3 LU: 3
IMSI: 12123126 CM: 3 LU: 4
IMSI: 12123127 CM: 3 LU: 5
IMSI: 12123128 CM: 3 LU: 6
IMSI: 12123124 CM: 3 LU: 2
Testing LAC extraction from SCCP CR
Testing execution completed.

View File

@ -1,2 +0,0 @@
0172,0049
+49,0
1 0172 0049
2 +49 0

View File

@ -20,13 +20,6 @@ cat $abs_srcdir/channel/channel_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/channel/channel_test], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([bsc-nat-trie])
AT_KEYWORDS([bsc-nat-trie])
cp $abs_srcdir/bsc-nat-trie/prefixes.csv .
cat $abs_srcdir/bsc-nat-trie/bsc_nat_trie_test.ok > expout
AT_CHECK([$abs_top_builddir/tests/bsc-nat-trie/bsc_nat_trie_test], [], [expout], [ignore])
AT_CLEANUP
AT_SETUP([abis])
AT_KEYWORDS([abis])
cat $abs_srcdir/abis/abis_test.ok > expout

View File

@ -249,357 +249,6 @@ class TestVTYBSC(TestVTYGenericBSC):
self.assert_(res.find("core-location-area-code 666") > 0)
self.assert_(res.find("core-cell-identity 333") > 0)
class TestVTYNAT(TestVTYGenericBSC):
def vty_command(self):
return ["./src/osmo-bsc_nat/osmo-bsc_nat", "-l", "127.0.0.1", "-c",
"doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg"]
def vty_app(self):
return (4244, "src/osmo-bsc_nat/osmo-bsc_nat", "OsmoBSCNAT", "nat")
def testBSCreload(self):
# Use different port for the mock msc to avoid clashing with
# the osmo-bsc_nat itself
ip = "127.0.0.1"
port = 5522
self.vty.enable()
bscs1 = self.vty.command("show bscs-config")
nat_bsc_reload(self)
bscs2 = self.vty.command("show bscs-config")
# check that multiple calls to bscs-config-file give the same result
self.assertEquals(bscs1, bscs2)
# add new bsc
self.vty.command("configure terminal")
self.vty.command("nat")
self.vty.command("bsc 5")
self.vty.command("token key")
self.vty.command("location_area_code 666")
self.vty.command("end")
# update bsc token
self.vty.command("configure terminal")
self.vty.command("nat")
self.vty.command("bsc 1")
self.vty.command("token xyu")
self.vty.command("end")
nat_msc_ip(self, ip, port)
msc_socket, msc = nat_msc_test(self, ip, port, verbose=True)
try:
b0 = nat_bsc_sock_test(0, "lol", verbose=True, proc=self.proc)
b1 = nat_bsc_sock_test(1, "xyu", verbose=True, proc=self.proc)
b2 = nat_bsc_sock_test(5, "key", verbose=True, proc=self.proc)
self.assertEquals("3 BSCs configured", self.vty.command("show nat num-bscs-configured"))
self.assertTrue(3 == nat_bsc_num_con(self))
self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection"))
nat_bsc_reload(self)
bscs2 = self.vty.command("show bscs-config")
# check that the reset to initial config succeeded
self.assertEquals(bscs1, bscs2)
self.assertEquals("2 BSCs configured", self.vty.command("show nat num-bscs-configured"))
self.assertTrue(1 == nat_bsc_num_con(self))
rem = self.vty.command("show bsc connections").split(' ')
# remaining connection is for BSC0
self.assertEquals('0', rem[2])
# remaining connection is authorized
self.assertEquals('1', rem[4])
self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection"))
finally:
msc.close()
msc_socket.close()
def testVtyTree(self):
self.vty.enable()
self.assertTrue(self.vty.verify('configure terminal', ['']))
self.assertEquals(self.vty.node(), 'config')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('mgcp', ['']))
self.assertEquals(self.vty.node(), 'config-mgcp')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('exit', ['']))
self.assertEquals(self.vty.node(), 'config')
self.assertTrue(self.vty.verify('nat', ['']))
self.assertEquals(self.vty.node(), 'config-nat')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('bsc 0', ['']))
self.assertEquals(self.vty.node(), 'config-nat-bsc')
self.checkForEndAndExit()
self.assertTrue(self.vty.verify('exit', ['']))
self.assertEquals(self.vty.node(), 'config-nat')
self.assertTrue(self.vty.verify('exit', ['']))
self.assertEquals(self.vty.node(), 'config')
self.assertTrue(self.vty.verify('exit', ['']))
self.assertTrue(self.vty.node() is None)
def testRewriteNoRewrite(self):
self.vty.enable()
res = self.vty.command("configure terminal")
res = self.vty.command("nat")
res = self.vty.command("number-rewrite rewrite.cfg")
res = self.vty.command("no number-rewrite")
def testEnsureNoEnsureModeSet(self):
self.vty.enable()
res = self.vty.command("configure terminal")
res = self.vty.command("nat")
# Ensure the default
res = self.vty.command("show running-config")
self.assert_(res.find('\n sdp-ensure-amr-mode-set') > 0)
self.vty.command("sdp-ensure-amr-mode-set")
res = self.vty.command("show running-config")
self.assert_(res.find('\n sdp-ensure-amr-mode-set') > 0)
self.vty.command("no sdp-ensure-amr-mode-set")
res = self.vty.command("show running-config")
self.assert_(res.find('\n no sdp-ensure-amr-mode-set') > 0)
def testRewritePostNoRewrite(self):
self.vty.enable()
self.vty.command("configure terminal")
self.vty.command("nat")
self.vty.verify("number-rewrite-post rewrite.cfg", [''])
self.vty.verify("no number-rewrite-post", [''])
def testPrefixTreeLoading(self):
cfg = os.path.join(confpath, "tests/bsc-nat-trie/prefixes.csv")
self.vty.enable()
self.vty.command("configure terminal")
self.vty.command("nat")
res = self.vty.command("prefix-tree %s" % cfg)
self.assertEqual(res, "% prefix-tree loaded 17 rules.")
self.vty.command("end")
res = self.vty.command("show prefix-tree")
self.assertEqual(res, '1,1\r\n12,2\r\n123,3\r\n1234,4\r\n12345,5\r\n123456,6\r\n1234567,7\r\n12345678,8\r\n123456789,9\r\n1234567890,10\r\n13,11\r\n14,12\r\n15,13\r\n16,14\r\n82,16\r\n823455,15\r\n+49123,17')
self.vty.command("configure terminal")
self.vty.command("nat")
self.vty.command("no prefix-tree")
self.vty.command("end")
res = self.vty.command("show prefix-tree")
self.assertEqual(res, "% there is now prefix tree loaded.")
def testUssdSideChannelProvider(self):
self.vty.command("end")
self.vty.enable()
self.vty.command("configure terminal")
self.vty.command("nat")
self.vty.command("ussd-token key")
self.vty.command("end")
res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is not connected and not authorized.'])
self.assertTrue(res)
ussdSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ussdSocket.connect(('127.0.0.1', 5001))
ussdSocket.settimeout(2.0)
print "Connected to %s:%d" % ussdSocket.getpeername()
print "Expecting ID_GET request"
data = ussdSocket.recv(4)
self.assertEqual(data, "\x00\x01\xfe\x04")
print "Going to send ID_RESP response"
res = ussdSocket.send(IPA().id_resp(IPA().tag_name('key')))
self.assertEqual(res, 10)
# initiating PING/PONG cycle to know, that the ID_RESP message has been processed
print "Going to send PING request"
res = ussdSocket.send(IPA().ping())
self.assertEqual(res, 4)
print "Expecting PONG response"
data = ussdSocket.recv(4)
self.assertEqual(data, "\x00\x01\xfe\x01")
res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is connected and authorized.'])
self.assertTrue(res)
print "Going to shut down connection"
ussdSocket.shutdown(socket.SHUT_WR)
print "Expecting EOF"
data = ussdSocket.recv(4)
self.assertEqual(data, "")
ussdSocket.close()
res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is not connected and not authorized.'])
self.assertTrue(res)
def testAccessList(self):
"""
Verify that the imsi-deny can have a reject cause or no reject cause
"""
self.vty.enable()
self.vty.command("configure terminal")
self.vty.command("nat")
# Old default
self.vty.command("access-list test-default imsi-deny ^123[0-9]*$")
res = self.vty.command("show running-config").split("\r\n")
asserted = False
for line in res:
if line.startswith(" access-list test-default"):
self.assertEqual(line, " access-list test-default imsi-deny ^123[0-9]*$ 11 11")
asserted = True
self.assert_(asserted)
# Check the optional CM Service Reject Cause
self.vty.command("access-list test-cm-deny imsi-deny ^123[0-9]*$ 42").split("\r\n")
res = self.vty.command("show running-config").split("\r\n")
asserted = False
for line in res:
if line.startswith(" access-list test-cm"):
self.assertEqual(line, " access-list test-cm-deny imsi-deny ^123[0-9]*$ 42 11")
asserted = True
self.assert_(asserted)
# Check the optional LU Reject Cause
self.vty.command("access-list test-lu-deny imsi-deny ^123[0-9]*$ 23 42").split("\r\n")
res = self.vty.command("show running-config").split("\r\n")
asserted = False
for line in res:
if line.startswith(" access-list test-lu"):
self.assertEqual(line, " access-list test-lu-deny imsi-deny ^123[0-9]*$ 23 42")
asserted = True
self.assert_(asserted)
def add_nat_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc_nat/osmo-bsc_nat")):
print("Skipping the NAT test")
return
test = unittest.TestLoader().loadTestsFromTestCase(TestVTYNAT)
suite.addTest(test)
def nat_bsc_reload(x):
x.vty.command("configure terminal")
x.vty.command("nat")
x.vty.command("bscs-config-file bscs.cfg")
x.vty.command("end")
def nat_msc_ip(x, ip, port):
x.vty.command("configure terminal")
x.vty.command("nat")
x.vty.command("msc ip " + ip)
x.vty.command("msc port " + str(port))
x.vty.command("end")
def data2str(d):
return d.encode('hex').lower()
def nat_msc_test(x, ip, port, verbose = False):
msc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
msc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
msc.settimeout(5)
msc.bind((ip, port))
msc.listen(5)
if (verbose):
print "MSC is ready at " + ip
conn = None
while True:
vty_response = x.vty.command("show msc connection")
print "'show msc connection' says: %r" % vty_response
if vty_response == "MSC is connected: 1":
# success
break;
if vty_response != "MSC is connected: 0":
raise Exception("Unexpected response to 'show msc connection'"
" vty command: %r" % vty_response)
timeout_retries = 6
while timeout_retries > 0:
try:
conn, addr = msc.accept()
print "MSC got connection from ", addr
break
except socket.timeout:
print "socket timed out."
timeout_retries -= 1
continue
if not conn:
raise Exception("VTY reports MSC is connected, but I haven't"
" connected yet: %r %r" % (ip, port))
return msc, conn
def ipa_handle_small(x, verbose = False):
s = data2str(x.recv(4))
if len(s) != 4*2:
raise Exception("expected to receive 4 bytes, but got %d (%r)" % (len(s)/2, s))
if "0001fe00" == s:
if (verbose):
print "\tBSC <- NAT: PING?"
x.send(IPA().pong())
elif "0001fe06" == s:
if (verbose):
print "\tBSC <- NAT: IPA ID ACK"
x.send(IPA().id_ack())
elif "0001fe00" == s:
if (verbose):
print "\tBSC <- NAT: PONG!"
else:
if (verbose):
print "\tBSC <- NAT: ", s
def ipa_handle_resp(x, tk, verbose = False, proc=None):
s = data2str(x.recv(38))
if "0023fe040108010701020103010401050101010011" in s:
retries = 3
while True:
print "\tsending IPA identity(%s) at %s" % (tk, time.strftime("%T"))
try:
x.send(IPA().id_resp(IPA().identity(name = tk.encode('utf-8'))))
print "\tdone sending IPA identity(%s) at %s" % (tk,
time.strftime("%T"))
break
except:
print "\tfailed sending IPA identity at", time.strftime("%T")
if proc:
print "\tproc.poll() = %r" % proc.poll()
if retries < 1:
print "\tgiving up"
raise
print "\tretrying (%d attempts left)" % retries
retries -= 1
else:
if (verbose):
print "\tBSC <- NAT: ", s
def nat_bsc_num_con(x):
return len(x.vty.command("show bsc connections").split('\n'))
def nat_bsc_sock_test(nr, tk, verbose = False, proc=None):
bsc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bsc.bind(('127.0.0.1', 0))
bsc.connect(('127.0.0.1', 5000))
if (verbose):
print "BSC%d " %nr
print "\tconnected to %s:%d" % bsc.getpeername()
if proc:
print "\tproc.poll() = %r" % proc.poll()
print "\tproc.pid = %r" % proc.pid
ipa_handle_small(bsc, verbose)
ipa_handle_resp(bsc, tk, verbose, proc=proc)
if proc:
print "\tproc.poll() = %r" % proc.poll()
bsc.recv(27) # MGCP msg
if proc:
print "\tproc.poll() = %r" % proc.poll()
ipa_handle_small(bsc, verbose)
return bsc
def add_bsc_test(suite, workdir):
if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc/osmo-bsc")):
@ -639,7 +288,6 @@ if __name__ == '__main__':
print "Running tests for specific VTY commands"
suite = unittest.TestSuite()
add_bsc_test(suite, workdir)
add_nat_test(suite, workdir)
if args.test_name:
osmoutil.pick_tests(suite, *args.test_name)