mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
				synced 2025-10-31 12:03:50 +00:00 
			
		
		
		
	Merge branch 'zecke/features/big-rewrite'
This commit is contained in:
		
							
								
								
									
										1
									
								
								openbsc/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								openbsc/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -50,6 +50,7 @@ src/osmo-bsc_nat/osmo-bsc_nat | ||||
|  | ||||
| #tests | ||||
| tests/bsc-nat/bsc_nat_test | ||||
| tests/bsc-nat-trie/bsc_nat_trie_test | ||||
| tests/channel/channel_test | ||||
| tests/db/db_test | ||||
| tests/debug/debug_test | ||||
|   | ||||
| @@ -157,6 +157,7 @@ AC_OUTPUT( | ||||
|     tests/db/Makefile | ||||
|     tests/channel/Makefile | ||||
|     tests/bsc-nat/Makefile | ||||
|     tests/bsc-nat-trie/Makefile | ||||
|     tests/mgcp/Makefile | ||||
|     tests/gprs/Makefile | ||||
|     tests/si/Makefile | ||||
|   | ||||
| @@ -13,7 +13,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ | ||||
| 		osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \ | ||||
| 		osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \ | ||||
| 		bss.h gsm_data_shared.h control_cmd.h ipaccess.h mncc_int.h \ | ||||
| 		arfcn_range_encode.h | ||||
| 		arfcn_range_encode.h nat_rewrite_trie.h | ||||
|  | ||||
| openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h | ||||
| openbscdir = $(includedir)/openbsc | ||||
|   | ||||
| @@ -45,6 +45,7 @@ struct nat_sccp_connection; | ||||
| struct bsc_nat_parsed; | ||||
| struct bsc_nat; | ||||
| struct bsc_nat_ussd_con; | ||||
| struct nat_rewrite_rule; | ||||
|  | ||||
| enum { | ||||
| 	NAT_CON_TYPE_NONE, | ||||
| @@ -298,6 +299,8 @@ struct bsc_nat { | ||||
| 	/* 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; | ||||
| @@ -308,6 +311,10 @@ struct bsc_nat { | ||||
| 	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; | ||||
| @@ -452,6 +459,7 @@ struct bsc_nat_num_rewr_entry { | ||||
| 	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 *); | ||||
|   | ||||
							
								
								
									
										47
									
								
								openbsc/include/openbsc/nat_rewrite_trie.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								openbsc/include/openbsc/nat_rewrite_trie.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| /* | ||||
|  * (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 | ||||
| @@ -7,7 +7,7 @@ bin_PROGRAMS = osmo-bsc_nat | ||||
|  | ||||
| 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_filter.c | ||||
| 		  bsc_nat_rewrite.c bsc_nat_filter.c bsc_nat_rewrite_trie.c | ||||
| osmo_bsc_nat_LDADD = $(top_builddir)/src/libcommon/libcommon.a \ | ||||
| 		$(top_builddir)/src/libmgcp/libmgcp.a \ | ||||
| 		$(top_builddir)/src/libbsc/libbsc.a \ | ||||
|   | ||||
| @@ -1480,6 +1480,7 @@ static struct vty_app_info vty_info = { | ||||
| 	.is_config_node	= bsc_vty_is_config_node, | ||||
| }; | ||||
|  | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	int rc; | ||||
| @@ -1526,6 +1527,8 @@ int main(int argc, char **argv) | ||||
| 	/* seed the PRNG */ | ||||
| 	srand(time(NULL)); | ||||
|  | ||||
|  | ||||
|  | ||||
| 	/* | ||||
| 	 * Setup the MGCP code.. | ||||
| 	 */ | ||||
|   | ||||
| @@ -27,6 +27,7 @@ | ||||
| #include <openbsc/gsm_data.h> | ||||
| #include <openbsc/debug.h> | ||||
| #include <openbsc/ipaccess.h> | ||||
| #include <openbsc/nat_rewrite_trie.h> | ||||
|  | ||||
| #include <osmocom/core/linuxlist.h> | ||||
| #include <osmocom/core/talloc.h> | ||||
| @@ -37,9 +38,30 @@ | ||||
|  | ||||
| #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) | ||||
| 				const char *imsi, struct llist_head *list, | ||||
| 				struct nat_rewrite *trie) | ||||
| { | ||||
| 	struct bsc_nat_num_rewr_entry *entry; | ||||
| 	char *new_number = NULL; | ||||
| @@ -53,11 +75,17 @@ static char *match_and_rewrite_number(void *ctx, const char *number, | ||||
| 			continue; | ||||
|  | ||||
| 		/* this regexp matches... */ | ||||
| 		if (regexec(&entry->num_reg, number, 2, matches, 0) == 0 && | ||||
| 		    matches[1].rm_eo != -1) | ||||
| 			new_number = talloc_asprintf(ctx, "%s%s", | ||||
| 		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; | ||||
| 	} | ||||
| @@ -65,18 +93,24 @@ static char *match_and_rewrite_number(void *ctx, const char *number, | ||||
| 	return new_number; | ||||
| } | ||||
|  | ||||
| static char *rewrite_isdn_number(struct bsc_nat *nat, void *ctx, const char *imsi, | ||||
| 				       struct gsm_mncc_number *called) | ||||
| 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)) | ||||
| 	if (llist_empty(&nat->num_rewr)) { | ||||
| 		LOGP(DCC, LOGL_DEBUG, "Rewrite rules empty.\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	/* only ISDN plan */ | ||||
| 	if (called->plan != 1) | ||||
| 	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) { | ||||
| @@ -86,9 +120,24 @@ static char *rewrite_isdn_number(struct bsc_nat *nat, void *ctx, const char *ims | ||||
| 	} | ||||
|  | ||||
| 	return match_and_rewrite_number(ctx, number, | ||||
| 					imsi, &nat->num_rewr); | ||||
| 					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; | ||||
| 		strncpy(called->number, chosen_number + 2, sizeof(called->number)); | ||||
| 	} else { | ||||
| 		/* rewrite international to unknown */ | ||||
| 		if (called->type == 1) | ||||
| 			called->type = 0; | ||||
| 		strncpy(called->number, chosen_number, sizeof(called->number)); | ||||
| 	} | ||||
|  | ||||
| 	called->number[sizeof(called->number) - 1] = '\0'; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Rewrite non global numbers... according to rules based on the IMSI | ||||
| @@ -101,7 +150,7 @@ static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg, | ||||
| 	unsigned int payload_len; | ||||
| 	struct gsm_mncc_number called; | ||||
| 	struct msgb *out; | ||||
| 	char *new_number = NULL; | ||||
| 	char *new_number_pre = NULL, *new_number_post = NULL, *chosen_number; | ||||
| 	uint8_t *outptr; | ||||
| 	const uint8_t *msgptr; | ||||
| 	int sec_len; | ||||
| @@ -119,16 +168,39 @@ static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg, | ||||
| 			    TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1); | ||||
|  | ||||
| 	/* check if it looks international and stop */ | ||||
| 	new_number = rewrite_isdn_number(nat, msg, imsi, &called); | ||||
| 	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) { | ||||
| 		LOGP(DNAT, LOGL_DEBUG, "No IMSI match found, returning message.\n"); | ||||
| 	if (!new_number_pre) { | ||||
| 		LOGP(DCC, LOGL_DEBUG, "No IMSI(%s) match found, returning message.\n", | ||||
| 			imsi); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	if (strlen(new_number) > sizeof(called.number)) { | ||||
| 		LOGP(DNAT, LOGL_ERROR, "Number is too long for structure.\n"); | ||||
| 		talloc_free(new_number); | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| @@ -140,8 +212,9 @@ static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg, | ||||
|  | ||||
| 	out = msgb_alloc_headroom(4096, 128, "changed-setup"); | ||||
| 	if (!out) { | ||||
| 		LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n"); | ||||
| 		talloc_free(new_number); | ||||
| 		LOGP(DCC, LOGL_ERROR, "Failed to allocate.\n"); | ||||
| 		talloc_free(new_number_pre); | ||||
| 		talloc_free(new_number_post); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| @@ -155,15 +228,10 @@ static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg, | ||||
| 	memcpy(outptr, &hdr48->data[0], sec_len); | ||||
|  | ||||
| 	/* create the new number */ | ||||
| 	if (strncmp(new_number, "00", 2) == 0) { | ||||
| 		called.type = 1; | ||||
| 		strncpy(called.number, new_number + 2, sizeof(called.number)); | ||||
| 	} else { | ||||
| 		/* rewrite international to unknown */ | ||||
| 		if (called.type == 1) | ||||
| 			called.type = 0; | ||||
| 		strncpy(called.number, new_number, sizeof(called.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 */ | ||||
| @@ -173,7 +241,8 @@ static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg, | ||||
| 	outptr = msgb_put(out, sec_len); | ||||
| 	memcpy(outptr, msgptr, sec_len); | ||||
|  | ||||
| 	talloc_free(new_number); | ||||
| 	talloc_free(new_number_pre); | ||||
| 	talloc_free(new_number_post); | ||||
| 	return out; | ||||
| } | ||||
|  | ||||
| @@ -261,7 +330,7 @@ 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); | ||||
| 					&nat->sms_num_rewr, NULL); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -600,6 +669,9 @@ void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, | ||||
| 			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); | ||||
|   | ||||
							
								
								
									
										259
									
								
								openbsc/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								openbsc/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,259 @@ | ||||
| /* 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 <openbsc/nat_rewrite_trie.h> | ||||
| #include <openbsc/debug.h> | ||||
| #include <openbsc/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 size_t 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 = 2342; | ||||
| 	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); | ||||
| } | ||||
| @@ -96,6 +96,7 @@ struct bsc_nat *bsc_nat_alloc(void) | ||||
| 	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); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /* OpenBSC NAT interface to quagga VTY */ | ||||
| /* (C) 2010-2012 by Holger Hans Peter Freyther | ||||
|  * (C) 2010-2012 by On-Waves | ||||
| /* (C) 2010-2013 by Holger Hans Peter Freyther | ||||
|  * (C) 2010-2013 by On-Waves | ||||
|  * All Rights Reserved | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
| @@ -26,6 +26,7 @@ | ||||
| #include <openbsc/gsm_04_08.h> | ||||
| #include <openbsc/mgcp.h> | ||||
| #include <openbsc/vty.h> | ||||
| #include <openbsc/nat_rewrite_trie.h> | ||||
|  | ||||
| #include <osmocom/core/talloc.h> | ||||
| #include <osmocom/core/rate_ctr.h> | ||||
| @@ -126,6 +127,10 @@ static int config_write_nat(struct vty *vty) | ||||
|  | ||||
| 	if (_nat->num_rewr_name) | ||||
| 		vty_out(vty, " number-rewrite %s%s", _nat->num_rewr_name, VTY_NEWLINE); | ||||
| 	if (_nat->num_rewr_post_name) | ||||
| 		vty_out(vty, " number-rewrite-post %s%s", | ||||
| 			_nat->num_rewr_post_name, VTY_NEWLINE); | ||||
|  | ||||
| 	if (_nat->smsc_rewr_name) | ||||
| 		vty_out(vty, " rewrite-smsc addr %s%s", | ||||
| 			_nat->smsc_rewr_name, VTY_NEWLINE); | ||||
| @@ -138,6 +143,9 @@ static int config_write_nat(struct vty *vty) | ||||
| 	if (_nat->sms_num_rewr_name) | ||||
| 		vty_out(vty, " sms-number-rewrite %s%s", | ||||
| 			_nat->sms_num_rewr_name, VTY_NEWLINE); | ||||
| 	if (_nat->num_rewr_trie_name) | ||||
| 		vty_out(vty, " prefix-tree %s%s", | ||||
| 			_nat->num_rewr_trie_name, VTY_NEWLINE); | ||||
|  | ||||
| 	llist_for_each_entry(lst, &_nat->access_lists, list) | ||||
| 		write_acc_lst(vty, lst); | ||||
| @@ -554,6 +562,39 @@ DEFUN(cfg_nat_number_rewrite, | ||||
| 			     &_nat->num_rewr, argv[0]); | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_nat_no_number_rewrite, | ||||
|       cfg_nat_no_number_rewrite_cmd, | ||||
|       "no number-rewrite", | ||||
|       NO_STR "Set the file with rewriting rules.\n") | ||||
| { | ||||
| 	talloc_free(_nat->num_rewr_name); | ||||
| 	_nat->num_rewr_name = NULL; | ||||
|  | ||||
| 	bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr, NULL); | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_nat_number_rewrite_post, | ||||
|       cfg_nat_number_rewrite_post_cmd, | ||||
|       "number-rewrite-post FILENAME", | ||||
|       "Set the file with post-routing rewriting rules.\n" "Filename") | ||||
| { | ||||
| 	return replace_rules(_nat, &_nat->num_rewr_post_name, | ||||
| 			     &_nat->num_rewr_post, argv[0]); | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_nat_no_number_rewrite_post, | ||||
|       cfg_nat_no_number_rewrite_post_cmd, | ||||
|       "no number-rewrite-post", | ||||
|       NO_STR "Set the file with post-routing rewriting rules.\n") | ||||
| { | ||||
| 	talloc_free(_nat->num_rewr_post_name); | ||||
| 	_nat->num_rewr_post_name = NULL; | ||||
|  | ||||
| 	bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr_post, NULL); | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_nat_smsc_addr, | ||||
|       cfg_nat_smsc_addr_cmd, | ||||
|       "rewrite-smsc addr FILENAME", | ||||
| @@ -621,6 +662,59 @@ DEFUN(cfg_nat_no_sms_number_rewrite, | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_nat_prefix_trie, | ||||
|       cfg_nat_prefix_trie_cmd, | ||||
|       "prefix-tree FILENAME", | ||||
|       "Prefix tree for number rewriting\n" "File to load\n") | ||||
| { | ||||
| 	/* give up the old data */ | ||||
| 	talloc_free(_nat->num_rewr_trie); | ||||
| 	_nat->num_rewr_trie = NULL; | ||||
|  | ||||
| 	/* replace the file name */ | ||||
| 	bsc_replace_string(_nat, &_nat->num_rewr_trie_name, argv[0]); | ||||
| 	if (!_nat->num_rewr_trie_name) { | ||||
| 		vty_out(vty, "%% prefix-tree no filename is present.%s", VTY_NEWLINE); | ||||
| 		return CMD_WARNING; | ||||
| 	} | ||||
|  | ||||
| 	_nat->num_rewr_trie = nat_rewrite_parse(_nat, _nat->num_rewr_trie_name); | ||||
| 	if (!_nat->num_rewr_trie) { | ||||
| 		vty_out(vty, "%% prefix-tree parsing has failed.%s", VTY_NEWLINE); | ||||
| 		return CMD_WARNING; | ||||
| 	} | ||||
|  | ||||
| 	vty_out(vty, "%% prefix-tree loaded %zu rules.%s", | ||||
| 		_nat->num_rewr_trie->prefixes, VTY_NEWLINE); | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_nat_no_prefix_trie, cfg_nat_no_prefix_trie_cmd, | ||||
|       "no prefix-tree", | ||||
|       NO_STR "Prefix tree for number rewriting\n") | ||||
| { | ||||
| 	talloc_free(_nat->num_rewr_trie); | ||||
| 	_nat->num_rewr_trie = NULL; | ||||
| 	talloc_free(_nat->num_rewr_trie_name); | ||||
| 	_nat->num_rewr_trie_name = NULL; | ||||
|  | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(show_prefix_tree, show_prefix_tree_cmd, | ||||
|       "show prefix-tree", | ||||
|       SHOW_STR "Prefix tree for number rewriting\n") | ||||
| { | ||||
| 	if (!_nat->num_rewr_trie) { | ||||
| 		vty_out(vty, "%% there is now prefix tree loaded.%s", | ||||
| 			VTY_NEWLINE); | ||||
| 		return CMD_WARNING; | ||||
| 	} | ||||
|  | ||||
| 	nat_rewrite_dump_vty(vty, _nat->num_rewr_trie); | ||||
| 	return CMD_SUCCESS; | ||||
| } | ||||
|  | ||||
| DEFUN(cfg_nat_ussd_lst_name, | ||||
|       cfg_nat_ussd_lst_name_cmd, | ||||
|       "ussd-list-name NAME", | ||||
| @@ -1077,6 +1171,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) | ||||
| 	install_element_ve(&show_bsc_mgcp_cmd); | ||||
| 	install_element_ve(&show_acc_lst_cmd); | ||||
| 	install_element_ve(&show_bar_lst_cmd); | ||||
| 	install_element_ve(&show_prefix_tree_cmd); | ||||
|  | ||||
| 	install_element(ENABLE_NODE, &set_last_endp_cmd); | ||||
| 	install_element(ENABLE_NODE, &block_new_conn_cmd); | ||||
| @@ -1112,12 +1207,17 @@ int bsc_nat_vty_init(struct bsc_nat *nat) | ||||
|  | ||||
| 	/* number rewriting */ | ||||
| 	install_element(NAT_NODE, &cfg_nat_number_rewrite_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_no_number_rewrite_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_number_rewrite_post_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_no_number_rewrite_post_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_smsc_addr_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_smsc_tpdest_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_sms_clear_tpsrr_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_no_sms_clear_tpsrr_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_sms_number_rewrite_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_no_sms_number_rewrite_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_prefix_trie_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_no_prefix_trie_cmd); | ||||
|  | ||||
| 	install_element(NAT_NODE, &cfg_nat_pgroup_cmd); | ||||
| 	install_element(NAT_NODE, &cfg_nat_no_pgroup_cmd); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| SUBDIRS = gsm0408 db channel mgcp gprs si abis | ||||
|  | ||||
| if BUILD_NAT | ||||
| SUBDIRS += bsc-nat | ||||
| SUBDIRS += bsc-nat bsc-nat-trie | ||||
| endif | ||||
|  | ||||
| if BUILD_SMPP | ||||
|   | ||||
							
								
								
									
										18
									
								
								openbsc/tests/bsc-nat-trie/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								openbsc/tests/bsc-nat-trie/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include | ||||
| AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) | ||||
| 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 \ | ||||
| 			$(top_srcdir)/src/libctrl/libctrl.a \ | ||||
| 			$(top_srcdir)/src/libmgcp/libmgcp.a \ | ||||
| 			$(top_srcdir)/src/libtrau/libtrau.a \ | ||||
| 			$(top_srcdir)/src/libcommon/libcommon.a \ | ||||
| 			$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -lrt \ | ||||
| 			$(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ | ||||
| 			$(LIBOSMOABIS_LIBS) | ||||
							
								
								
									
										87
									
								
								openbsc/tests/bsc-nat-trie/bsc_nat_trie_test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								openbsc/tests/bsc-nat-trie/bsc_nat_trie_test.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| /* | ||||
|  * (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 <openbsc/nat_rewrite_trie.h> | ||||
| #include <openbsc/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> | ||||
|  | ||||
| int main(int argc, char **argv) | ||||
| { | ||||
| 	struct nat_rewrite *trie; | ||||
|  | ||||
| 	osmo_init_logging(&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; | ||||
| } | ||||
							
								
								
									
										20
									
								
								openbsc/tests/bsc-nat-trie/bsc_nat_trie_test.ok
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								openbsc/tests/bsc-nat-trie/bsc_nat_trie_test.ok
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| 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. | ||||
							
								
								
									
										25
									
								
								openbsc/tests/bsc-nat-trie/prefixes.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								openbsc/tests/bsc-nat-trie/prefixes.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| 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. | 
| @@ -2,7 +2,7 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include | ||||
| AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) | ||||
| AM_LDFLAGS = $(COVERAGE_LDFLAGS) | ||||
|  | ||||
| EXTRA_DIST = bsc_nat_test.ok bsc_data.c barr.cfg barr_dup.cfg | ||||
| EXTRA_DIST = bsc_nat_test.ok bsc_data.c barr.cfg barr_dup.cfg prefixes.csv | ||||
|  | ||||
| noinst_PROGRAMS = bsc_nat_test | ||||
|  | ||||
| @@ -12,6 +12,7 @@ bsc_nat_test_SOURCES = bsc_nat_test.c \ | ||||
| 			$(top_srcdir)/src/osmo-bsc_nat/bsc_nat_utils.c \ | ||||
| 			$(top_srcdir)/src/osmo-bsc_nat/bsc_nat_filter.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 | ||||
| bsc_nat_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ | ||||
| 			$(top_srcdir)/src/libctrl/libctrl.a \ | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| #include <openbsc/gsm_data.h> | ||||
| #include <openbsc/bsc_nat.h> | ||||
| #include <openbsc/bsc_nat_sccp.h> | ||||
| #include <openbsc/nat_rewrite_trie.h> | ||||
|  | ||||
| #include <osmocom/core/application.h> | ||||
| #include <osmocom/core/backtrace.h> | ||||
| @@ -451,6 +452,8 @@ static void test_paging(void) | ||||
| 		printf("Should have found it.\n"); | ||||
| 		abort(); | ||||
| 	} | ||||
|  | ||||
| 	talloc_free(nat); | ||||
| } | ||||
|  | ||||
| static void test_mgcp_allocations(void) | ||||
| @@ -819,6 +822,7 @@ static void test_cr_filter() | ||||
| 	} | ||||
|  | ||||
| 	msgb_free(msg); | ||||
| 	talloc_free(nat); | ||||
| } | ||||
|  | ||||
| static void test_dt_filter() | ||||
| @@ -1039,6 +1043,117 @@ static void test_setup_rewrite() | ||||
| 	verify_msg(out, cc_setup_national_again, | ||||
| 			ARRAY_SIZE(cc_setup_national_again)); | ||||
| 	msgb_free(out); | ||||
| 	bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); | ||||
| 	talloc_free(nat); | ||||
| } | ||||
|  | ||||
| static void test_setup_rewrite_prefix(void) | ||||
| { | ||||
| 	struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); | ||||
| 	struct msgb *out; | ||||
| 	struct bsc_nat_parsed *parsed; | ||||
| 	const char *imsi = "27408000001234"; | ||||
|  | ||||
| 	struct bsc_nat *nat = bsc_nat_alloc(); | ||||
|  | ||||
| 	/* a fake list */ | ||||
| 	struct osmo_config_list entries; | ||||
| 	struct osmo_config_entry entry; | ||||
|  | ||||
| 	INIT_LLIST_HEAD(&entries.entry); | ||||
| 	entry.mcc = "274"; | ||||
| 	entry.mnc = "08"; | ||||
| 	entry.option = "^0([1-9])"; | ||||
| 	entry.text = "prefix_lookup"; | ||||
| 	llist_add_tail(&entry.list, &entries.entry); | ||||
| 	bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); | ||||
|  | ||||
|         nat->num_rewr_trie = nat_rewrite_parse(nat, "prefixes.csv"); | ||||
|  | ||||
| 	msgb_reset(msg); | ||||
| 	copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); | ||||
| 	parsed = bsc_nat_parse(msg); | ||||
| 	if (!parsed) { | ||||
| 		printf("FAIL: Could not parse ID resp\n"); | ||||
| 		abort(); | ||||
| 	} | ||||
|  | ||||
| 	out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); | ||||
| 	if (!out) { | ||||
| 		printf("FAIL: A new message should be created.\n"); | ||||
| 		abort(); | ||||
| 	} | ||||
|  | ||||
| 	if (msg == out) { | ||||
| 		printf("FAIL: The message should have changed\n"); | ||||
| 		abort(); | ||||
| 	} | ||||
|  | ||||
| 	verify_msg(out, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); | ||||
| 	msgb_free(out); | ||||
|  | ||||
| 	bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); | ||||
| 	talloc_free(nat); | ||||
| } | ||||
|  | ||||
| static void test_setup_rewrite_post(void) | ||||
| { | ||||
| 	struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); | ||||
| 	struct msgb *out; | ||||
| 	struct bsc_nat_parsed *parsed; | ||||
| 	const char *imsi = "27408000001234"; | ||||
|  | ||||
| 	struct bsc_nat *nat = bsc_nat_alloc(); | ||||
|  | ||||
| 	/* a fake list */ | ||||
| 	struct osmo_config_list entries; | ||||
| 	struct osmo_config_entry entry; | ||||
| 	struct osmo_config_list entries_post; | ||||
| 	struct osmo_config_entry entry_post; | ||||
|  | ||||
| 	INIT_LLIST_HEAD(&entries.entry); | ||||
| 	entry.mcc = "274"; | ||||
| 	entry.mnc = "08"; | ||||
| 	entry.option = "^0([1-9])"; | ||||
| 	entry.text = "0049"; | ||||
| 	llist_add_tail(&entry.list, &entries.entry); | ||||
| 	bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); | ||||
|  | ||||
| 	/* attempt to undo the previous one */ | ||||
| 	INIT_LLIST_HEAD(&entries_post.entry); | ||||
| 	entry_post.mcc = "274"; | ||||
| 	entry_post.mnc = "08"; | ||||
| 	entry_post.option = "^\\+49([1-9])"; | ||||
| 	entry_post.text = "prefix_lookup"; | ||||
| 	llist_add_tail(&entry_post.list, &entries_post.entry); | ||||
| 	bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, &entries_post); | ||||
|  | ||||
|         nat->num_rewr_trie = nat_rewrite_parse(nat, "prefixes.csv"); | ||||
|  | ||||
| 	msgb_reset(msg); | ||||
| 	copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); | ||||
| 	parsed = bsc_nat_parse(msg); | ||||
| 	if (!parsed) { | ||||
| 		printf("FAIL: Could not parse ID resp\n"); | ||||
| 		abort(); | ||||
| 	} | ||||
|  | ||||
| 	out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); | ||||
| 	if (!out) { | ||||
| 		printf("FAIL: A new message should be created.\n"); | ||||
| 		abort(); | ||||
| 	} | ||||
|  | ||||
| 	if (msg == out) { | ||||
| 		printf("FAIL: The message should have changed\n"); | ||||
| 		abort(); | ||||
| 	} | ||||
|  | ||||
| 	verify_msg(out, cc_setup_national, ARRAY_SIZE(cc_setup_national)); | ||||
| 	msgb_free(out); | ||||
|  | ||||
| 	bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); | ||||
| 	talloc_free(nat); | ||||
| } | ||||
|  | ||||
| static void test_sms_smsc_rewrite() | ||||
| @@ -1322,6 +1437,8 @@ int main(int argc, char **argv) | ||||
| 	test_cr_filter(); | ||||
| 	test_dt_filter(); | ||||
| 	test_setup_rewrite(); | ||||
| 	test_setup_rewrite_prefix(); | ||||
| 	test_setup_rewrite_post(); | ||||
| 	test_sms_smsc_rewrite(); | ||||
| 	test_sms_number_rewrite(); | ||||
| 	test_mgcp_allocations(); | ||||
|   | ||||
							
								
								
									
										2
									
								
								openbsc/tests/bsc-nat/prefixes.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								openbsc/tests/bsc-nat/prefixes.csv
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| 0172,0049 | ||||
| +49,0 | ||||
| 
 | 
| @@ -34,6 +34,7 @@ AT_CLEANUP | ||||
| AT_SETUP([bsc-nat]) | ||||
| AT_KEYWORDS([bsc-nat]) | ||||
| AT_CHECK([test "$enable_nat_test" != no || exit 77]) | ||||
| cp $abs_srcdir/bsc-nat/prefixes.csv . | ||||
| cp $abs_srcdir/bsc-nat/barr.cfg . | ||||
| cp $abs_srcdir/bsc-nat/barr_dup.cfg . | ||||
| cat $abs_srcdir/bsc-nat/bsc_nat_test.ok > expout | ||||
| @@ -48,6 +49,14 @@ cat $abs_srcdir/smpp/smpp_test.err > experr | ||||
| AT_CHECK([$abs_top_builddir/tests/smpp/smpp_test], [], [expout], [experr]) | ||||
| AT_CLEANUP | ||||
|  | ||||
| AT_SETUP([bsc-nat-trie]) | ||||
| AT_KEYWORDS([bsc-nat-trie]) | ||||
| AT_CHECK([test "$enable_nat_test" != no || exit 77]) | ||||
| 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([si]) | ||||
| AT_KEYWORDS([si]) | ||||
| cat $abs_srcdir/si/si_test.ok > expout | ||||
|   | ||||
| @@ -96,8 +96,41 @@ class TestVTYNAT(TestVTYBase): | ||||
|     def vty_app(self): | ||||
|         return (4244, "src/osmo-bsc_nat/osmo-bsc_nat",  "OsmoBSCNAT", "nat") | ||||
|  | ||||
|     def testMoo(self): | ||||
|         pass | ||||
|     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 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 add_nat_test(suite, workdir): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user